我有一个控制台控制器和一个发送电子邮件的动作(在下面的module.config.php中定义)
'console' => array(
'router' => array(
'routes' => array(
'cronroute' => array(
'options' => array(
'route' => 'sendEmails',
'defaults' => array(
'controller' => 'Application\Controller\Console',
'action' => 'send-emails'
)
)
),
)
)
),
在我要发送的电子邮件中,该电子邮件包含指向该网站上其他操作的链接。这通常是通过URL View Helper完成的,但由于Request类型是Console而不是HTTP,因此不起作用。我曾尝试创建HTTP请求,但我不知道如何为其提供站点域或控制器/操作链接。
我的控制器代码:
$vhm = $this->getServiceLocator()->get('viewhelpermanager');
$url = $vhm->get('url');
$urlString = $url('communication', array('action' => 'respond', 'id' => $id,
array('force_canonical' => true));
这会引发错误:
======================================================================
The application has thrown an exception!
======================================================================
Zend\Mvc\Router\Exception\RuntimeException
Request URI has not been set
如何在具有站点方案,域和路径/到/ action的控制台控制器中创建HTTP请求?我如何将其传递给URL View Helper?
答案 0 :(得分:1)
以下是此问题的解决方法:
<?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;
},
),
);
}
}
当然,您必须在config中定义默认主机和方案值,因为无法在控制台模式下自动检测它们。
答案 1 :(得分:0)
<强>更新 这篇文章的正确答案可以在这里找到: Stackoverflow: Using HTTP routes within ZF2 console application
嗯,你非常接近这个,但你没有使用Url
插件。如果您进一步深入了解控制器插件的ZF2文档,您可以找到解决方案。
参见参考:ZF2 Documentation - Controller plugins
您的ConsoleController
必须执行以下操作之一才能检索Controller插件:
AbstractActionController
AbstractRestfulController
setPluginManager
我建议你使用AbstractActionController
来扩展你的控制器,如果还没有完成的话。
如果您使用AbstractActionController
,则只需致电$urlPlugin = $this->url()
,因为AbstractActionController
有一个__call()
实现为您检索插件。但您也可以使用:$urlPlugin = $this->plugin('url');
因此,为了生成邮件的URL,您可以在控制器中执行以下操作:
$urlPlugin = $this->url();
$urlString = $urlPlugin->fromRoute(
'route/myroute',
array(
'param1' => $param1,
'param2' => $param2
),
array(
'option1' => $option1,
'option2' => $option2
)
);
您现在可以将此网址传递给viewModel
或使用viewModel中的网址viewHelper,但这取决于您。
尽量避免使用控制器中的viewHelpers,因为我们已经为这种情况提供了插件。
如果你想知道AbstractActionController
有哪些方法,这里是ZF2 ApiDoc - AbstractActionController
为了完成这项工作,您必须使用适当的结构设置路由配置:
// 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
)
)
),
)
如果您有控制台模块,只需坚持控制台路径路径即可。不要忘记控制台键及其下面的所有路线!请查看文档以获取参考:ZF2 - Documentation: Console routes and routing
答案 2 :(得分:0)
我无法相信,但我做到了:)
希望它适用于所有人。
在使用fromRoute()函数的控制器中,我添加了以下行:
$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,
)
);
输出:
//mydomain.local/route-url/1/2
当然,route_parent / route_child不是控制台路由,而是HTTP路由:)
答案 3 :(得分:0)
感谢@Alexey Kosov的回复。当您的应用程序在域名'/'后面的子目录而不是根目录下工作时,您可能会遇到问题。
你必须添加:
$router->setBaseUrl($config['website']['path']);
整个代码:
<?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;
},
),
);
}
}
答案 4 :(得分:0)
我在zend控制台上遇到了类似的问题 - 默认情况下,serverUrl
视图助手也无法正常工作。
我的情况:
/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>
serverUrl
视图助手只返回控制台控制器下的"http://"
(由cron运行)。但是相同的模板在其他控制器处理的Web http请求下正确呈现。
我通过这种方式修复了它:
/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(ZF2引擎启动脚本)
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';
...
这就是我改变的一切。
魔术!有用! : - )
希望这对某人也有帮助。
答案 5 :(得分:0)
我认为最好的解决方案是使用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;
}
}