I currently have a widget inside a module and I would like to create a messages directory so that I can translate module strings from inside that folder.
The issue I have is that I can't get the widget to get the translations from inside the module folder.
This is my structure
frontend/modules/comments
frontend/modules/comments/Module.php
frontend/modules/comments/widgets/CommentsWidget.php
frontend/modules/comments/widgets/views/_form.php
-Module.php
namespace frontend\modules\comments;
use Yii;
class Module extends \yii\base\Module {
public $controllerNamespace = 'frontend\modules\comments\controllers';
public function init() {
parent::init();
$this->registerTranslations();
}
public function registerTranslations() {
Yii::$app->i18n->translations['modules/comments/*'] = [
'class' => 'yii\i18n\PhpMessageSource',
'sourceLanguage' => 'en',
'basePath' => '#frontend/modules/comments/messages',
'fileMap' => [
'modules/comments/comments' => 'comments.php',
]
];
}
public static function t($category, $message, $params = [], $language = null) {
return Yii::t('modules/comments/' . $category, $message, $params, $language);
}
}
_form.php
I use the following code to call the translation.
Module::t('comments', 'COMMENT_REPLY')
But it doesn't seem to work. Any ideas?
Thank you in advance!
Have same problem.
It's because you register translations is in init() method (when instance of module was created). You can change registerTranslations() method to static:
public function init()
{
// ...
self::registerTranslations();
}
public static function registerTranslations()
{
// ...
}
And call it Content::registerTranslations(); in your widget before use Module::t().
Related
I've created a module that overrides an AdminProductController.php and make a new bulk_action.
<?php
class AdminProductsController extends AdminProductsControllerCore
{
public function __construct()
{
parent::__construct();
$this->bulk_actions['setprice'] = array(
'text' => $this->l('Set a price for selected'),
'icon' => 'icon-price',
);
}
}
Now I need to translate the action text and distribute that translation with module.
The problem is that I don't see the original text inside modules translation instead it is visible in back-office translations.
So, is there any way to add this string to module translations not to back-office translations?
You can do it by creating an instance of a module you want the translation to be in.
class AdminProductsController extends AdminProductsControllerCore
{
public function __construct()
{
parent::__construct();
$module = Module::getInstanceByName('modulename');
$this->bulk_actions['setprice'] = array(
'text' => $module->l('Set a price for selected'),
'icon' => 'icon-price',
);
}
}
The main problem description I've found here: How to get translation from other module in PrestaShop?
This is because translations controller scans for $this->l((.*)) inside module folder using regex and adds the translatable strings to a file
So we should in module do something like this:
class MyModule extends Module
{
public static $l = null;
public function __construct()
{
parent::__construct();
$this::$l = $this->l('Set a price for selected');
}
}
Than in controller we can do what was suggested by #TheDrot:
class AdminProductsController extends AdminProductsControllerCore
{
public function __construct()
{
parent::__construct();
$module = Module::getInstanceByName('modulename');
$this->bulk_actions['setprice'] = array(
'text' => $module->l('Set a price for selected'),
'icon' => 'icon-price',
);
}
}
Try using the following code in place of $this->l('Set a price for selected')
Translate::getModuleTranslation(YOUR_MODULE_NAME, 'Set a price for selected', FILE_NAME);
I am trying to extend an existing plugin component and I
need to add a function but use plugins methods.
Here what I have:
<?php namespace Bbrand\Shop\Components;
use Cms\Classes\ComponentBase;
use Jiri\JKShop\Components\Basket;
class Shopextend extends ComponentBase
{
public function componentDetails()
{
return [
'name' => 'shopextend Component',
'description' => 'No description provided yet...'
];
}
public function defineProperties()
{
return [];
}
public function onBasket(){
$data = [];
$data["basket"] = Basket::getSessionBasket();
$data["jkshopSetting"] = \Jiri\JKShop\Models\Settings::instance();
return [
$this->property("idElementWrapperBasketComponent") => $this->renderPartial('#basket-0', $data)
];
}
}
But I'm getting an error
"Non-static method Jiri\JKShop\Components\Basket::getSessionBasket()
should not be called statically" on line 30 of
/Applications/MAMP/htdocs/fidgycube.co/plugins/bbrand/shop/components/Shopextend.php
Any help!?
thanks
You need to add component first.
<?php namespace Bbrand\Shop\Components;
class Shopextend extends ComponentBase
{
public function init()
{
// Add component
$this->addComponent('\Jiri\JKShop\Components\Basket', 'basket', []);
}
}
I've made a global variable in bootstrap of Module.php
public function setCashServiceToView($event) {
$app = $event->getParam('application');
$cashService = $app->getServiceManager()->get('Calculator/Service/CashServiceInterface');
$viewModel = $event->getViewModel();
$viewModel->setVariables(array(
'cashService' => $cashService,
));
}
public function onBootstrap($e) {
$app = $e->getParam('application');
$app->getEventManager()->attach(\Zend\Mvc\MvcEvent::EVENT_RENDER, array($this, 'setCashServiceToView'), 100);
}
I can use it inside of my layout.phtml as
$this->cashService;
But I need this variable to use in my partial script of navigation menu, which I call in layout.phtml:
echo $this->navigation('navigation')
->menu()->setPartial('partial/menu')
->render();
?>
How can I use it inside of my partial/menu.phtml? And may be there is a better way, than to declare it in onBootstrap function?
Thank you for your answers. I decided to make an extended class of \Zend\View\Helper\Navigation\Menu to provide there a property of cashService. However I receive an error:'Zend\View\Helper\Navigation\PluginManager::get was unable to fetch or create an instance for Calculator\Service\CashServiceInterface'.
I need this service to display navigation menu. Seems weird, but that's true. I display some diagram in it, using the data, which I get from the service. So why do I have the error?
I added to module.config.php
'navigation_helpers' => array(
'factories' => array(
'mainMenu' => 'Calculator\View\Helper\Factory\MainMenuFactory'
),
MainMenuFactory:
namespace Calculator\View\Helper\Factory;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use Calculator\View\Helper\Model\MainMenu;
Class MainMenuFactory implements FactoryInterface {
/**
* Create service
*
* #param ServiceLocatorInterface $serviceLocator
* #return mixed
*/
public function createService(ServiceLocatorInterface $serviceLocator) {
return new MainMenu(
$serviceLocator->get('Calculator\Service\CashServiceInterface')
);
}
P.S: CashServiceInterface is an alias to CashServiceFactory
You could remove the event listener and use a custom view helper to access the service in the view.
namespace Calculator\View\Helper;
use Zend\View\Helper\AbstractHelper;
class CashService extends AbstractHelper
{
protected $cashService;
public function __construct(CashServiceInterface $cashService)
{
$this->cashService = $cashService;
}
public function __invoke()
{
return $this->cashService;
}
}
Create a factory.
namespace Calculator\View\Helper;
class CashServiceFactory
{
public function __invoke($viewPluginManager)
{
$serviceManager = $viewPluginManager->getServiceLocator();
$cashService = $serviceManager->get('Calculator\\Service\\CashServiceInterface');
return new CashService($cashService);
}
}
Register the new helper in moudle.config.php.
'view_helpers' => [
'factories' => [
'CashService' => 'Calculator\View\Helper\CashServiceFactory',
],
],
Then you can use the plugin in all view scripts.
$cashService = $this->cashService();
I wanna use my entities inside my custom plugin. So, I am doing in that order:
1) Declared my plugin in Module\src\Plugin\Plugin.php
namespace Application\Plugin;
use Zend\Mvc\Controller\Plugin\AbstractPlugin;
use Doctrine\ORM\EntityManager;
use User\Entity\UserProfile;
use Zend\ServiceManager\ServiceManager;
class AuthenticationPlugin extends AbstractPlugin {
protected $entityManager;
protected $serviceManager;
public function setServiceManager(ServiceManager $locator) {
$this->serviceManager = $locator;
}
public function getServiceManager() {
return $this->serviceManager;
}
public function getEntityManager() {
$userEntityFactory = new \Application\Factory\UserEntityFactory();
$this->entityManager = $userEntityFactory->createService($this->getServiceManager());
return $this->entityManager;
}
public function someAction($user_email) {
$user = $this->getEntityManager()->getRepository('User\Entity\User')->findBy(array('email'=>$user_email));
}
}
2) Created my factory:
namespace User\Factory;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
class UserEntityFactory implements FactoryInterface {
public function createService(ServiceLocatorInterface $serviceLocator) {
return $serviceLocator->get('doctrine.entitymanager.orm_default');
}
}
3) Defines it in module.config.php:
'service_manager' => array(
'factories' => array(
'UserEntityFactory' => 'Application\Factory\UserEntityFactory',
),
),
'controller_plugins' => array(
'invokables' => array(
'AuthenticationPlugin' => 'Application\Plugin\AuthenticationPlugin',
)
),
4) Sending ServiceLocator to my plugin in Module.php:
public function getServiceConfig() {
return array(
'factories' => array(
'AuthenticationPlugin' => function($sm) {
$locator = $sm->getServiceLocator();
$instance = new \Application\Plugin\AuthenticationPlugin();
$instance->setServiceManager($locator);
return $instance;
},
),
);
}
5) ...and calling it in onBootstrap:
$em->attach('ZfcUser\Service\User', 'register', function($e) {
$user = $e->getParam('user'); // User account object
$authenticationPlugin = new AuthenticationPlugin();
$authenticationPlugin->someAction($user->getEmail());
});
But I received the error that $locator in plugin is null... I'm confused and I am sure that I'm doing something wrong... or all. I would be happy if somebody will share experiences or will show the order of actions. Thanks.
You don't need to inject the entire service manager object into your plugin class.
You only need to inject the User\Entity\User repository object, this appears to be the only dependancy required in your plugin class.
You should pass this into the constructor of your plugin class via your factory :
public function getServiceConfig() {
return array(
'factories' => array(
'AuthenticationPlugin' => function($sm) {
return new \Application\Plugin\AuthenticationPlugin($sm->get('doctrine.entitymanager.orm_default')->getRepository('User\Entity\User'));
},
),
);
}
in your plugin class:
class AuthenticationPlugin extends AbstractPlugin {
private $userRepository;
public function __construct(\User\Entity\User $userRepository){
$this->userRepository=$userRepository;
}
public function someAction($user_email) {
$user = $this->userRepository->findBy(array('email'=>$user_email));
}
}
As you are configuring the plugin via the module.php you don't need to also declare the plugin as an invokable in your config file. So remove the following line from your module.config.php
'AuthenticationPlugin' => 'Application\Plugin\AuthenticationPlugin'
As a side note, there are various pros and cons between declaring your services/plugins in either the module.php or the module.config file. This though wasn't the question so I won't go into detail here.
How to do the following __construct section shown in ZF1 on the fly in ZF2 way?
I have tried $this->headTitle('..'); by ommiting ->view call, but it still fail by throwing:
Zend\ServiceManager\ServiceManager::get was unable to fetch or create an instance for headTitle
public function __construct() { //init is gone
$this->_helper->layout()->setLayout('brand');
$this->HeadTitle($this->title)->setIndent(8);
$this->view->headMeta()->appendName('keywords', $this->keyword)->setIndent(8);
$this->view->headMeta()->appendName('description', $this->description)->setIndent(8);
$this->view->headMeta()->appendName('Language', 'en')->setIndent(8);
$this->view->headMeta()->appendName('dc.title', $this->title)->setIndent(8);
$this->view->headMeta()->appendName('dc.keywords', $this->keyword)->setIndent(8);
$this->view->headMeta()->appendName('dc.description', $this->description)->setIndent(8);
$this->view->headLink()->appendStylesheet('/css/main.css')->setIndent(8);
$this->view->headLink()->appendStylesheet('/jquery/css/custom-theme/jquery-ui-
1.8.20.custom.css')->setIndent(8);
$post = $this->getRequest()->getPost();
$get = $this->getRequest()->getQuery();
}
You could access to 'renderer' object in your action controller:
public function indexAction()
{
$renderer = $this->getServiceLocator()->get('Zend\View\Renderer\PhpRenderer');
$renderer->headTitle('My title');
return new ViewModel();
}
I got the same question and I have developed an ZF2 plugin to use headTitle like in layout.phtml file.
https://github.com/remithomas/rt-headtitle
public function indexAction(){
$this->headTitle("My website")->setSeparator(" - ")->append("easy ?!");
return new ViewModel();
}
Write a function to handle it for all actions in a controller
protected function setHeadTitle($title = ''){
if(!empty($title)){
$renderer = $this->getServiceLocator()->get('Zend\View\Renderer\PhpRenderer');
$renderer->headTitle($title);
}
}
Use the function in your action
public function loginAction()
{
$this->setHeadTitle("Login");
//write some other codes
}
Write a plugin for all module
class HeadTitlePlugin extends AbstractPlugin
{
public function setHeadTitle($title = '')
{
if (! empty($title)) {
$renderer = $this->getController()->getServiceLocator()->
get('Zend\View\Renderer\PhpRenderer');
$renderer->headTitle($title);
}
}
}
Attach the plugin in module config
'controller_plugins' => array(
'invokables' => array(
'HeadTitlePlugin' => 'Modulename\Controller\Plugin\HeadTitlePlugin'
)
),
Call the plugin function in controller action
public function indexAction()
{
$this->HeadTitlePlugin()->setHeadTitle("Signup");
// other codes
}
Thats all