How to add Javascript and CSS files to layout in ZF2 - php

I am trying to learn ZF2 and I just want to specify Javascript and CSS files to be included in my layout. I currently pass an array of paths relative to my public directory to my view and then loop through them. I would like to make use of the built in ZF2 solution using:
$this->headScript();
$this->headStyle();
I have tried many suggested methods on similar questions, but I must not be following them correctly.
One of the solutions I tried which seemed to make sense was here by using either of these in my controller:
$this->getServiceLocator()->get('Zend\View\HelperPluginManager')->get('headLink')->appendStylesheet('/css/style.css');
$this->getServiceLocator()->get('viewhelpermanager')->get('headLink')->appendStylesheet('/css/style.css');
I am not sure what viewhelpermanager it seems like a placeholder the poster used, but I have seen it in more than one question. I went ahead and found the location of Zend\View\HelperPluginManager but that did not work either.
By "not working" I mean my page is displayed without CSS and there is zero output from these:
$this->headScript();
$this->headStyle();
It seems like such a simple task and I do not know why I am having this much of a difficulty.
EDIT #1:
Here is my controller:
<?php
namespace CSAdmin\Controller;
use Zend\View\Model\ViewModel;
use Zend\View\HelperPluginManager;
class LoginController extends AdminController
{
public function __construct() {
parent::__construct();
}
public function indexAction()
{
//Set Action specific Styles and Scripts
$viewHelperManager = $this->getServiceLocator()->get(`ViewHelperManager`);
$headLinkHelper = $viewHelperManager->get('HeadLink');
$headLinkHelper->appendStylesheet('/css/admin/form.css','text/css',array());
$headLinkHelper->appendStylesheet('/css/admin/styles.css','text/css',array());
//Override view to use predefined Admin Views
$view = new ViewModel(array('data'=>$this->data));
$view->setTemplate('CSAdmin/login/login.phtml'); // path to phtml file under view folder
//Set the Admin Layout
$layout = $this->layout();
$layout->setVariable('layout', $this->layoutVars);
$layout->setTemplate('layout/CSAdmin/login.phtml');
//Render Page
return $view;
}
My AdminController:
<?php
namespace CSAdmin\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
class AdminController extends AbstractActionController
{
protected $data = array();
protected $layoutVars = array();
protected $viewHelper;
public function __construct() {
$this->layoutVars['customStyles'] = array();
$this->layoutVars['customScripts'] = array();
$this->layoutVars['miscCode'] = array();
//$this->viewHelper = $viewHelper;
}
}
EDIT #2:
#Wilt Error message for the above to controllers:
Line 19 is
$viewHelperManager = $this->getServiceLocator()->get("ViewHelperManager");
EDIT #3:
There are two modules involved here. Admin and CSAdmin, the controllers from Admin extend the controllers from CSAdmin and all of the controllers from CSAdmin extend a base controller within CSAdmin AdminController. AdminController extends AbstractActionController.
My controller and service_manager arrays for each module.config.php for both modules are below:
Admin:
'service_manager' => array(
'invokables' => array(
'CSAdmin\Form\LoginForm' => 'CSAdmin\Form\LoginForm'
),
'factories' => array(
)
),
'controllers' => array(
'invokables' => array(
),
'factories' => array(
'Admin\Controller\Login' => 'Admin\Factory\LoginControllerFactory',
)
),
// This lines opens the configuration for the RouteManager
'router' => array(
// Open configuration for all possible routes
'routes' => array(
'admin' => array(
'type' => 'literal',
'options' => array(
'route' => '/admin',
'defaults' => array(
'controller' => 'Admin\Controller\Login',
'action' => 'index',
),
),
'may_terminate' => true,
'child_routes' => array(
'home' => array(
'type' => 'literal',
'options' => array(
'route' => '/home',
'defaults' => array(
'controller' => 'Admin\Controller\Login',
'action' => 'home'
)
)
),
)
)
)
)
CSAdmin:
'service_manager' => array(
'invokables' => array(
),
'factories' => array(
'CSAdmin\Mapper\LoginMapperInterface' => 'CSAdmin\Factory\LoginMapperFactory',
'CSAdmin\Service\LoginServiceInterface' => 'CSAdmin\Factory\LoginServiceFactory'
)
),
'controllers' => array(
'invokables' => array(
),
'factories' => array(
'CSAdmin\Controller\Admin' => 'CSAdmin\Factory\AdminControllerFactory',
'CSAdmin\Controller\Login' => 'CSAdmin\Factory\LoginControllerFactory',
)
)
EDIT #4:
/module/Admin/src/Admin/Factory/LoginControllerFactory.php:
namespace Admin\Factory;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use Admin\Controller\LoginController;
use CSAdmin\Service\LoginServiceInterface;
class LoginControllerFactory implements FactoryInterface
{
/**
* Create service
*
* #param ServiceLocatorInterface $serviceLocator
* #return mixed
*/
public function createService(ServiceLocatorInterface $serviceLocator)
{
$realServiceLocator = $serviceLocator->getServiceLocator();
$loginService = $realServiceLocator->get('CSAdmin\Service\LoginServiceInterface');
$loginForm = $realServiceLocator->get('FormElementManager')->get('CSAdmin\Form\LoginForm');
return new LoginController(
$loginService,
$loginForm
);
}
}
/module/CSAdmin/src/CSAdmin/Factory/AdminControllerFactory.php:
namespace CSAdmin\Factory;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use CSAdmin\Controller\AdminController;
use Zend\View\Helper\BasePath;
class AdminControllerFactory implements FactoryInterface
{
/**
* Create service
*
* #param ServiceLocatorInterface $serviceLocator
* #return mixed
*/
public function createService(ServiceLocatorInterface $serviceLocator)
{
$realServiceLocator = $serviceLocator->getServiceLocator();
//$viewHelper = $realServiceLocator->get('Zend\View\Helper\BasePath');
//return new AdminController($viewHelper);
return new AdminController();
}
}
/module/CSAdmin/src/CSAdmin/Factory/LoginControllerFactory.php:
namespace CSAdmin\Factory;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use CSAdmin\Controller\LoginController;
class LoginControllerFactory implements FactoryInterface
{
/**
* Create service
*
* #param ServiceLocatorInterface $serviceLocator
* #return mixed
*/
public function createService(ServiceLocatorInterface $serviceLocator)
{
$realServiceLocator = $serviceLocator->getServiceLocator();
$loginService = $realServiceLocator->get('CSAdmin\Service\LoginServiceInterface');
$loginForm = $realServiceLocator->get('FormElementManager')->get('CSAdmin\Form\LoginForm');
return new LoginController(
$loginService,
$loginForm
);
}
}
EDIT #5:
After correcting the type of quotes being used I am still not getting the stylesheets in my layout. As a test I change ->appendStylesheet() to ->someMethod() and it properly reports that the method does not exist. So it definitely has an instance of the HeadLink object. As a next step I decided to just try defining everything in the layout file and it still does not use the stylesheets. See below for the exact code used in the <head> tag of my layout file.
<?php echo $this->doctype(); ?>
<html lang="en">
<head>
<meta charset="utf-8">
<title><?php echo $this->layout['title']; ?></title> //Intend to change eventually.
<?php
$this->headLink()->appendStylesheet('/css/admin/form.css');
$this->headLink()->appendStylesheet('/css/admin/styles.css');
echo $this->headScript();
echo $this->headStyle(); //This outputs nothing when viewing with the chrome debugger.
</head>
EDIT #6:
In order to get it to work, instead of using:
echo $this->headScript();
echo $this->headStyle();
I just had to do:
echo $this->headLink();

You will have to add echo to output the result...
echo $this->headScript();
echo $this->headStyle();
echo $this->headLink();
UPDATE
To get the Zend\View\HelperPluginManager in your controller you can do like this:
$viewHelperManager = $this->getServiceLocator()->get('ViewHelperManager');
Then you can do:
$headLinkHelper = $viewHelperManager->get('headLink');
UPDATE 2
Another thing, but it is a bit ridiculous, no wonder it was hard to find.
You used wrong quotes:
`ViewHelperManager` //You cannot use these: `
Try like this:
'ViewHelperManager'
or like this:
"ViewHelperManager"

you need to append file in this way
$this->headScript()->appendFile(
'/js/prototype.js',
'text/javascript',
array('conditional' => 'lt IE 7')
);
then you write it
echo $this->headScript();
note echo head script is required only one time. otherwise you inser js more time
more info at
http://framework.zend.com/manual/current/en/modules/zend.view.helpers.head-script.html

Related

How can I access Database Adapter in ZF2 Field Set?

I have followed an example and would like to pass the Database adapter to a fieldset to create a drop down menu.
The code below is how i call the fieldset.
How can i access the database adapter in the BrandFieldset class?
$this->add(array(
'type' => 'Application\Form\BrandFieldset',
'name' => 'brand',
'options' => array(
'label' => 'Brand of the product',
),
));
Instantiating a fieldset is responsibility of the FormElementManager. When you try to access a form, form element or fieldset, the FormElementManager knows where to find and how to create it. This behaviour summerized in Default Services section of the framework.
Since the proper way of accessing form elements is retrieving them from FormElementManager, I would write a BrandFieldsetFactory to inject that DB adapter or further dependencies to fieldset on construction to achieve this.
A ZF3 friendly fieldset factory would look like:
<?php
namespace Application\Form\Factory;
use Application\Form\BrandFieldset;
use Interop\Container\ContainerInterface;
class BrandFieldsetFactory
{
/**
* #return BrandFieldset
*/
public function __invoke(ContainerInterface $fem, $name, array $options = null)
{
// FormElementManager is child of AbstractPluginManager
// which makes it a ContainerInterface instance
$adapter = $fem->getServiceLocator()->get('Your\Db\Adapter');
return new BrandFieldset($adapter);
}
}
At this point, BrandFieldset should extend the Zend\Form\Fieldset\Fieldset and it's constructor may look like following:
private $dbAdapter;
/**
* {#inheritdoc}
*/
public function __construct(My/Db/Adapter $db, $options = [])
{
$this->dbAdapter = $db;
return parent::__construct('brand-fieldset', $options);
}
Finally, in module.config.php file I'd have a configuration to tell FormElementManager about this factory:
<?php
use Application\Form\BrandFieldset;
use Application\Form\Factory\BrandFieldsetFactory;
return [
// other config
// Configuration for form element manager
'form_elements' => [
'factories' => [
BrandFieldset::class => BrandFieldsetFactory::class
],
],
];
HINT: The BrandFieldset::init() method will be called automatically by FormElementManager after construction. You can put any post-initialization logic into this method.
Based of these docs I was able to find a solution.
https://framework.zend.com/manual/2.1/en/modules/zend.form.advanced-use-of-forms.html
'form_elements' => array(
'invokables' => array(
'fieldset' => BrandFieldsetFactory::class
)
)
I needed to call the form using the service locator in the controller like below.
$sl = $this->getServiceLocator();
$form = $sl->get('FormElementManager')->get('Application\Form\CreateForm');
In addition I changed the __construct to init.

Different uses of ServiceLocatorInterface in ZF2 Application

I have 2 factories.
The first is a Controller Factory:
<?php
namespace Blog\Factory;
use Blog\Controller\ListController;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
class ListControllerFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $serviceLocator)
{
$realServiceLocator = $serviceLocator->getServiceLocator();
$postService = $realServiceLocator->get('Blog\Service\PostServiceInterface');
return new ListController($postService);
}
}
The second is a Post ServiceFactory:
<?php
namespace Blog\Factory;
use Blog\Service\PostService;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
class PostServiceFactory implements FactoryInterface
{
/**
* Create service
*
* #param ServiceLocatorInterface $serviceLocator
* #return mixed
*/
public function createService(ServiceLocatorInterface $serviceLocator)
{
return new PostService(
$serviceLocator->get('Blog\Mapper\PostMapperInterface')
);
}
}
Here is my module config:
<?php
return array(
'service_manager' => array(
'factories' => array(
'Blog\Service\PostServiceInterface' => 'Blog\Factory\PostServiceFactory'
)
),
'controllers' => array(
'factories' => array(
'Blog\Controller\List' => 'Blog\Factory\ListControllerFactory'
)
),
'router' => array(
// Open configuration for all possible routes
'routes' => array(
// Define a new route called "post"
'post' => array(
// Define the routes type to be "Zend\Mvc\Router\Http\Literal", which is basically just a string
'type' => 'literal',
// Configure the route itself
'options' => array(
// Listen to "/blog" as uri
'route' => '/blog',
// Define default controller and action to be called when this route is matched
'defaults' => array(
'controller' => 'Blog\Controller\List',
'action' => 'index',
)
)
)
)
),
'view_manager' => array(
'template_path_stack' => array(
__DIR__ . '/../view',
),
)
);
In the controller factory, I have to call getServiceLocator against the ServiceLocatorInterface, followed by the get call. however in the post service factory i just call get. I did a dump and it looks like both are the Zend\ServiceManager\ServiceManager classes. When I tried performing the getServiceLocator call against the post service factory service locator it errored no method found.
Im not quite understanding whats going on?
Controller factories are called in a different way than casual service factories. The ServiceLocator passed to createService is actually not the ServiceManager you are looking for but an instance of ControllerManager.
If you try this:
public function createService(ServiceLocatorInterface $serviceLocator)
{
$realServiceLocator = $serviceLocator->getServiceLocator();
$postService = $realServiceLocator->get('Blog\Service\PostServiceInterface');
var_dump(get_class($serviceLocator));
return new ListController(postService );
}
you'll get the output:
string(37) "Zend\Mvc\Controller\ControllerManager"
while the same dump in your PostServiceFactory will give you:
string(34) "Zend\ServiceManager\ServiceManager"
From the Zend 2 documentation:
http://framework.zend.com/manual/current/en/in-depth-guide/services-and-servicemanager.html#writing-a-factory-class
When using a Factory-Class that will be called from the ControllerManager it will actually inject itself as the $serviceLocator. However, we need the real ServiceManager to get to our Service-Classes. This is why we call the function getServiceLocator() who will give us the real ServiceManager.

Zend 2 Dynamic Content in Layout with View Helpers

I'm new in Zend FW 2 and I try to showing data from database in layout but I receive error:
Catchable fatal error: Argument 1 passed to Application\View\Helper\HotNews::__construct() must be an instance of Zend\Db\Adapter\Adapter, none given, called in C:\xampp\htdocs\webtruonghoc\vendor\ZF2\library\Zend\ServiceManager\AbstractPluginManager.php on line 207 and defined in C:\xampp\htdocs\webtruonghoc\module\Application\src\Application\View\Helper\HotNews.php on li
Function getViewHelperConfig in Module.php:
public function getViewHelperConfig()
{
return array(
'factories' => array(
'hotNews' => function($sm) {
$adapter = $sm->getServiceLocator()->get('Application\Model\NewsTable');
return new HotNews($adapter);
},
),
);
}
Add code in module.config.php:
'view_helpers' => array(
'invokables' => array(
'hotnews' => 'Application\View\Helper\HotNews',
),
File HotNews.php:
<?php
namespace Application\View\Helper;
use Zend\Authentication\AuthenticationService;
use Zend\View\Helper\AbstractHelper;
use Zend\Db\Adapter\Adapter;
class HotNews extends AbstractHelper
{
protected $adapter;
public function __construct(Adapter $adapter)
{
$this->adapter = $adapter;
}
public function __invoke()
{
$sql="SELECT * FROM news order by date DESC limit 0,4";
return $resultSet = $this->adapter->query($sql, \Zend\Db\Adapter\Adapter::QUERY_MODE_EXECUTE);
}
}
and final I showing data in layout:
<?php $hotnews = $this->hotNews();
var_dump($hotnews);
?>
Do I miss something?
It looks like you are expecting your model to be set up as a service. but may not have set up the service correctly. In your module.config.php file, there should be an entry under 'service_manager' => 'factories' :
return array(
'service_manager' => array(
'factories' => array(
'Application\Model\NewsTable' => function (ServiceLocatorInterface $serviceLocator) {
//... returns an instance of Application\Model\NewsTable
}
)
)
);
Your SQL has an error in it. Also, you should not be executing SQL statements inside a view helper, and passing the entire result set of a select * to the view is bad JuJu as well. I would place the SQL inside a Repository class which returns DTO objects representing your data model. You could then inject the repository into your ViewHelper and and use those DTOs in your view.

How can I create a URL in a Console Controller in ZF2?

I have a Console Controller and an action to send emails (defined below in module.config.php)
'console' => array(
'router' => array(
'routes' => array(
'cronroute' => array(
'options' => array(
'route' => 'sendEmails',
'defaults' => array(
'controller' => 'Application\Controller\Console',
'action' => 'send-emails'
)
)
),
)
)
),
In the action I want to send an email that contains a link to another action on the site. This would normally be done with a URL View Helper, but since the Request is of type Console and not HTTP, that doesn't work. I've tried to create an HTTP request, but I do not know how to give it the site domain or the Controller/Action link.
My Controller code:
$vhm = $this->getServiceLocator()->get('viewhelpermanager');
$url = $vhm->get('url');
$urlString = $url('communication', array('action' => 'respond', 'id' => $id,
array('force_canonical' => true));
This throws an error:
======================================================================
The application has thrown an exception!
======================================================================
Zend\Mvc\Router\Exception\RuntimeException
Request URI has not been set
How do I create an HTTP Request in a Console Controller that has the site scheme, domain and path/to/action? And how do I pass it along to the URL View Helper?
Here's how this issue can be solved:
<?php
// Module.php
use Zend\View\Helper\ServerUrl;
use Zend\View\Helper\Url as UrlHelper;
use Zend\Uri\Http as HttpUri;
use Zend\Console\Console;
use Zend\ModuleManager\Feature\ViewHelperProviderInterface;
class Module implements ViewHelperProviderInterface
{
public function getViewHelperConfig()
{
return array(
'factories' => array(
'url' => function ($helperPluginManager) {
$serviceLocator = $helperPluginManager->getServiceLocator();
$config = $serviceLocator->get('Config');
$viewHelper = new UrlHelper();
$routerName = Console::isConsole() ? 'HttpRouter' : 'Router';
/** #var \Zend\Mvc\Router\Http\TreeRouteStack $router */
$router = $serviceLocator->get($routerName);
if (Console::isConsole()) {
$requestUri = new HttpUri();
$requestUri->setHost($config['website']['host'])
->setScheme($config['website']['scheme']);
$router->setRequestUri($requestUri);
}
$viewHelper->setRouter($router);
$match = $serviceLocator->get('application')
->getMvcEvent()
->getRouteMatch();
if ($match instanceof RouteMatch) {
$viewHelper->setRouteMatch($match);
}
return $viewHelper;
},
'serverUrl' => function ($helperPluginManager) {
$serviceLocator = $helperPluginManager->getServiceLocator();
$config = $serviceLocator->get('Config');
$serverUrlHelper = new ServerUrl();
if (Console::isConsole()) {
$serverUrlHelper->setHost($config['website']['host'])
->setScheme($config['website']['scheme']);
}
return $serverUrlHelper;
},
),
);
}
}
Of course you have to define default host and scheme values in config since there's no way to detect them automatically in console mode.
Update:
The correct answer for this post can be found here:
Stackoverflow: Using HTTP routes within ZF2 console application
Well you're very close to this but you are not using the Url plugin. If you dived a little bit further into the ZF2 Documentation of the Controller Plugins you could have found the solution.
See for reference: ZF2 Documentation - Controller plugins
Your ConsoleController has to implement one of the following, to be able to retrieve the Controller plugins:
AbstractActionController
AbstractRestfulController
setPluginManager
Well I recommend to extend your controller with the AbstractActionController if you haven't done it yet.
In case you do use the AbstractActionController you can simply call $urlPlugin = $this->url() since the AbstractActionController has an __call() implementation retrieving the plugin for you. But you can also use: $urlPlugin = $this->plugin('url');
So in order to generate the URL for your mail you can do the following in your controller:
$urlPlugin = $this->url();
$urlString = $urlPlugin->fromRoute(
'route/myroute',
array(
'param1' => $param1,
'param2' => $param2
),
array(
'option1' => $option1,
'option2' => $option2
)
);
You can now pass this URL to your viewModel or use the URL viewHelper within your viewModel, but that is up to you.
Try to avoid viewHelpers within your controller as we've got plugins available for this case.
In case you wonder what methods the AbstractActionController has, here is ZF2 ApiDoc - AbstractActionController
In order to make this work you have to setup your route config with a proper structure:
// This can sit inside of modules/Application/config/module.config.php or any other module's config.
array(
'router' => array(
'routes' => array(
// HTTP routes are here
)
),
'console' => array(
'router' => array(
'routes' => array(
// Console routes go here
)
)
),
)
If you've got a Console module, just stick with the console route paths. Don't forget the console key with all the routes beneath it! Take a look at the documentation for a reference: ZF2 - Documentation: Console routes and routing
I think the best solution is using a DelegatorFactory.
config/autoload/server-url.local.php:
return [
'server_url' => 'http://example.com',
];
module/Application/config/module.config.php:
'service_manager' => [
'delegators' => [
TreeRouteStack::class => [
TreeRouteStackConsoleDelegatorFactory::class,
],
]
],
module/Application/src/TreeRouteStackConsoleDelegatorFactory.php:
namespace Application;
use Interop\Container\ContainerInterface;
use Zend\Router\Http\TreeRouteStack;
use Zend\ServiceManager\Factory\DelegatorFactoryInterface;
use Zend\Uri\Http;
class TreeRouteStackConsoleDelegatorFactory implements DelegatorFactoryInterface
{
public function __invoke(ContainerInterface $container, $name, callable $callback, array $options = null)
{
/** #var TreeRouteStack $treeRouteStack */
$treeRouteStack = $callback();
if (!$treeRouteStack->getRequestUri()) {
$treeRouteStack->setRequestUri(
new Http($container->get('config')['server_url'])
);
}
return $treeRouteStack;
}
}
I can't believe it but I did it :)
Hope it will work for all of You.
In controller where the fromRoute() function is used I added those lines below:
$event = $this->getEvent();
$http = $this->getServiceLocator()->get('HttpRouter');
$router = $event->setRouter($http);
$request = new \Zend\Http\Request();
$request->setUri('');
$router = $event->getRouter();
$routeMatch = $router->match($request);
var_dump($this->url()->fromRoute(
'route_parent/route_child',
[
'param1' => 1,
'param2' => 2,
)
);
Output:
//mydomain.local/route-url/1/2
Of course route_parent/route_child is not a console route but HTTP route :)
Thank #Alexey Kosov for response. You will probably have an issue when your application is working under subdirectory rather than root directory after domain '/'.
You have to add:
$router->setBaseUrl($config['website']['path']);
Whole code:
<?php
// Module.php
use Zend\View\Helper\ServerUrl;
use Zend\View\Helper\Url as UrlHelper;
use Zend\Uri\Http as HttpUri;
use Zend\Console\Console;
use Zend\ModuleManager\Feature\ViewHelperProviderInterface;
class Module implements ViewHelperProviderInterface
{
public function getViewHelperConfig()
{
return array(
'factories' => array(
'url' => function ($helperPluginManager) {
$serviceLocator = $helperPluginManager->getServiceLocator();
$config = $serviceLocator->get('Config');
$viewHelper = new UrlHelper();
$routerName = Console::isConsole() ? 'HttpRouter' : 'Router';
/** #var \Zend\Mvc\Router\Http\TreeRouteStack $router */
$router = $serviceLocator->get($routerName);
if (Console::isConsole()) {
$requestUri = new HttpUri();
$requestUri->setHost($config['website']['host'])
->setScheme($config['website']['scheme']);
$router->setRequestUri($requestUri);
$router->setBaseUrl($config['website']['path']);
}
$viewHelper->setRouter($router);
$match = $serviceLocator->get('application')
->getMvcEvent()
->getRouteMatch();
if ($match instanceof RouteMatch) {
$viewHelper->setRouteMatch($match);
}
return $viewHelper;
},
'serverUrl' => function ($helperPluginManager) {
$serviceLocator = $helperPluginManager->getServiceLocator();
$config = $serviceLocator->get('Config');
$serverUrlHelper = new ServerUrl();
if (Console::isConsole()) {
$serverUrlHelper->setHost($config['website']['host'])
->setScheme($config['website']['scheme']);
}
return $serverUrlHelper;
},
),
);
}
}
I had an similar problem with zend console - the serverUrl view helper also not worked properly by default.
My case:
/module/Application/src/Application/Controller/ConsoleController.php
...
public function someAction()
{
...
$view = new ViewModel([
'data' => $data,
]);
$view->setTemplate('Application/view/application/emails/some_email_template');
$this->mailerZF2()->send(array(
'to' => $data['customer_email'],
'subject' => 'Some email subject',
), $view);
...
}
/module/Application/view/application/emails/some_email_template.phtml
<?php
/** #var \Zend\View\Renderer\PhpRenderer $this */
/** #var array $data */
?><!doctype html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link ... rel="stylesheet" />
<title>...</title>
</head>
<body>
<div style="...">
... <img src="<?= $this->serverUrl() ?>/images/logo-maillist.png" width="228" height="65"> ...
<p>Hello, <?= $this->escapeHtml($data['customer_name']) ?>!</p>
<p>... email body ...</p>
<div style="...">
some action ...
</div>
...
</div>
</body>
</html>
The serverUrl view helper returns just only "http://" under Console Controller (runned by cron). But the same template renders properly under web http requests handled by other controllers.
I fixed it by this way:
/config/autoload/global.php
return array(
...
'website' => [
'host' => isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'my.production.domain',
'scheme' => 'https',
'path' => '',
],
);
/config/autoload/local.php
return array(
...
'website' => [
'host' => isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'my.local.domain',
],
);
/public/index.php (the ZF2 engine starting script)
chdir(dirname(__DIR__));
// --- Here is my additional code ---------------------------
if (empty($_SERVER['HTTP_HOST'])) {
function array_merge_recursive_distinct(array &$array1, array &$array2)
{
$merged = $array1;
foreach ($array2 as $key => &$value) {
if (is_array($value) && isset($merged[$key]) && is_array($merged[$key])) {
$merged[$key] = array_merge_recursive_distinct($merged[$key], $value);
} else {
$merged[$key] = $value;
}
}
return $merged;
}
$basicConfig = require 'config/autoload/global.php';
$localConfig = #include 'config/autoload/local.php';
if (!empty($localConfig)) {
$basicConfig = array_merge_recursive_distinct($basicConfig, $localConfig);
}
unset($localConfig);
$_SERVER['HTTP_HOST'] = $basicConfig['website']['host'];
$_SERVER['HTTP_SCHEME'] = $basicConfig['website']['scheme'];
$_SERVER['HTTPS'] = $_SERVER['HTTP_SCHEME'] === 'https' ? 'on' : '';
$_SERVER['SERVER_NAME'] = $_SERVER['HTTP_HOST'];
unset($basicConfig);
}
// ---/End of my additional code ---------------------------
// Setup autoloading
require 'init_autoloader.php';
...
And that's all that I changed.
Magic! It works! :-)
Hope this helps to someone too.

zend-fzend framework 2 cron

I have application created in Zend Framework 2. I would like to run controller action as cron job. I read a lot about it but I don't know how to run it.
I did something like that. I added console route to module's module.config.php
'console' => array(
'router' => array(
'routes' => array(
'cronroute' => array(
'options' => array(
'route' => 'updateproducts',
'defaults' => array(
'controller' => 'Application\Controller\Console',
'action' => 'update'
)
)
)
),
),
),
I created Controller named ConsoleController
namespace Application\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Application\Model;
use Application\Model\Auth;
class ConsoleController extends AbstractActionController
{
protected $usersTable = null;
public function updateAction()
{
$this->getUsersTable()->cronTest();
return false;
}
public function getUsersTable()
{
if (!$this->usersTable) {
$sm = $this->getServiceLocator();
$this->usersTable = $sm->get('Application\Model\UsersTable');
}
return $this->usersTable;
}
Inside Auth.php
public function cronTest(){
$data = array(
'login' => 'cronZend'
);
$this->tableGateway->insert($data);
}
I think that everything here is OK and I tried to write something inside command line on shared server:
/usr/local/bin/php /home/****/domains/****/public_html/public/index.php updateproducts
and it doesn't work. When I test it writing something like that in cron.php
$dbc = mysqli_connect(****);
$query = "INSERT INTO vm_user (login) VALUES ('cron')";
mysqli_query($dbc, $query);
and in command line
/usr/local/bin/php /home/****/domains/****/public_html/cron.php
it works fine. Could anyone tell me what is wrong or how to do it?

Categories