How to add Fenom Template in Yii2? - templates

I'm trying to add Fenom Tempate to Yii2 application, but I'm getting a lot of different kinds errors.
I've tried to create a component ViewRenderer and to write code like here, but with my own namespace:
namespace app\components\fenom;
use Yii;
use yii\base\View;
use yii\base\ViewRenderer as BaseViewRenderer;
class ViewRenderer extends BaseViewRenderer {
/**
* #var string the directory, where stores templates.
*/
public $templatePath = '#app/views';
/**
* #var string the directory, where stores compiled templates in PHP files.
*/
public $compilePath = '#runtime/Fenom/compile';
/**
* #var int|array bit-mask or array of Fenom settings.
* #see https://github.com/bzick/fenom/blob/master/docs/en/configuration.md#template-settings
*/
public $options = 0;
/**
* #var \Fenom object that renders templates.
*/
public $fenom;
public function init() {
$this->fenom = \yii\fenom\Fenom::factory($this->templatePath, $this->compilePath, $this->options);
}
public function render($view, $file, $params) {
$params['this'] = $view;
return $this->fenom->fetch($file, $params);
}
}
Added this component to config
'components' => [
'view' => [
'class' => 'yii\web\View',
'renderers' => [
'tpl' => [
'class' => 'app\components\fenom\ViewRenderer',
'options' => [
'auto_reload' => true,
],
],
// ...
],
],
But I'm getting errors. Bad namespace or unwritable directory or another and another errors.
So, my question is: How to add Fenom to Yii2? What and Where should I write (in config, components, or other folders)? What way is the fastest and the most efficient?
Please tell me how to do it properly?

Well, I did it. I'm not sure if this is correct, but...
I made the fenom folder inside the components folder. I put files from the src folder of fenom repo into the /components/fenom.
Also in this folder I created a ViewRenderer.php file. It contains code:
<?php
namespace app\components\fenom;
use Yii;
use yii\base\ViewRenderer as BaseViewRenderer;
class ViewRenderer extends BaseViewRenderer {
/**
* #var string the directory, where stores templates.
*/
public $templatePath = '#app/views';
/**
* #var string the directory, where stores compiled templates in PHP files.
*/
public $compilePath = '#runtime/Fenom/compile';
/**
* #var int|array bit-mask or array of Fenom settings.
* #see https://github.com/bzick/fenom/blob/master/docs/en/configuration.md#template-settings
*/
public $options = ['auto_reload' => true];
/**
* #var \Fenom object that renders templates.
*/
public $fenom;
public function init() {
// put main Fenom class into the yii classmap
Yii::$classMap['Fenom'] = __DIR__.'/Fenom.php';
// call Fenom class autoloader (https://github.com/fenom-template/fenom/blob/master/docs/en/start.md#custom-loader)
\Fenom::registerAutoload(__DIR__."./");
// Yii::getAlias - because it's not understand Yii aliases???
$this->fenom = \Fenom::factory(Yii::getAlias($this->templatePath), Yii::getAlias($this->compilePath), $this->options);
}
public function render($view, $file, $params) {
$params['this'] = $view;
$dirPath = '';
// this is because Fenom do not understand absolute paths???
if (strpos($file, 'views') != false)
$dirPath = explode('views', $file)[1];
if (strpos($file, 'widgets') != false)
$dirPath = explode('widgets', $file)[1];
if (strpos($file, 'modules') != false)
$dirPath = explode('modules', $file)[1];
return $this->fenom->fetch($dirPath, $params);
}
}
I've added ViewRenderer component into the config file:
'components' => [
'view' => [
'class' => 'yii\web\View',
'renderers' => [
'tpl' => [
'class' => 'app\components\fenom\ViewRenderer',
],
],
],
// ...
and created folders inside the runtime folder
- runtime
- Fenom
- compile
- cache
compile - for compiled filed, cache - for cached filed
That's it.
For testing:
/views/site/index.tpl file contains:
{$testtext}
/controllers/SiteController → actionIndex contains:
public function actionIndex() {
return $this->render('index.tpl', ['testtext' => 'It works! Test text']);
}
result:
Something like that...

Installation
Since fenom is an extension on its own, you should use composer to install it. From the docs:
The preferred way to install this extension is through composer.
Either run
php composer.phar require --prefer-dist y2i/yii2-fenom "*"
or add
"y2i/yii2-fenom": "*"
to the require section of your composer.json file.
Usage
The class element in your config file should be a fully qualified class name, not a path to the class file. As such, if installed using composer, you can use the following:
'class' => 'y2i\fenom\ViewRenderer'

Related

How to use Entities Classes from Different Locations in CodeIgniter 4 using Doctrine 2

I am using CodeIgniter 4.x for my project. In my approach, I am using Module system for my project. My Module system is like below structure:
- App
- Modules
- ListMaster
- User
- Models
- Doctrine
- Entities
- User.php
- UserApp.php
- UserGroup
- Models
- Doctrine
- Entities
- Usergroup.php
- Budget
- Models
- Doctrine
- Entities
- Budget.php
In a simple word, I have designed to have my Modules under App/Modules folder. This Folder could consist a Module folder or a folder which will hold Modules. As I created two Modules App/Modules/ListMaster/User and App/Modules/ListMaster/Usergroup. My Entity Class Files will be located under ...Models/Doctrine/Entities folders.
I have downloaded Doctrine using Composer. My Composer is as follow:
{
"require": {
"doctrine/orm": "^2.3.3",
"doctrine/dbal": "^3.2",
"doctrine/annotations": "^1.14",
"symfony/yaml": "^5.4",
"symfony/cache": "^5.4"
},
"autoload": {
"psr-0": {"": "src/"}
},
}
I have created a Library file under App/Libraries which is as follow:
<?php
namespace App\Libraries;
//WE INCLUDING THE AUTOLOAD VENDOR
include_once dirname(__DIR__, 2) . '/vendor/autoload.php';
use Doctrine\Common\ClassLoader;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Tools\Setup;
// TO OBTAIN THE ENTITY MANAGER
class Doctrine
{
public $em;
public function __construct()
{
// Retrieving all paths leading to entities classes
$modulePath = APPPATH."Models/Doctrine/Entities";
$entitiesPath = glob($modulePath, GLOB_ONLYDIR);
$modulePath = APPPATH."Modules/*/Models/Doctrine/Entities";
$entitiesPath = array_merge($entitiesPath, glob($modulePath, GLOB_ONLYDIR));
$modulePath = APPPATH."Modules/*/*/Models/Doctrine/Entities";
$entitiesPath = array_merge($entitiesPath, glob($modulePath, GLOB_ONLYDIR));
$isDevMode = true;
$cache = null;
$useSimpleAnnotationReader = false;
// CONNECTION SETUP
$config = config("Database");
$connection_options = array(
'driver' => strtolower($config->doctrine['DBDriver']),
'user' => $config->doctrine['username'],
'password' => $config->doctrine['password'],
'dbname' => $config->doctrine['database'],
'host' => $config->doctrine['hostname']
);
$proxies_dir = APPPATH . 'Models/Doctrine/Proxies';
$config = Setup::createAnnotationMetadataConfiguration($entitiesPath, $isDevMode, $proxies_dir, $cache, $useSimpleAnnotationReader);
if (ENVIRONMENT === 'development') {
$config->setAutoGenerateProxyClasses(true);
} else {
$config->setAutoGenerateProxyClasses(false);
}
try {
$this->em = EntityManager::create($connection_options, $config);
} catch (\Doctrine\ORM\ORMException $e) {
log_message("Doctrine Exception : ", $e);
}
}
}
As you can see from this, My Entities files will be at Models/Doctrine/Entities, Modules/{any folder}/Models/Doctrine/Entities, Modules/{any folder}/{any folder}/Models/Doctrine/Entities folders.
Now here is my sample Entities Class:
<?php
namespace entities;
use Doctrine\ORM\Mapping as ORM;
/**
* User
*
* #ORM\Table(name="user")
* #ORM\Entity
*/
class User
{
/**
* #var smallint $id
*
* #ORM\Column(name="id", type="smallint", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* #var string $userName
*
* #ORM\Column(name="user_name", type="string", length=150, nullable=true)
*/
protected $userName;
/**
* Constructor
*/
public function __construct()
{
}
/**
* Get id
*
* #return boolean
*/
public function getId()
{
return $this->id;
}
/**
* Set userName
*
* #param string $userName
*/
public function setUserName($userName)
{
$this->userName = $userName;
}
/**
* Get userName
*
* #return string
*/
public function getUserName()
{
return $this->userName;
}
}
Now from my Controller I am executing this Line of code which produces entities\User class not found error. Though this structure can create and update Schema in Database successfully.
$users = $this->em->getRepository('entities\User')->findAll();
Please be noted that I have successfully Generate Proxy, Generate Entities, Crate Schema, Update Schema from this installation.
Thanks in Advance. Please let me know if I missed something to inform you.
So my question is, How to fix the class not found error and got result from Database from any table?

Adding JS to field widget being created in my module - Drupal 8

Cross-posting to drupal.stackexchange.com
I am creating a custom field to eventually be displayed in a custom paragraph. I need to upload a JS file for the widget view, but can't seem to get it to work. Can anyone see what I am doing wrong or need to do differently?
I can add the field to the paragraph, add the paragraph to a document and see the fields, but I see no evidence of the JS being attached (the file is not downloaded in the browser and does not activate).
Any help or suggestions are appreciated.
file: src/Plugin/Field/FieldWidget/get_libguides_listings_widget.php:
<?php
namespace Drupal\get_libguides_listings\Plugin\Field\FieldWidget;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\WidgetBase;
use Drupal\Core\Form\FormStateInterface;
class get_libguides_listings_widget extends WidgetBase {
/**
* {#inheritdoc}
*/
public function formElement(
FieldItemListInterface $items,
$delta, array $element, array &$form,
FormStateInterface $form_state) {
$element['Subject_IDs'] = [
'#type'=>'textfield',
'#title'=>$this->t('Subject IDs to Display'),
'#description'=>$this->t('BLAH'),
'#default_value'
=>isset($items->getValue()[$delta]['Subject_IDs'])
?$items->getValue()[$delta]['Subject_IDs']
:'',
'#states'=>[
'visible' => [
[':input[name$="default_value_input[field_libguides_listing][0][SearchBy]"]'
=>['value'=>'subject']],
'or',
[':input[name$="default_value_input[field_libguides_listing][0][SearchBy]"]'
=>['value'=>'both']],
],
],
];
$element['Subject_IDs']['#attached'][]
= 'get_libguides_listings/get_searchby';
return $element;
}
}
file: get_libguides_listings.libraries.yml:
get_searchby:
js:
js/get_searchby.js: {}
dependencies:
- core/jquery
- core/drupal
- core/drupalSettings
file: js/get_searchby.js
/**
* #file
*/
(function(){
alert('hello there');
(function ($, Drupal)
{
Drupal.behaviors.get_searchby = {
attach: function (context, settings)
{
alert('hello');
}
};
}(jQuery, Drupal));
}());
Turns out I forgot the 'library' key $element['Subject_IDs']['#attached']['library'][] = ...

Overriding Template in Shopware 4 from plugin

public function install() {
$this->subscribeEvent(
'Enlight_Controller_Action_PostDispatchSecure_Frontend',
'onFrontendPostDispatch',
0
);
return array('success' => true, 'invalidateCache' => array('frontend'));
}
public function onFrontendPostDispatch(\Enlight_Event_EventArgs $args)
{
/** #var \Enlight_Controller_Action $controller */
$controller = $args->get('subject');
$view = $controller->View();
$view->addTemplateDir(
__DIR__ . '/Views'
);
}
I had tried to run the plugin and override Template but Shopware does not see changes in a plugin.
I am creating new file in /Views/frontend/checkout/cart_footer.tpl in plugins root.
I am also insert
{extends file='parent:frontend/checkout/cart_footer.tpl'}
line in .tpl file but still no success.
Does any one know where is a problem?
This was very easy
I just add one line
$view->loadTemplate('frontend/plugins/checkout/cart.tpl');
And change code little bit.
I am change event from Enlight_Controller_Action_PostDispatchSecure_Frontend to
Enlight_Controller_Action_PostDispatch_Frontend_Checkout
and add $view->loadTemplate('frontend/plugins/checkout/cart.tpl');
This path is related from "/Views" folder which is declared in addTemplateDir method.
Bellow is whole code, Enjoy :)
public function install() {
$this->subscribeEvent(
'Enlight_Controller_Action_PostDispatch_Frontend_Checkout',
'onFrontendPostDispatch'
);
return array('success' => true, 'invalidateCache' => array('frontend'));
}
public function onFrontendPostDispatch(\Enlight_Event_EventArgs $args)
{
/** #var \Enlight_Controller_Action $controller */
$controller = $args->get('subject');
$view = $controller->View();
$view->addTemplateDir(
__DIR__ . '/Views'
);
$view->loadTemplate('frontend/plugins/checkout/cart.tpl');
}

Yii2 + Codeception: How to use fixtures?

I wrote a simple test for my Yii2 application using Codeception. Instead of using the real MySQL db, I want to use fixtures.
Here is the code:
tests/PersonTest.php:
namespace app\tests\unit\models;
use tests\fixtures;
use app\controllers;
class PersonTest extends \Codeception\Test\Unit
{
protected $tester;
public $appConfig = '#app/config/main.php';
protected function _before(){ }
protected function _after(){ }
public function _fixtures()
{
return [ 'Person' => fixtures\PersonFixture::className() ];
}
public function testUser(){
$person = Person::findOne( [ "id" => 1 ] );
$userId = isset( $person->id ) ? $person->id : false;
$this->assertEquals( 1, $userId );
}
}
tests/fixtures/data/Person.php
return [
'person1' => [
'id' => 1,
'firstname' => 'Foo',
'lastname' => 'Bar',
],
];
tests/fixtures/Person.php
namespace tests\fixtures;
use yii\test\ActiveFixture;
class PersonFixture extends ActiveFixture
{
public $modelClass = 'app\models\Person';
}
When I run the test, I just get the error:
[Error] Class 'tests\fixtures\PersonFixture' not found
I tried 100 different things, but I can not make it work. If this simple example would work for me, I could create real tests.
With Codeception 2.3.8 you can do it like this:
Define your fixture (and have the data file just like you have in your question)
namespace app\tests\fixtures;
class PersonFixture extends \yii\test\ActiveFixture {
public $modelClass = 'app\models\Person';
}
And write your test
namespace app\tests\unit;
class PersonTest extends \Codeception\Test\Unit {
public function _fixtures() {
return [
'persons' => 'app\tests\fixtures\PersonFixture',
];
}
public function testUser() {
$person1 = $this->tester->grabFixture('persons', 'person1');
$this->assertEquals(1, $person1->id);
}
}
That's it.
with codeception 4.0.3 you can run your fixture by following the steps...
create fixtures folder inside test
[fixture folder][1]
[1]: https://i.stack.imgur.com/uK9Cy.png
inside your fixtures/data/book.php
<?php
return [
'book1' => [
'title' => 'lmayert',
'isbn' => 'Ibn-098',
],
'user2' => [
'title' => 'napoleon69',
'isbn' => 'Ibn-042',
],
];
your fixtures/BookFixture be like this:
<?php
namespace app\tests\fixtures;
use yii\test\ActiveFixture;
/**
*
*/
class BookFixture extends ActiveFixture
{
public $modelClass = 'app\models\Book';
}
Now the tests/unit/BookTest be like this
<?php
use app\tests\unit\fixtures\BookFixture;
class BookTest extends \Codeception\Test\Unit
{
/**
* #var \UnitTester
*/
protected $tester;
protected function _before()
{
}
protected function _after()
{
}
public function _fixtures() {
return [
'books' => 'app\tests\fixtures\BookFixture',
];
}
// tests
public function testBook()
{
$book1 = $this->tester->grabFixture('books','book1');
$this->assertEquals(1,$book1->id);
}
}
I hope this will help
You have to change fixture file name from Person.php to PersonFixture.php and it will start working.
You have to be using yii2-codeception extension which would autoload fixtures for you.
After installing it you would have class yii\codeception\DbTestCase available, PersonTest should extend it.
Person fixture should have namespace as follows: app\tests\fixtures.

Hook a twig template to a block in Drupal 8

I created a module which creates a custom block :
<?php
/**
* Provides a 'SLS Block' Block
*
* #Block(
* id = "SLS-Subheader",
* admin_label = #Translation("SLS Subheader"),
* )
*/
namespace Drupal\subheader\Plugin\Block;
use Drupal\Core\Block\BlockBase;
class SubheaderBlock extends BlockBase {
/**
* {#inheritdoc}
*/
public function build() {
return array(
'#title' => "test",
);
}
}
?>
The module name is "subheader"
In my subheader.module i want to hook a specific template:
<?php
/**
* Implements hook_theme().
*/
function subheader_theme() {
return array(
'slssubheader' => array(
'variables' => array('pierre' => NULL),
'template' => 'specifictemplate',
),
);
}
I tried all kind of naming convention for the function name and the array key, but always unsuccesful. It never hook the template to specifictemplate.html.twig
Anyone has an idea??
Thanks a LOOOOTTT
Pierre
I had the same problem, though probably a different cause. Google lead me to your question though. The issue with your code is the missing #theme key in your build method I believe:
public function build() {
return array(
'#title' => "test",
'#theme' => 'slssubheader' // this one
);
}
In my case I had to search for a couple of hours before I found out I accidentally added a custom namespace to my .module file. Drupal doesn't like that and didn't recognize any of my hooks.