zf2 change language dynamically - php

I have one question, about ZF2 Translator, in the specific case in the costruction the link for change langauge dunamically when user click on flag or menu link.
In My Application/config/module.config.php i have this code:
'service_manager' => array(
'factories' => array(
'translator' => 'Zend\I18n\Translator\TranslatorServiceFactory',
'navigation' => 'Zend\Navigation\Service\DefaultNavigationFactory',
),
),
and my route is:
return array(
'router' => array(
'routes' => array(
'home' => array(
'type' => 'Segment',
'options' => array(
'route' => '/[:lang[/:action]]',
'constraints' => array(
'lang' => '[a-zA-Z]*',
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
),
'defaults' => array(
'controller' => 'Application\Controller\Index',
'action' => 'index',
),
),
),
And in my Application/Module.php i set this code on bootstrap:
public function onBootstrap(MvcEvent $e)
{
$sm = $e->getApplication()->getServiceManager();
$router = $sm->get('router');
$request = $sm->get('request');
$matchedRoute = $router->match($request);
$params = $matchedRoute->getParams();
if(isset($params['lang']) && $params['lang'] !== '') {
$translator = $e->getApplication()->getServiceManager()->get('translator');
//or
//$translator = $e->getApplication()->getServiceManager()->get('MvcTranslator');
if($params['lang'] == 'en') {
$translator->setLocale('en_US');
}
}
$eventManager = $e->getApplication()->getEventManager();
$moduleRouteListener = new ModuleRouteListener();
$moduleRouteListener->attach($eventManager);
}
now my route http://www.xxxx.com/it/index or http://www.xxxx.com/it/company but i can't create a link in my view for change language in my application...
How do i proceed ?
Thanks

You can create a link to the same page you are in by changing only the lang parameter like the following:
$this->url(null, array('lang' => $anotherLang), array(), true)

Just do this in your Views :
English
This will give the same URL as the current one but in different language (here it's English).

Related

zf2 phpunit scheme routes

We're using ZF2 for an web-application and want to test it with phpunit (v4.8.9). Within this application we've got a scheme-route, to be able to switch between http/https-context (Doesnt matter why...). The route looks like this:
'http' => array(
'type' => 'Scheme',
'options' => array(
'scheme' => 'http',
'defaults' => array(
'http' => true
)
),
'child_routes' => array(
'search' => array(
'type' => 'segment',
'options' => array(
'route' => '/search[/:keyword[/:page]]',
'constraints' => array(
'page' => '[1-9]+[0-9]*'
),
'defaults' => array(
'controller' => SearchController::class,
'action' => 'search',
),
),
),
),
),
'https' => array(
'type' => 'Scheme',
'options' => array(
'scheme' => 'https',
'defaults' => array(
'https' => true
)
),
'child_routes' => array(
'search' => array(
'type' => 'segment',
'options' => array(
'route' => '/search[/:keyword[/:page]]',
'constraints' => array(
'page' => '[1-9]+[0-9]*'
),
'defaults' => array(
'controller' => SearchController::class,
'action' => 'search',
),
),
),
),
),
The class of the test looks like this:
class SearchControllerTest extends SynHttpControllerTestCase
{
public function setUp()
{
$this->setApplicationConfig($this->getCurrentBootstrap()->getApplicationConfig());
parent::setUp();
$this->getApplicationServiceLocator()->setAllowOverride(true);
}
public function testSearchActionCanBeAccessed()
{
$this->dispatch('/search');
$this->assertResponseStatusCode(200);
$this->assertControllerName(SearchController::class);
$this->assertControllerClass('SearchController');
$this->assertActionName('search');
$this->assertMatchedRouteName('search');
}
}
FYI:
The "SynHttpControllerTestCase" is an extension from the original AbstractHttpControllerTestCase which comes with Zend-Test. It's modified to get the right bootstrap-file in our tests.
If we're running the tests, this error appears:
Fatal error: Call to a member function getParam() on null in C:\xampp\htdocs\git\xxx\vendor\zendframework\zend-test\src\PHPUnit\Controller\AbstractControllerTestCase.php on line 563
We looked into the AbstractControllerTestCase and this line is throwing the error:
$routeMatch = $this->getApplication()->getMvcEvent()->getRouteMatch();
Because the $routeMatch-Object is empty.
We've some other controllers and tests within our application, they're all fine and not affected from this problem, cause the routes to these controllers arent scheme-routes.
Do you have any ideas how to solve this? In advance: we're not able to use static https-routes in this case.
There is a lot of official documentation on how to write a proper controller test. In your setUp method you need to attach a Router instance to a RouteMatch instance which you attach to a MvcEvent in the controller.
protected function setUp()
{
$serviceManager = Bootstrap::getServiceManager();
$this->controller = new IndexController();
$this->request = new Request();
$this->routeMatch = new RouteMatch(array('controller' => 'index'));
$this->event = new MvcEvent();
$config = $serviceManager->get('Config');
$routerConfig = isset($config['router']) ? $config['router'] : array();
$router = HttpRouter::factory($routerConfig);
$this->event->setRouter($router);
$this->event->setRouteMatch($this->routeMatch);
$this->controller->setEvent($this->event);
$this->controller->setServiceLocator($serviceManager);
}
Then you can call dispatch.
UPDATE
Can you not set your route match object like this:
$routeParams = array('controller' => 'search', 'action' => 'search');
$routeMatch = new RouteMatch($routeParams);
$routerConfig = isset($config['router']) ? $config['router'] : array();
$router = HttpRouter::factory($routerConfig);
$event = new MvcEvent();
$event->setRouter($router);
$event->setRouteMatch($routeMatch);
$this->getApplication()->setMvcEvent($event);

Pass custom variables in ZF2 routing config?

I'm thinking about the best way of implementing ACL. So - I need to protect certain routes. Some routes would be accessible only to users, some to guests and some to admins.
It seems like the best way of doing it would be by adding a $role variable in the routing config. So then I'd attach to post-route event, fetch the routeMatch and I would see if this user can enter this route.
How can I do that? Can I simply inject extra varibles like this:
'router' => array(
'routes' => array(
'route1' => array(
'type' => 'Zend\Mvc\Router\Http\Regex',
'options' => array(
'regex' => '/some/route/1',
'defaults' => array(
'controller' => 'Subscriber\Controller\View',
'action' => 'route1',
'role' => 'user', //extra
),
'spec' => '/some/route/1',
),
),
'route2' => array(
'type' => 'Zend\Mvc\Router\Http\Regex',
'options' => array(
'regex' => '/some/route/2',
'defaults' => array(
'controller' => 'Subscriber\Controller\View',
'action' => 'route2',
'role' => 'guest', //extra
),
'spec' => '/some/route/2',
),
),
//other routes....
),
),
Yes you can just add the router key like you have
'defaults' => array(
'controller' => 'Subscriber\Controller\View',
'action' => 'route1',
'role' => 'user', //extra
),
And then you can checkit like this
public function onBootstrap(MvcEvent $e) {
$application = $e->getApplication();
$eventManager = $application->getEventManager();
$eventManager->attach(MvcEvent::EVENT_ROUTE, function(MvcEvent $e) {
$e->getRouteMatch()->getParam('role');
});
}
There are however modules made for this
For example bjyoungblood/BjyAuthorize which works with ZfcUser
You should take a look at : ZfcRbac. It's well documented.

MultiLingual Site in Zend Framework 2 - set value of setLocale() from URL param

Below is what I have done so far -
In Application Module - module.config.php -
'service_manager' => array(
[....],
'aliases' => array(
'translator' => 'MvcTranslator',
),
),
'translator' => array(
'locale' => 'en_US',
'translation_file_patterns' => array(
array(
'type' => 'gettext',
'base_dir' => __DIR__ . '/../language',
'pattern' => '%s.mo',
),
),
),
In Album Module - module.config.php -
'router' => array(
'routes' => array(
'album' => array(
'type' => 'segment',
'options' => array(
'route' => '[/:lang]/album[/:action][/:id]',
'constraints' => array(
'lang' => '[a-zA-Z]*',
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
'id' => '[0-9]+',
),
'defaults' => array(
'controller' => 'Album\Controller\Album',
'action' => 'index',
),
),
),
),
),
In Album Module - Module.php -
public function onBootstrap(MvcEvent $e) {
$sm = $e->getApplication()->getServiceManager();
$router = $sm->get('router');
$request = $sm->get('request');
$matchedRoute = $router->match($request);
$params = $matchedRoute->getParams();
if(isset($params['lang']) && $params['lang'] !== '') {
$translator = $e->getApplication()->getServiceManager()->get('translator');
//or
//$translator = $e->getApplication()->getServiceManager()->get('MvcTranslator');
if($params['lang'] == 'en')
$translator->setLocale('en_US');
elseif($params['lang'] == 'fr')
$translator->setLocale('fr_FR');
else
$translator->setLocale('en_US');
}
}
In view -
echo $this->translate('Home');
Note: URL - http://zf2-tutorial.localhost/fr/album, works just fine. The translation is successful.
Query -
$translator->setLocale('en'); seems to be working with ZF1 but not with ZF2.
I need to know whether there is any way to directly set the URL param value like $translator->setLocale($params['lang']); rather then long if-else or switch statements.
Some sites might be in 20 or more languages.
Thanks in advance.
Simple answer: use SlmLocale. I wrote the module to implement locale detection DRY and for different use cases.
Don't try to fit the localization into your routes. This allows you to have translatable routes as you detect the locale before routing. Also, it helps you enormously to change locale with different URIs.
A mistake you made in your process is that you grab the route match from the event during bootstrap. However, bootstrap occurs before routing, so you can't get the route match parameters at that stage.
TL;DR: checkout SlmLocale, it should help you with all your problems.

ZF2 dynamic routing

I have problem with the routing in ZF2. I want to make dynamic routing for the software, that I'm making.
For example:
This is the URL: http://localhost:8080/application/index.json/
And this is my module.config (router part):
'router' => array(
'routes' => array(
'home' => array(
'type' => 'Zend\Mvc\Router\Http\Segment',
'options' => array(
'route' => '/',
'defaults' => array(
'controller' => 'Application\Controller\Index',
),
),
),
'restful' => array(
'type' => 'Zend\Mvc\Router\Http\Segment',
'options' => array(
'route' => '/:module/[:controller[/:action][.:formatter][/:id]]',
'constraints' => array(
'module' => '[a-zA-Z][a-zA-Z0-9_-]*',
'controller' => '[a-zA-Z][a-zA-Z0-9_-]*',
'formatter' => '[a-zA-Z][a-zA-Z0-9_-]*',
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
'id' => '[a-zA-Z0-9_-]*'
),
),
),
),
),
Everything is working fine, but when I create new controller, have to add it to controllers['invokables'] setting in module.config.
'controllers' => array(
'invokables' => array(
'index' => 'Application\Controller\IndexController',
'cloud' => 'Application\Controller\CloudController',
),
),
So the question is, how to automate the controllers['invokables'] to process requests dynamically, without describing every controller in it.
Fast and dirty, but you get the idea.
namespace Application;
use Zend\Mvc\ModuleRouteListener;
use Zend\Mvc\MvcEvent;
class Module
{
public function onBootstrap(MvcEvent $e)
{
$eventManager = $e->getApplication()->getEventManager();
$eventManager->attach (MvcEvent::EVENT_ROUTE, function (MvcEvent $e) {
$controller_loader = $e->getApplication ()->getServiceManager ()->get ('ControllerLoader');
$controller = $e->getRouteMatch ()->getParam ('controller');
$controller_class = '\Application\Controller\\'.ucfirst ($controller).'Controller';
// Add service locator to the controller
$controller_object = new $controller_class;
$controller_object->setServiceLocator ($e->getApplication ()->getServiceManager ());
// ------------------------------------
$controller_loader->setService ($controller, $controller_object);
});
}
public function getConfig()
{
return include __DIR__ . '/config/module.config.php';
}
public function getAutoloaderConfig()
{
return array(
'Zend\Loader\StandardAutoloader' => array(
'namespaces' => array(
__NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__,
),
),
);
}
}

First optional routing segment acts as mandatory one for child routes

I have the following routing definition:
'admin_default' => array(
'type' => 'segment',
'options' => array(
'route' => '[/:lang]/administrator[/:module][/:action]',
'constraints' => array(
'lang' => '[a-zA-Z]{2}',
'module' => '[a-zA-Z0-9_-]*',
'action' => '[a-zA-Z0-9_-]*',
),
'defaults' => array(
'module' => 'Application',
'controller' => 'Admin',
'action' => 'index',
'lang' => 'ru'
),
),
'may_terminate' => true,
'child_routes' => array(
'wildcard' => array(
'type' => 'wildcard',
'may_terminate' => true,
'options' => array(
'key_value_delimiter' => '/',
'param_delimiter' => '/'
),
),
),
),
So, I can't get rid of segment [/:lang] in URL string
For example:
URL view helper $this->url('admin_default', array('module' => 'albums')) returns the following URL string:
/administrator/albums
while $this->url('admin_default/wildcard', array('module' => 'albums', 'action' => 'edit', 'id' => album_id_here)) returns:
/ru/administrator/albums/edit/id/album_id_here
How can I remove [/:lang] segment from URL string in second case?
so whats the matter with that "ru" ?
you have to extend the zend view helper URL to inject your current locale to the URL
look what i made for my current project :
<?php
namespace PatrickCore\View\Helper;
use Doctrine\ORM\EntityManager;
use Zend\View\Helper\Url;
class I18nUrl extends Url {
/**
* #var String
*/
protected $lang;
protected $router;
public function __construct($locale,$router) {
$arraylanguagemapping = array(
'en_US' => 'en',
'fa_IR' => 'fa'
);
$this->lang = $arraylanguagemapping[$locale];
$this->router = $router;
}
public function __invoke($name = null, array $params = array(), $options = array(), $reuseMatchedParams = false) {
$this->setRouter($this->router);
if (!array_key_exists('lang', $params)) {
$params['lang'] = $this->lang;
}
return parent::__invoke($name,$params,$options,$reuseMatchedParams);
}
}
?>

Categories