Render partial in other module ZF2 - zend-framework2

In my project I have to modules
Module1
Module2
In Module1 I have a view that needs to render a view that I have in Module2, so what I'm doing is:
$this->partial('partials/hello/title.phtml','Module2',array('data' => $data))
and seems I'm calling correctly the view, but inside of the view title.phtml I'm unable to use data
Undefined variable: data in /site/src/module/Module2/view/partials/hello/title.phtml
Do I need add something related to the configuration?
Thanks!

You aren't calling it correctly, try:
$this->partial('partials/hello/title.phtml', array('data' => $data));
See: http://framework.zend.com/manual/2.3/en/modules/zend.view.helpers.partial.html
The fact that the partial is in a different module doesn't matter. Having to specify the module name as the second parameter was a thing in ZF1 only.

Another solution is add your own view-path resolver in module-bootstrap:
class Module
{
/* #var \Zend\ServiceManager\ServiceManager $SM */
public static $SM;
/* #var \Zend\EventManager\EventManager $EM */
public static $EM;
public function onBootstrap(MvcEvent $e)
{
self::$SM = $e->getApplication()->getServiceManager();
self::$EM = $e->getApplication()->getEventManager();
//change view resolver to resolve views from {Module}/view/{Controller}/{Action}.phtml path
self::$EM->attach('dispatch', function($e) {
self::$SM->get('ViewRenderer')->resolver()->attach(
new \Engine\View\Resolver\MCA() , 10
);
});
}
....
Resolver gets a string, and must to return path or false (if not resolved), just write resolver to understand other-modules paths:
<?php
namespace Engine\View\Resolver;
use Zend\View\Renderer\RendererInterface as Renderer;
/**
* Resolves view scripts based on a stack of paths
*/
class MCA implements \Zend\View\Resolver\ResolverInterface
{
public function resolve($name, Renderer $renderer = null)
{
$path = explode('/', $name);
if (count($path)<3){
return false;
}
$module = array_shift($path);
$resolvedPath = ROOT_PATH . '/module/'. ucfirst($module) . '/view/' . implode('/', $path). '.phtml';
if (!file_exists($resolvedPath)){
return false;
}
return $resolvedPath;
}
}
There can be collisions, but you can regulate priority of resolvers (10 in example).

Related

Zend framework 2 session exists or not, in Module.php

I am trying to call the session in public function onBootstrap(MvcEvent $e) function in Module.php
public function onBootstrap(MvcEvent $e)
{
if( $user_session->offsetExists('user_email_id')){
//code here
}
else {
header("Location: ". $this->serverUrl() . "/register");
}
}
How can i achieve this?
i am not getting the echo $this->serverUrl(); inside the OnBootstrap function
There a number of problems with this code.
You need to create a new session container (Zend\Session\Container) to set/get your session data.
You are trying to set headers manually, although this would work, there are better ways to do so in ZF2.
Redirection in the onBootstrap method is probably not the best 'time' to do so.
You attempt to use a view helper in Module.php (\Zend\View\Helper\ServiceUrl) to redirect. View helpers can should only be called in the view. You can use them, however you would need to fetch it via the ViewPluginManager, rather than using $this->.
With these points in mind I would consider adding a event listener either late onRoute or early onDispatch.
For example:
namespace FooModule;
use Zend\ModuleManager\Feature\BootstrapListenerInterface;
use Zend\EventManager\EventInterface;
use Zend\Session\Container;
use Zend\Mvc\MvcEvent;
class Module implements BootstrapListenerInterface
{
public function onBootstrap(EventInterface $event)
{
$application = $event->getApplication();
$eventManager = $application->getEventManager();
$eventManager->attach(MvcEvent::EVENT_DISPATCH, [$this, 'isLoggedIn'], 100);
}
public function isLoggedIn(MvcEvent $event)
{
$data = new Container('user');
if (! isset($data['user_email_id'])) {
$serviceManager = $event->getApplication()->getServiceManager();
$controllerPluginManager = $serviceManager->get('ControllerPluginManager');
// Get the \Zend\Mvc\Controller\Plugin\Redirect
$redirect = $controllerPluginManager->get('redirect');
return $redirect->toRoute('some/route/path', ['foo' => 'bar']);
}
// use $data here
}
}

Get local value in layout or view in Zend Framework 2

How can we get local value (i.e: 'en' or 'en_US', 'de' etc) in layout.phtml or views in Zend Framework 2?
My local setting are exactly same as explained here
<?php
namespace FileManager;
use Zend\Mvc\ModuleRouteListener;
class Module
{
public function onBootstrap($e)
{
$translator = $e->getApplication()->getServiceManager()->get('translator');
$translator
->setLocale(\Locale::acceptFromHttp($_SERVER['HTTP_ACCEPT_LANGUAGE']))
->setFallbackLocale('en_US');
}
//...
}
I want to get local value something like this:
$locale = $this->translate()->getLocale(); // <-- It's not working anyway
I need to use '$locale' it while calling google map api url to get matched locale/language. I'm calling it throughtout the application in layout.phtml
$this->headScript()->appendFile('http://maps.googleapis.com/maps/api/js?language=' . $locale);
So I want to make language option dynamic while calling api.
PS: I don't have any query string parameter such as 'language', It's a google api thing which I need to set in script url (if you don't know) Please don't get confused.
Not answered here
Depends on where you want to get the Locale value from. In any case, you can do it in your controller, e.g.:
$locale = $this->request->getQuery('language');
$this->layout()->locale = $locale;
or
return new ViewModel(array('locale' => $locale));
Edit if you just want to get the locale from the translator, you can try this in view script:
$this->plugin('translate')->getTranslator()->getLocale();
My version is like that
<?php
namespace FileManager;
use Zend\Mvc\ModuleRouteListener;
use Zend\Session\Container;
class Module
{
public function onBootstrap($e)
{
$application = $e->getTarget();
$serviceManager = $application->getServiceManager();
$eventManager = $application->getEventManager();
$events = $eventManager->getSharedManager();
// session container
$sessionContainer = new Container('locale');
// test if the language in session exists
if(!$sessionContainer->offsetExists('mylocale')){
// doesn't so the browser lan
if(isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])){
$sessionContainer->offsetSet('mylocale', Locale::acceptFromHttp($_SERVER['HTTP_ACCEPT_LANGUAGE']));
}else{
$sessionContainer->offsetSet('mylocale', 'en_US');
}
}
// translation
$translator = $serviceManager->get('translator');
$translator ->setLocale($sessionContainer->mylocale)
->setFallbackLocale('en_US');
$mylocale = $sessionContainer->mylocale;
$events->attach('Zend\Mvc\Controller\AbstractActionController', 'dispatch', function($e) use ($mylocale) {
$controller = $e->getTarget();
$controller->layout()->mylocale = $mylocale;
}, 100);
}
//...
}
in your layout
$this->headScript()->appendFile('http://maps.googleapis.com/maps/api/js?language=' . $this->mylocale);

Smarty Fetch is not loading anything into my variable

I have a class that sets up my smarty instances:
class View {
protected $templateEngine;
protected $templateExtension = '.tpl';
public function __construct(){
global $ABS_PUBLIC_PATH;
global $ABS_PUBLIC_URL;
$this->templateEngine = new Smarty();
$this->templateEngine->error_reporting = E_ALL & ~E_NOTICE;
$this->templateEngine->setTemplateDir($ABS_PUBLIC_PATH . '/templates/');
$this->templateEngine->setCompileDir($ABS_PUBLIC_PATH . '/templates_c/');
$this->templateEngine->assign('ABS_PUBLIC_URL', $ABS_PUBLIC_URL);
if(isset($_SESSION['loggedIn'])){
$this->assign('session', $_SESSION);
}
}
public function assign($key, $value){
$this->templateEngine->assign($key, $value);
}
public function display($templateName){
$this->templateEngine->display($templateName . $this->templateExtension);
}
public function fetch($templateName){
$this->templateEngine->fetch($templateName . $this->templateExtension);
}
}
Then in my functions, I use the class like this:
public function showMeSomething()
{
$view = new View();
$view->assign('session', $_SESSION);
$view->display('header');
$view->display('index');
$view->display('footer');
}
Now, I'm trying to fetch some data into a variable, in order to send emails from my template files as well. Unfortunately, this var_dumps below (both of them) output NULL - even though the template file referenced has a lot of HTML in it. Furthermore, changing the word fetch to display below will correctly display the template file. So, the problem certainly lies within the fetch command. I'm not sure what to do to continue debugging.
function emailPrep($data,){
$mailView = new View();
$emailHTML = $mailView->fetch('myEmail');
var_dump($mailView->fetch("myEmail"));
var_dump($emailHTML);
}
Your code must be
public function fetch($templateName){
return $this->templateEngine->fetch($templateName . $this->templateExtension);
}

Symfony 2 Controller dependencies, extending ContainerAware

Edit
after digging into the symfony code, particularly the ControllerResolver, it seems what im trying to do actually isnt possible unless i subclass/implement ControllerResolverInterface myself.
this is the following code which instantiates the controller passed from the route:
protected function createController($controller)
{
if (false === strpos($controller, '::')) {
throw new \InvalidArgumentException(sprintf('Unable to find controller "%s".', $controller));
}
list($class, $method) = explode('::', $controller, 2);
if (!class_exists($class)) {
throw new \InvalidArgumentException(sprintf('Class "%s" does not exist.', $class));
}
return array(new $class(), $method);
}
as you can see on the last line, this is always instantiated with no arguments passed, so i will have to override this method to inject something in that way. feels very hacky.
Original Question
I'm trying to figure out how I can inject services into a custom controller defined in dynamic routes using Symfony components (e.g. not the full stack framework).
Please note, I am not using the full stack framework and am not using their DemoBundle src code. I have a composer.json file that requires components, so I have a custom index.php file which is more or less the same as that detailed here:
http://fabien.potencier.org/article/55/create-your-own-framework-on-top-of-the-symfony2-components-part-12
I have the following:
$routes = new RouteCollection();
$routes->add(
'some route name',
new Route(
'a route path',
array(
'_controller' => 'App\MyBundle\Controller\MyController::handle'
)
)
);
Then I have the following within App/MyBundle/DependencyInjection/MyExtension.php:
public function load(array $configs, ContainerBuilder $container) {
$loader = new XmlFileLoader(
$container,
new FileLocator(__DIR__.'/../Resource/config')
);
$loader->load('services.xml');
}
App/MyBundle/Resources/config/services.xml:
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services
http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="templating" class="Symfony\Component\Templating\EngineInterface" />
<service id="navigation" class="App\MyBundle\Controller\MyController">
<argument type="service" id="templating" />
</service>
</services>
</container>
I'm basically trying to get the templating service injected into the MyController constructor, and my understanding is the MyExtension file should be loaded automatically. I assume as I'm not using the full stack framework, this is the reason why, but how can I get this working?
Nothing wrong with overriding ControllerResolver. The full stack framework does that too. Otherwise the Controllers couldn't be ContainerAware.
I also use Symfony Components without the full stack framework and, partly copying the full stack framework, I ended up with this in order to inject the container in my controllers
class ControllerResolver extends SymfonyControllerResolver
{
protected $container;
public function __construct(ContainerInterface $container, LoggerInterface $logger = null)
{
$this->container = $container;
parent::__construct($logger);
}
protected function createController($controller)
{
if (false === strpos($controller, '::')) {
throw new \InvalidArgumentException(sprintf('Unable to find controller "%s".', $controller));
}
list($class, $method) = explode('::', $controller, 2);
$class = "Namespace\\Controllers\\" . $class;
if (!class_exists($class)) {
throw new \InvalidArgumentException(sprintf('Class "%s" does not exist.', $class));
}
$controller = new $class();
if ($controller instanceof ContainerAwareInterface) {
$controller->setContainer($this->container);
}
return array($controller, $method);
}
}
If you wanted to add possibility to define controllers as services you can replace
if (!class_exists($class)) {
throw new \InvalidArgumentException(sprintf('Class "%s" does not exist.', $class));
}
$controller = new $class();
if ($controller instanceof ContainerAwareInterface) {
$controller->setContainer($this->container);
}
With something like
if (!class_exists($class)) {
if (!$this->container->has($class)) {
throw new \Exception( ... );
}
$controller = $this->container->get($class);
return array($controller, $method);
}
$controller = new $class();
if ($controller instanceof ContainerAwareInterface) {
$controller->setContainer($this->container);
}
return array($controller, $method);
Well, at first. You don't have to inject services into your controller. A normal controller will extend Symfony\Bundle\FrameworkBundle\Controller\Controller which gets the hole container injected. This means you can access the templating service like this:
public function myAction()
{
$templating = $this->get('templating');
}
But Symfony2 gives you also the possibility of creating controller as services. That means you remove the extend from the default Controller and instead of that only inject the services you need (usually request and response). More information can be found in this great post by Richard Miller.
You can also read this post by Lukas Kahwe Smith, in which he talks about why he thinks services are a 'best practise' (please note that Fabien, former of the Symfony project, disagrees with this).

zend framework 2 base path access in controller

How can i call basePath helper in controller in ZF 2. I have to redirect to a particular url in which i need base path.
return $this->redirect()->toUrl($basePath.'/application/rent/search');
Here's an easy method to make all view helpers available from within the controllers. So you should be able to use the following:
public function someAction()
{
$renderer = $this->serviceLocator->get('Zend\View\Renderer\RendererInterface');
$url = $renderer->basePath('/application/rent/search');
$redirect = $this->plugin('redirect');
return $redirect->toUrl($url);
}
The full base url (http://...) can be determined from within the controller as follows:
$event = $this->getEvent();
$request = $event->getRequest();
$router = $event->getRouter();
$uri = $router->getRequestUri();
$baseUrl = sprintf('%s://%s%s', $uri->getScheme(), $uri->getHost(), $request->getBaseUrl());
try
class XxxController extends AbstractActionController
{
...
public function basePath()
{
$basePath = $this->serviceLocator
->get('viewhelpermanager')
->get('basePath');
return $basePath();
}
in
OR
public function algoAction()
{
echo $this->getRequest()->getBaseUrl();
}
http://project.com/profile
returns ""
http://localhost/~limonazzo/public/profile
returns /~limonazzo/public/

Resources