silex and twig localization - localization

I'm trying to implement translation in my web application with silex framework. So, i've come up with this
<?php
require_once __DIR__.'/../vendor/autoload.php';
$app = new Silex\Application();
$app['debug'] = true;
$app->register(new Silex\Provider\UrlGeneratorServiceProvider());
$app->register(new Silex\Provider\TwigServiceProvider(), array(
'twig.path' => __DIR__.'/../views',
));
$app->register(new Silex\Provider\TranslationServiceProvider(array(
'locale_fallbacks' => array('hr'),
)));
$app['translator'] = $app->share($app->extend('translator', function($translator) {
$translator->addLoader('xlf', new \Symfony\Component\Translation\Loader\XliffFileLoader());
$translator->addResource('xlf', __DIR__.'/../locales/hr.xlf', 'hr');
$translator->addResource('xlf', __DIR__.'/../locales/en.xlf', 'en');
$translator->addResource('xlf', __DIR__.'/../locales/sl.xlf', 'sl');
return $translator;
}));
$app->get('/', function () use ($app) {
$app['translator']->setLocale('hr');
return $app['twig']->render('home.twig', array('d' => $app['translator']->getLocale()));
});
$app->get('/{_locale}/', function() use ($app) {
$app['translator']->setLocale($app['request']->get('locale'));
return $app['twig']->render('home.twig', array('d' => $app['translator']->getLocale()));
});
$app->run();
Basically, i'd like my homepage (mysite.com) default to hr locale but i can't get it to work. Translations are working properly but when i check for locale in my twig template i get 'en' (I need that check to output some extra text depending on locale). If i enter locale explicitly like mysite.com/hr or mysite.com/en twig registers locale as expected.
Also, I'm wondering if it's good practice having multilingual page with no specified locale on homepage.

Try
$app['locale'] = 'hr';
Silex default locale is set to 'en'.
More info in silex translation documentation

Related

DI fails with namespace

I'm following this tutorial to get a deeper understanding in dependency injection.
Because our host is still on PHP5.3, I'm using Aura\Web -components for HTTP response/request.
Dependency injection is done with Auryn\Injector
So far I've managed to get project running, but I cannot use the alias as a classname that I've defined in the injector:
$injector = new \Auryn\Injector;
$injector->alias( 'Http\Request', '\Aura\Web\Request' );
$injector->share( '\Aura\Web\Request' );
$injector->define( '\Aura\Web\Request', array(
':client' => new \Aura\Web\Request\Client( $_SERVER ),
':content' => new \Aura\Web\Request\Content( $_SERVER ),
':globals' => new \Aura\Web\Request\Globals(
new \Aura\Web\Request\Values( $_COOKIE ),
new \Aura\Web\Request\Values( $_ENV ),
new \Aura\Web\Request\Files( $_FILES ),
new \Aura\Web\Request\Values( $_POST ),
new \Aura\Web\Request\Values( $_GET ),
new \Aura\Web\Request\Values( $_SERVER )
),
':headers' => new \Aura\Web\Request\Headers( $_SERVER ),
':method' => new \Aura\Web\Request\Method( $_SERVER, $_POST ),
':params' => new \Aura\Web\Request\Params,
':url' => new \Aura\Web\Request\Url( $_SERVER )
)
);
In my controller I would like to use this alias:
namespace Example\Controllers;
use Http\Request;
class Homepage {
public function __construct( Request $request) { ... }
}
This throws the following error:
Could not make \Example\Controllers\Homepage: Class Http\Request does not exist
I can fix this by declaring the class as:
namespace Example\Controllers;
use Aura\Web\Request;
class Homepage {
public function __construct( Request $request) { ... }
}
Which probably makes the dependency injection a bit.. useless? Auryn still supplies the proper arguments ($action = $injector->make( $action_class );), but why isn't the alias accepted?
I hope my question makes some sense. :-)
This is an Auryn "issue". If you read their docs, you can see that alias works like this:
// Tell the Injector class to inject an instance of V8 any time
// it encounters an Engine type-hint
$injector->alias('Engine', 'V8');
So all it does is it maps a default implementation (class) to an interface.
Right now you are mixing my own HTTP library with the one from Aura which won't work because Aura\Web\Request is not implementing the Http\Request interface from my library (obviously).
So what you need to do is type hint either for an interface or class that is part of the Aura library.
I recommend you give the Auryn docs a read so that you understand how alias and the other commands work.

ZF2 resolver could not resolve to a file (but works on development environment)

I've gone through the other similar questions on here and have tried numerous things though to no avail.
I have a dashboard controller that works correctly on my development machine, though when it is uploaded to the production server it reports:
Zend\View\Renderer\PhpRenderer::render: Unable to render template "Dashboard\Dashboard\Index"; resolver could not resolve to a file
I've checked my module.config.php file for the view-template (and it's correctly listed on there)
'template_path_stack' => array(
'dashboard' => __DIR__ . '/../view',
),
And the file is also at that physical location...
I'm not sure what I am missing in terms of this, so any pointers would be great.
UPDATE:
Here is the code for the controller:
public function indexAction() {
//check the users authenticity
$userId = null;
$auth = $this->getServiceLocator()->get('zfcuser_auth_service');
if ($auth->hasIdentity()) {
$user = $auth->getIdentity();
$userId = $user->getId();
} else {
$this->redirect()->toUrl('/user/login');
}
//set the view model to improve performance
//http://samminds.com/2012/11/zf2-performance-quicktipp-1-viewmodels/
$viewModel = new ViewModel();
$viewModel->setTemplate('Dashboard\Dashboard\Index');
//return the amount of counts the various items have outstanding
$dbAdapter = $this->getServiceLocator()->get('Zend\Db\Adapter\Adapter');
$systemRepo = $this->getSystemRepo($dbAdapter);
$internalContacts = $systemRepo->widgetAlphabetList("Internal Contacts", $systemRepo->getInternalContacts(), 'firstname', 'surname');
return $viewModel->setVariables(array(
'internalContacts' => $internalContacts
));
}
And the full path to the file is (add index.phtml on the end of the below):
/var/www/html/module/Dashboard/view/dashboard/dashboard
I'm going to guess dev machine is not a case sensitive file system and prod is case sensitive. Try this:
$viewModel->setTemplate('dashboard/dashboard/index')

ZF2 - Injecting pages to navigation before controller is called

I'm creating a dynamic Application in which the content is added through a CMS. Inside the CMS, I'm setting a db entry which states what module to use for each content page.
NodeId,
ParentNodeId,
Name_de,
Name_en,
ModuleName,
foreignkey_ContentLinks,
in this table entries look as follows:
6,
1,
Veranstaltung-21-02-2013,
Event-21-02-2013,
Events,
682
The entire tree should end up in my navigation (and perfectly also in my routing). I do not want to add it in some controller, because my Application consists of a whole bunch of Modules and I want to access that Info across all my Modules.
I already tried injecting it in the global.php, but to no avail because I can't my db adapter or any other important classes at that stage.
Any ideas or links to best practices?
The navigation containers are composed by factory classes. The easiest approach is to write your own factory and have the getPages() method fetch pages from a database instead of from config. If you extend from the AbstractNavigationFactory you only need to write a couple of methods.
<?php
namespace Application\Navigation\Service;
use Zend\Navigation\Service\AbstractNavigationFactory;
use Zend\ServiceManager\ServiceLocatorInterface;
class CmsNavigationFactory extends AbstractNavigationFactory
{
/**
* #param ServiceLocatorInterface $serviceLocator
* #return array
* #throws \Zend\Navigation\Exception\InvalidArgumentException
*/
protected function getPages(ServiceLocatorInterface $serviceLocator)
{
if (null === $this->pages) {
$application = $serviceLocator->get('Application');
$routeMatch = $application->getMvcEvent()->getRouteMatch();
$router = $application->getMvcEvent()->getRouter();
// get your pages from wherever...
$pages = $this->getPagesFromDB();
$this->pages = $this->injectComponents($pages, $routeMatch, $router);
}
return $this->pages;
}
public function getName()
{
// this isn't used if fetching from db, it's just here to keep the abstract factory happy
return 'cms';
}
}
Add the factory to the service manager, just like you would for other containers
'service_manager' => array(
'factories' => array(
'CmsNavigation' => 'Application\Navigation\Service\CmsNavigationFactory',
),
),
And use it with the navigation view helpers in the same way
<?php echo $this->navigation()->menu('CmsNavigation'); ?>
Responding to your comment on #Crisp's answer, and for future googlers, I'll explain how to do something similar for routing.
Typically you would want to create a custom router that can match URLs to the pages in your database, similarly to the standard Segment router. To do this, you will have to implement the Zend\Mvc\Router\RouteInterface interface. For example:
namespace Application\Router;
use Zend\Mvc\Router\RouteInterface;
use Application\Model\CMSTable;
class CmsRoute implements RouteInterface, ServiceLocatorAwareInterface
{
protected $table;
// Service locator injection code
public function getCmsTable()
{
// Retrieve the table from the service manager
}
public function match(Request $request)
{
// Match the request on some route field, etc.
}
public function assemble(array $params = array(), array $options = array())
{
// Assemble a URL based on the given parameters (e.g. page ID).
}
public static function factory($options = array())
{
// Construct a new route, based on the options.
}
}
You could then register this route as an invokable for the RoutePluginManager in your module configuration:
'route_manager' => array(
'invokables' => array(
'Cms' => 'Application\Router\CmsRoute'
),
),
Then, you can create a new route (just as you would for any other route) with type Cms. The route plugin manager will create your route instance, and since CmsRoute implements ServiceLocatorAwareInterface, the plugin manager will inject itself in the route. In turn, the plugin manager has the main service manager set, so that you can get the database table from there!
Of course you can match on page ID, but if you have a hierarchical structure, it's nicer to reflect that in your URLs. I would therefore recommend adding a route field to the database schema and match on that, beginning with the tree root and working down.

How to share zfcuser across subdomain in zend framework 2

I have in my application installed zfcuser module and everything works fine. I configured hostname router and here my problem starts, when I log in on main domain (http://example.com) everything is ok, but when I go to any subdomain (http://test.example.com, http://anysubdomain.example.com) I'm loosing logged state and on every subdomain I have to login again. How to share login state across subdomains? In ZF1 i just set 'cookie_domain' and it works but how make it in ZF2? Of course I'm using also Bjyauthorize and I want to keep bjyauthorize guards on subdomains...
Ok I found solution, in ZfcUser Module.php I've added:
use Zend\Session\Config\SessionConfig;
use Zend\Session\SessionManager;
use Zend\Session\Container;
use Zend\EventManager\EventInterface;
public function onBootstrap(EventInterface $e)
{
$config = $e->getApplication()
->getServiceManager()
->get('Configuration');
$sessionConfig = new SessionConfig();
$sessionConfig->setOptions($config['session']);
$sessionManager = new SessionManager($sessionConfig);
$sessionManager->start();
Container::setDefaultManager($sessionManager);
}
and in ZfcUser module.config.php:
return array(
'session' => array(
'use_cookies' => true,
'cookie_domain'=>'example.com',
)
);
Hope it will help somebody.

how to set a base url with sammy?

i'm looking around for javascript routing libraries and i come to Sammy, so i'm learning it.
All examples that i've seen so far show hot to proceed routing based from a domain as a base url, like www.mydomain.com/# and then all routes goes on
but i'm doing some trials within a nested dir within my localhost dir, say /wwwroot/play/sammy/ so my base url would be
http://localhost/~rockdeveloper/play/sammy/#
and then all routes must go on, like:
http://localhost/~rockdeveloper/play/sammy/#/products
http://localhost/~rockdeveloper/play/sammy/#/clients
http://localhost/~rockdeveloper/play/sammy/#/search
is there any way to set this base url so i can proceed to config sammy routes like this ?
get('#/products')
get('#/clients')
get('#/search')
by now i have to concatenate the main string to the route, and i wish it would be more smart than this...
baseurl='/~rockdeveloper/play/sammy/#/search';
get(baseurl + '#/products');
thanks.
Sammy is a frontend framework, you don't need to provide a baseurl, since all calls are made at clientside on the base of url, the rest of the path after the pound sign are there just for sammy use.
Ex:
http://localhost/~rockdeveloper/play/sammy/#/products
http://localhost/~rockdeveloper/play/sammy/#/products/iphone
http://localhost/~rockdeveloper/play/sammy/#/products/iphone/cases/all
Your base path IS
http://localhost/~rockdeveloper/play/sammy/
In all of them. The rest are just sammy routes, (think of them as GET params)
Also your routes must be defined in a way that can be called seamlessly from your anchors. Here is a portion of my routes file:
app = $.sammy('body', function() {
//define events
this.bind('addNew',function(e,data){
//data.name = data.name.split(' ').join('_');
for(x in mapa[data.element]){
if(mapa[data.element][x].name.toLowerCase() == data.name.toLowerCase()){
return alert('There is already an element with the same name');
break;
}
}
ap('Adding: '+data.element+' with the name: '+data.name);
mapa[data.element].push({name:data.name});
this.trigger('sections',{action:data.element});
});
// define routes
this.get('#/', function() {
$('#menuright').html('');
$('.customMenu').remove();
$('#holder').html('').attr({style:''});
});
this.get('#/someroute/:variable', function() {
/*
...
...
...
*/
});
this.before(function(){
if(typeof(app.historial)=='undefined'){
app.historial = [];
}
app.historial.unshift(this.path.split('#')[1]);
if(app.historial.length>2) app.historial.length = 2;
do_something();
});
});
And from your views you can just simply use something like:
<i class="icon-bookmark"></i> {{name}}
//le me here using mustache :{

Resources