How to create url in console controller in ZF2?

I have a console controller and an action for sending emails (defined below in the module.config.php file)

'console' => array( 'router' => array( 'routes' => array( 'cronroute' => array( 'options' => array( 'route' => 'sendEmails', 'defaults' => array( 'controller' => 'Application\Controller\Console', 'action' => 'send-emails' ) ) ), ) ) ), 

In action, I want to send an email containing a link to another action on the site. This is usually done using the URL browse helper, but since the request is of type Console and not HTTP, this does not work. I tried to create an HTTP request, but I do not know how to pass the site domain or the Controller / Action link to it.

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 causes an error:

 ====================================================================== The application has thrown an exception! ====================================================================== Zend\Mvc\Router\Exception\RuntimeException Request URI has not been set 

How to create an HTTP request in a console controller that has a site map, domain and path / in / action? And how do I pass it along with the URL view helper?

+8
php zend-framework2
source share
5 answers

Update: The correct answer to this post can be found here: stack overflow

Well, you are very close to this, but you are not using the Url plugin. If you are a little immersed in the ZF2 Documentation controller plugins, you might find a solution.

See link: ZF2 Documentation - Controller Plugins

Your ConsoleController must do one of the following in order to be able to retrieve controller plugins:

  • AbstractActionController
  • AbstractRestfulController
  • setPluginManager

Well, I recommend extending your controller using AbstractActionController if you haven't already.

If you use AbstractActionController , you can simply call $urlPlugin = $this->url() , since AbstractActionController has an __call() implementation that retrieves the plugin for you. But you can also use: $urlPlugin = $this->plugin('url');

So, to generate a 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 viewModel URL in your viewModel, but that is up to you.

Try to avoid viewHelpers inside your controller as we have plugins available for this case.

If you are wondering what methods AbstractActionController has, here ZF2 ApiDoc is AbstractActionController

To do this, you need to configure the route configuration with the appropriate structure:

 // This can sit inside of modules/Application/config/module.config.php or any other module config. array( 'router' => array( 'routes' => array( // HTTP routes are here ) ), 'console' => array( 'router' => array( 'routes' => array( // Console routes go here ) ) ), ) 

If you have a console module, just stick to the console route paths. Do not forget the console key with all the routes under it! Take a look at the documentation for reference: ZF2 - Documentation: console routes and routing

0
source share

Here's how this problem 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 must determine the default host and schema values ​​in config, as there is no way to automatically detect them in console mode.

0
source share

I can’t believe it, but I did it :)

Hope this works for all of you.

In the controller where the fromRoute () function is used, I added the following lines:

  $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 an HTTP route :)

0
source share

Thanks @Alexey Kosov for the answer. You will probably have a problem when your application runs in a subdirectory, and not in the root directory after the '/' domain.

You must add:

 $router->setBaseUrl($config['website']['path']); 

All 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; }, ), ); } } 
0
source share

I had a similar problem with the zend console - the serverUrl view serverUrl also did not work 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="..."> ... <a href="<?= $this->serverUrl() ?>"><img src="<?= $this->serverUrl() ?>/images/logo-maillist.png" width="228" height="65"></a> ... <p>Hello, <?= $this->escapeHtml($data['customer_name']) ?>!</p> <p>... email body ...</p> <div style="..."> <a href="<?= $this->serverUrl() ?>/somepath/<?= $data['some-key'] ?>" style="...">some action</a> ... </div> ... </div> </body> </html> 

The serverUrl view serverUrl only returns "http://" under the Console controller (cron is executed). But the same pattern is correctly displayed in web http requests processed by other controllers.


I fixed it as follows:

/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(starting the ZF2 script engine)

 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 is all that I have changed .

Magic! It works!: -)

Hope this helps someone too.

0
source share

All Articles