Zend framework 2 : How to set locale globaly? - zend-framework

I have to change the locale dynamically depending which language the user wants.
I can set the locale in the Application/Module.php like this :
public function onBootstrap(MvcEvent $e)
{
$translator = $e->getApplication()->getServiceManager()->get('translator');
$translator->setLocale('hu_HU');
}
But, how can I do this in the controller, if I want to change languages ? I tried this, but after this I can change the locale only for this one request and not global.
$translator = $this->getServiceLocator()->get('translator');
$translator->setLocale('srb_SRB');

Set up the default locale at configuration level! See #61 of module.config.php from ZendSkeletonApplications Application Module
'translator' => array(
'locale' => 'en_US',
)

I had the same issue. In my user login module, I registered for MvcEvent on bootstrap:
use Zend\Mvc\MvcEvent;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\Session\SessionManager;
use Zend\Session\Container as SessionContainer;
use \Zend\I18n\Translator\TranslatorInterface;
...
public function onBootstrap(MvcEvent $event)
{
// Get event manager.
$eventManager = $event->getApplication()->getEventManager();
$sharedEventManager = $eventManager->getSharedManager();
// Register the event listener method.
$sharedEventManager->attach(AbstractActionController::class,
MvcEvent::EVENT_DISPATCH, [$this, 'onDispatch'], 100);
}
Then when that event comes, I set the locale based on info from the URL:
public function onDispatch(MvcEvent $event)
{
$servicemanager = $event->getApplication()->getServiceManager();
$lang = $event->getRouteMatch()->getParam('lang','jp-JP');
$translator = $servicemanager->get(TranslatorInterface::class);
if( $translator != null )
{
$translator->setLocale($lang);
}
...
In the end, this does not really make the locale global - instead, it just sets it for every request. The net effect is the same, from the code point of view - i.e., I don't have to set the locale on every controller.
Hope that helps.

This work for me:
public function onBootstrap(MvcEvent $e)
{
$localeFromHttp = \Locale::acceptFromHttp($_SERVER['HTTP_ACCEPT_LANGUAGE']);
if (false === stripos($localeFromHttp, '-')) {
$locale = $localeFromHttp . '_' . strtoupper($localeFromHttp);
$e->getApplication()
->getServiceManager()
->get('MvcTranslator')
->setLocale($locale);
}
else {
$e->getApplication()->getServiceManager()->get('MvcTranslator')->setFallbackLocale('en_US');
}
}
And my modal.config.php:
'service_manager' => array(
'abstract_factories' => array(
'Zend\Cache\Service\StorageCacheAbstractServiceFactory',
'Zend\Log\LoggerAbstractServiceFactory',
),
'aliases' => array(
'translator' => 'MvcTranslator',
),
),
'service_manager' => array(
'factories' => array(
'translator' => 'Zend\I18n\Translator\TranslatorServiceFactory',
),
),
'translator' => array(
'translation_file_patterns' => array(
array(
'type' => 'gettext',
'base_dir' => __DIR__ . '/../language',
'pattern' => '%s.mo',
'text_domain' => __NAMESPACE__,
),
),
),

In the modal.config file, I do not think that the following is required as you have used the alias 'MvcTranslator' for translator.
'service_manager' => array(
'factories' => array(
'translator' => 'Zend\I18n\Translator\TranslatorServiceFactory',
),

In ZF2 locale is set always per request. You can do that on bootstrap:
$translator = $event->getApplication()->getServiceManager()->get('translator');
$translator->setLocale($locale);
$translator->addTranslationFile(
'phpArray', DATA_PATH . DIRECTORY_SEPARATOR . 'languages' . DIRECTORY_SEPARATOR . $locale . '.php', 'default', $locale
);
and later in controller, if You want to change:
$translator = $this->getServicelocator()->get('translator');
$translator->setLocale($locale);
if You change selected locale, You have to add translation file path again to make it works

Related

Zend Framework 2 - Gobal Variable that are accessible to controller/model that are initialize in local.php or global.php

Hello everyone please someone help me how to create a global variable in zend framework 2 to be use in table prefix that are accessible in controller and model.
Thanks and regards to all.
In your config/database.local.php you can define which you want globally
<?
return array(
'service_manager' => array(
'factories' => array(
//'Zend\Db\Adapter\Adapter' => 'Zend\Db\Adapter\AdapterServiceFactory',
'Zend\Db\Adapter\Adapter' => function ($serviceManager) {
$adapterFactory = new Zend\Db\Adapter\AdapterServiceFactory();
$adapter = $adapterFactory->createService($serviceManager);
\Zend\Db\TableGateway\Feature\GlobalAdapterFeature::setStaticAdapter($adapter);
return $adapter;
}
),
),
'db' => array(
'driver' => 'pdo',
'dsn' => 'mysql:dbname=testdb;host=localhost',
'username' => 'root',
'password' => '',
),
'msg' => array(
'add' => 'Data Inserted Successfully',
'edit' => 'Data Updated Successfully',
'delete' => 'Data Deleted Successfully',
),
);
?>
Controller File:
DemoController.php
<?php
namespace Demo\Controller;
use Zend\Mvc\Controller\AbstractActionController;
class DemoController extends AbstractActionController
{
public function indexAction($cms_page_name='whyus')
{
/*Call config file to fetch current cms page id-- fetch config file from database.local.php*/
$config = $this->getServiceLocator()->get('Config');
$all_msg = $config['msg'];
}
}
?>

Zend Framework 2 invalidate translator cache

I have this code:
'translator' => array(
...
'cache' => array(
'adapter' => array(
'name' => 'Filesystem',
'options' => array(
'cache_dir' => __DIR__ . '/../../../data/cache',
'ttl' => '3600'
)
),
'plugins' => array(
array(
'name' => 'serializer',
'options' => array()
),
'exception_handler' => array(
'throw_exceptions' => true
)
)
)
The question is, how do I invalidate it not by TTL?
For example, I KNOW when the translation was changed so I want to invalidate in on demand but I have not found a way to do it.
The translator component does not utilize the TaggableInterface so you have to know the cacheId which the translator generates to clear the item from you storage adapter. You can use the following code to simply generate the same id and remove the item. Call this from your service or some event listener.
$translator = $sm->get('McvTranslator');
$textDomain = 'default';
$locale = 'en';
$cacheId = 'Zend_I18n_Translator_Messages_' . md5($textDomain . $locale);
$translator->getCache()->removeItem($cacheId);
I think you could set Ttl = 0 (always), and when the cache (file) is not valid anymore -- delete it.
Another way to do it:
Find a point in your code where you call addTranslation.
For example:
$translate = Zend_Registry::get('Zend_Translate');
$translate->addTranslation(array(
'content' => "$dir/$locale.mo",
'locale' => $locale
));
Change the addTranslation function to add reload => true , like this:
$translate->addTranslation(array(
'content' => "$dir/$locale.mo",
'locale' => $locale,
'reload' => true
));
Refresh your page.
Voila.
Remeber to remove reload after that, otherwise you will have no cache.

Including settings in to module class

Im my module.config.php file got following excerpt:
return array(
'service_manager' => array(
'aliases' => array(
'Util\Dao\Factory' => 'modelFactory',
),
'factories' => array(
'modelFactory' => function($sm) {
$dbAdapter = $sm->get('Doctrine\ORM\EntityManager');
return new \Util\Dao\Factory($dbAdapter);
},
)
),
'doctrine' => array(
'driver' => array(
'application_entities' => array(
'class' => 'Doctrine\ORM\Mapping\Driver\AnnotationDriver',
'cache' => 'array',
'paths' => array(
__DIR__ . '/../src/Application/Model'
),
),
'orm_default' => array(
'drivers' => array(
'Application\Model' => 'application_entities'
)
),
),
),
How do i put the block "doctrine" in module class?
Well, this is actually fairly simple. Probably your Module class has the method getConfig(). That method usually loads moduleName/config/module.config.php.
So in whatever function you are, simply call the getConfig()-method. This is pure and basic php ;)
//Module class
public function doSomethingAwesome() {
$moduleConfig = $this->getConfig();
$doctrineConfig = isset($moduleConfig['doctrine'])
? $moduleConfig['doctrine']
: array('doctrine-config-not-initialized');
}
However you need to notice that this only includes your Modules config. If you need to gain access to the merged configuration, you'll need to do that in the onBootstrap()-method. Which would be done like this:
//Module class
public function onBootstrap(MvcEvent $mvcEvent)
{
$application = $mvcEvent->getApplication();
$serviceLocator = $application->getServiceLocator();
$mergedConfig = $serviceLocator->get('config');
$doctrineConfig = isset($mergedConfig['doctrine'])
? $mergedConfig['doctrine']
: array('doctrine-config-not-initialized');
}
This works similar if you're attaching to some events...

Can't get Auth login to work with CakePHP 2.0

I'm trying to get a simple login form to work using CakePHP 2.0... just Auth, no ACLs for now.
I'm able to see the form and enter the email and password as they are in the database, but I just get returned to the form and the flash error message is displayed. Here is my code:
AppController:
class AppController extends Controller
{
function beforeFilter()
{
$this->Auth->userModel = 'Users';
$this->Auth->fields = array('username' => 'email', 'password' => 'password'); //have to put both, even if we're just changing one
$this->Auth->loginAction = array('controller' => 'users', 'action' => 'login');
$this->Auth->loginRedirect = array('controller' => 'hotels', 'action' => 'dashboard');
$this->Auth->logoutRedirect = array('controller' => 'users', 'action' => 'login');
}
}
login.ctp:
<?php
echo $this->Form->create('User', array('action' => 'login'));
echo $this->Form->input('email');
echo $this->Form->input('password');
echo $this->Form->end('Login');
?>
UsersController:
class UsersController extends AppController
{
var $name = 'Users';
var $helpers = array('Html','Form');
var $components = array('Auth','Session');
function beforeFilter()
{
$this->Auth->allow("logout");
parent::beforeFilter();
}
function index() { } //Redirects to login()
function login()
{
if ($this->Auth->login())
{
$this->redirect($this->Auth->redirect());
} else
{
$this->Session->setFlash(__('Invalid username or password, try again'));
}
}
function logout()
{
$this->redirect($this->Auth->logout());
}
}
?>
I appreciate any help with this. Thanks!
The "Invalid username or password, try again" error is displayed after you hit login?
There are a few things you should check:
• Is the output of $this->Auth->login() identical to the information in your database? Put debug($this->Auth->login()) to see the output in your login method after the form is submitted.
• Are the passwords correctly hashed in the database?
• Try making the AuthComponent available to all your controllers not just the UsersController.
• Not sure if this makes a difference, but call parent::beforeFilter(); before anything else in your controller's beforeFilter method.
EDIT:
Is see that you're trying to validate based on email and password. As a default AuthComponent expects a username and password. You have to explicitly state that you want the email and password to be validated by $this->Auth->login(). This comes from the 2.0 documentation:
public $components = array(
'Auth'=> array(
'authenticate' => array(
'Form' => array(
'fields' => array('username' => 'email')
)
)
)
);
The fact that you're not seeing any SQL output is to be expected, I believe.
Also you must check if your field "password" in database is set to VARCHAR 50.
It happens to me that I was truncating the hashed password in DB and Auth never happened.
if you are not using defalut "username", "password" to auth, you cant get login
e.g., you use "email"
you should edit component declaration in your controller containing your login function:
$component = array('Auth' => array(
'authenticate' => array(
'Form' => array(
'fields' => array('username' => 'email', 'password' => 'mot_de_passe')
)
)
));
Becareful with cakephp's conventions. You should change this "$this->Auth->userModel = 'Users';" to "$this->Auth->userModel = 'User';" because User without plural is the Model's convention in cake. That worked for me and also becareful with the capital letters. it almost drived me crazy. Good luck.
public $components = array(
'Session',
'Auth' => array(
'loginRedirect' => array(
'controller' => 'Events',
'action' => 'index'
),
'logoutRedirect' => array(
'controller' => 'Users',
'action' => 'login',
'home'
),
'authenticate' => array(
'Form' => array(
'fields' => array('username' => 'username','password' => 'password')
)
)
)
);
Editing the component declaration in AppController did the trick for me. If you have the fields named other than "username" and "password" you should always specify them. In your case it would be
public $components = array(
'Auth' => array(
'authenticate' => array(
'Form' => array(
'passwordHasher' => 'Blowfish',
'fields' => array('username' => 'email','password' => 'password')
)
)
)
);
There is a bug in the cakephp tutorial.
$this->Auth->login() should be changed to
$this->Auth->login($this->request->data)

CakePHP not showing my form errors

I'm trying to create a login form for my web application.
Form validation errros are not showing even though I'm using the $validate Array.
user.php
public $validate = array(
'email' => array(
'notEmpty' => array(
'rule' => 'notEmpty',
'message' => 'notEmpty',
'required' => true
),
'isEmail' => array(
'rule' => 'email'
),
'isUnique' => array(
'rule' => 'isUnique'
)
),
'password' => array(
'notEmpty' => array(
'rule' => 'notEmpty'
),
'minLength' => array(
'rule' => array('minLength', 8)
)
)
);
I can't see an error in my user model, so I show you my controller and my view.
users_controller.php
class UsersController extends AppController {
public $name = 'Users';
public $helpers = array(
'Form'
);
public function login() {
if(!empty($this->data)) {
if ($this->Auth->user() != null) {
$this->Session->setFlash('You are now logged in.', 'flash/success');
$this->redirect('/');
} else {
$this->Session->setFlash('You could not get logged in. Please see errors below.', 'flash/error');
}
}
}
login.ctp
echo $this->Form->create('User', array('action' => 'login'));
echo $this->Form->input('User.email', array(
'label' => __('email address:', true),
'error' => array(
'notEmpty' => __('Email address must not be blank.', true),
'isEmail' => __('Email address must be valid.', true),
)
));
echo $this->Form->input('User.password', array('label' => __('password:', true)));
echo $this->Form->end('Log in');
I hope you can help me. I can't find my mistake since hours. Is there maybe a component or an helper which I need to include?
put echo $this->Session->flash('auth'); before form->create. You don't have to validate login form, Auth will take care of that for you. Read the cookbook: http://book.cakephp.org/view/1250/Authentication
Since you are using Auth, the minLength validation for password is useless.
Validation doesn't occur automatically unless you're saving into the database. Change the first line of the login method in the controller to
if( !empty( $this->data ) && $this->User->validates() ) {
...