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
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?
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'][] = ...
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');
}
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.
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.