I have a web app using zf2. And when it launches it shows the URL like follows:
http://www.example.com/auth/themes/neighborhoods for the neighborhoods
http://www.example.com/auth/comments/comments for the comments
http://www.example.com/auth/themes/themes for the themes
I need to make them like:
http://www.example.com/neighborhoods
http://www.example.com/comments
http://www.example.com/themes
I tried to play with module.config.php, but no use:
'router' => array(
'routes' => array(
'home' => array(
'type' => 'Literal',
'options' => array(
'route' => '/',
'defaults' => array(
'controller' => 'Auth\Controller\Index',
'action' => 'login',
),
),
),
'auth' => array(
'type' => 'Literal',
'options' => array(
'route' => '/auth',
'defaults' => array(
'__NAMESPACE__' => 'Auth\Controller',
'controller' => 'Auth\Controller\Index',
'action' => 'login',
),
),
'may_terminate' => true,
'child_routes' => array(
'default' => array(
'type' => 'Segment',
'options' => array(
'route' => '/[:controller[/:action[/:id]]]',
'constraints' => array(
'controller' => '[a-zA-Z][a-zA-Z0-9_-]*',
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
'id' => '[a-zA-Z0-9_-]*',
),
'defaults' => array(
),
),
),
),
),
),
),
Any help would be appreciated!
Solution one :
'neighborhoods' => array(
'type' => 'Literal',
'options' => array(
'route' => '/neighborhoods',
'defaults' => array(
'module' => 'auth',
'controller' => 'neighborhoods',
'action' => 'neighborhoods',
),
),
'child_routes' => array(
'default' => array(
'type' => 'Segment',
'options' => array(
'route' => '/[:id]',
'constraints' => array(
'id' => '[a-zA-Z0-9_-]*',
),
'defaults' => array(
),
),
),
),
'comments' => array(
'type' => 'Literal',
'options' => array(
'route' => '/comments',
'defaults' => array(
'module' => 'auth',
'controller' => 'comments',
'action' => 'comments',
),
),
'child_routes' => array(
'default' => array(
'type' => 'Segment',
'options' => array(
'route' => '/[:id]',
'constraints' => array(
'id' => '[a-zA-Z0-9_-]*',
),
'defaults' => array(
),
),
),
),
'themes' => array(
'type' => 'Literal',
'options' => array(
'route' => '/themes',
'defaults' => array(
'module' => 'auth',
'controller' => 'themes',
'action' => 'themes',
),
),
'child_routes' => array(
'default' => array(
'type' => 'Segment',
'options' => array(
'route' => '/[:id]',
'constraints' => array(
'id' => '[a-zA-Z0-9_-]*',
),
'defaults' => array(
),
),
),
),
Solution 2 : Custom route
http://www.zendexperts.com/2012/12/09/custom-routing-in-zend-framework-2/
in module.config.php
'routeTestCustom' => array(
'type' => 'pageRoute',
),
in Module.php
use [modulename]\Route\PageRoute;
....
public function getRouteConfig()
{
return array(
'factories' => array(
'pageRoute' => function ($routePluginManager) {
$locator = $routePluginManager->getServiceLocator();
$params = array('defaults' => array('module' => 'auth' ));
$route = PageRoute::factory($params);
$route->setServiceManager($locator);
return $route;
},
),
);
}
your custom route class in [module_name]\src[module_name]\Route\PageRoute.php
namespace [module_name]\Route;
use Zend\Mvc\Router\Http\RouteInterface;
use Zend\ServiceManager\ServiceManagerAwareInterface;
use Zend\ServiceManager\ServiceManager;
use Zend\Stdlib\RequestInterface as Request;
use Zend\Mvc\Router\Http\RouteMatch;
class PageRoute implements RouteInterface
{
protected $defaults;
public function __construct(array $defaults = array())
{
$this->defaults = $defaults;
}
public static function factory($options = array())
{
if ($options instanceof Traversable) {
$options = ArrayUtils::iteratorToArray($options);
} elseif (!is_array($options)) {
throw new Exception\InvalidArgumentException(__METHOD__ . ' expects an array or Traversable set of options');
}
if (!isset($options['defaults'])) {
$options['defaults'] = array();
}
return new static($options['defaults']);
}
public function match(Request $request)
{
$uri = $request->getUri();
$path = $uri->getPath();
$part = explode('/',$uri);
if(count($part) == 4 && $part[0] == 'http:' && $part[2] == "www.example.com"){
$params = $this->defaults;
$params['controller'] = $part[3];
$params['action']= $part[3];
}
return new RouteMatch($params);
}
public function assemble(array $params = array(), array $options = array()){
return $this->route;
}
public function getAssembledParams()
{
return array();
}
}
Updated
Related
So I'm trying to redirect my code to another action within a controller http://localhost/salesorder/view?id=5509c273f948e7cf068b456a this view action is working fine. But every time the redirect code runs it redirects me to http://localhost/salesorder?id=5509c273f948e7cf068b456a
I am now clueless what is did I do wrong.
$params = ['controller' => 'SalesOrder',
'action' => 'view',
];
$options = ['query' => ['id' => (string) $orderId]];
return $this->redirect()->toRoute('Salesorder', $params, $options);
My moduleconfig looks like this
'Salesorder' => array(
'type' => 'Literal',
'options' => array(
'route' => '/salesorder',
'defaults' => array(
'__NAMESPACE__' => 'Backend\Controller',
'controller' => 'SalesOrder',
'action' => 'new',
),
),
'may_terminate' => true,
'child_routes' => array(
'default' => array(
'type' => 'Segment',
'options' => array(
'route' => '[/:action]',
'constraints' => array(
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
),
'defaults' => array(
'action' => 'new'
),
),
),
),
),
Excuse me that I cannot put a comment since I have not enough reputation, but this may lead you to a solution:
First of all fix the toroute function call to this:
return $this->redirect()->toRoute('Salesorder', array('id'=> (string) $orderId));
Then fix the route specification to this:
'Salesorder' => array(
'type' => 'segment',
'options' => array(
'route' => '/MODULE_NAME/SalesOrder/new/:id[/]',
'constraints' => array(
'id' => '[a-zA-Z0-9_-]*'
),
'defaults' => array(
'controller' => 'MODULE\Controller\SalesOrder',
'action' => 'new',
),
),
),
I don't know how can I explain my problem. I'm trying to get JSON response from one of my module that extend abstractrestfulcontroler. I have following module configuration
File: module.config.php
return array(
'controllers' => array(
'invokables' => array(
'TfwCommunication\\Controller\\TfwCommunication' => 'TfwCommunication\\Controller\\TfwCommunicationController',
'TfwCommunication\\Controller\\TfwChat' => 'TfwCommunication\\Controller\\TfwChatController',
'TfwCommunication\\Controller\\TfwContacts' => 'TfwCommunication\\Controller\\TfwContactsController',
'TfwCommunication\\Controller\\TfwMessage' => 'TfwCommunication\\Controller\\TfwMessageController',
'TfwCommunication\\Controller\\TfwUserMessageTemplates' => 'TfwCommunication\\Controller\\TfwUserMessageTemplatesController',
'TfwCommunicationControllerTfwUserMessageTemplates' => 'TfwCommunication\\Controller\\TfwUserMessageTemplatesController',
),
),
'router' => array(
'routes' => array(
'communication' => array(
'type' => 'Segment',
'options' => array(
'route' => '/communication',
'constraints' => array(
#'id' => '[0-9]+', # '[a-zA-Z][a-zA-Z0-9_-]*',
#'action'=>'[a-z][a-z0-9]*',
),
'defaults' => array(
'controller' => 'TfwCommunication\\Controller\\TfwCommunication',
'action' => 'index',
#'id'=>'update',
#'action' => 'index',
),
),
'may_terminate' => true,
'child_routes' => array(
'actions'=>array(
'type' => 'Segment',
'options' => array(
'route' => '/[:action[/]]',
'constraints' => array(
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
),
'defaults' => array(
'controller' => 'TfwCommunication\\Controller\\TfwCommunication',
'action' => 'index',
),
),
),
'message' => array(
'type' => 'Segment',
'options' => array(
'route' => '/message',
'defaults' => array(
'controller' => 'TfwCommunication\\Controller\\TfwMessage',
'action' => 'index',
),
),
'may_terminate' => true,
'child_routes' => array(
'read'=>array(
'type' => 'Segment',
'options' => array(
'route' => '/[:id]',
'constraints' => array(
'id' => '[0-9]*',
),
'defaults' => array(
'controller' => 'TfwCommunication\\Controller\\TfwMessage',
'action' => 'read',
),
),
),
'actions'=>array(
'type' => 'Segment',
'options' => array(
'route' => '/[:action[/[:id]]]',
'constraints' => array(
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
'id' => '.*',
),
'defaults' => array(
'controller' => 'TfwCommunication\\Controller\\TfwMessage',
'action' => 'index',
),
),
),
'json-request-by-child-route'=>array(
'type' => 'Segment',
'options' => array(
'route' => '/json-request-by-child-route[/:id]',
'constraints' => array(
'id' => '.*',
),
'defaults' => array(
'controller' => 'TfwCommunicationControllerTfwUserMessageTemplates',
),
),
),
),
),
),
),
'user-defined-templates'=>array(
'type' => 'Segment',
'options' => array(
'route' => '/communication/message/user-defined-templates[/:id]',
'constraints' => array(
'id' => '.*',
),
'defaults' => array(
'controller' => 'TfwCommunication\\Controller\\TfwUserMessageTemplates',
),
),
),
'user-defined-templates-direct-link'=>array(
'type' => 'Segment',
'options' => array(
'route' => '/user-defined-templates-direct-link[/:id]',
'constraints' => array(
'id' => '.*',
),
'defaults' => array(
'controller' => 'TfwCommunication\\Controller\\TfwUserMessageTemplates',
),
),
),
),
),
'view_manager' => array(
'template_path_stack' => array(
'tfwcommunication' => __DIR__ . DS.'..'.DS.'view',
),
'strategies' => array(
'ViewJsonStrategy',
),
),
);
Now following link is working - tfw.com.bd/communication/message/user-defined-templates/ OR tfw.com.bd/user-defined-templates-direct-link/
But following link will not work as expected (it says 404 controller not found) - tfw.com.bd/communication/message/json-request-by-child-route
Here tfw.com.bd indicating localhost.
Please note, I'm expected output as JSON format.
Also noted that, all I use here same controller. In some link/route it didn't work. I can't figure out the reason.
Can any ZF2 expert here who can explain the real reason behind the behavior.
Thanks
Finally I got this answer by myself. The above routing configuration didn't works due to default "action" define as "index". Zend seek "action" parameter, if found then it load that action. If not found it return "notFoundAction". So, in child route of above router defines "action" parameter. So, Zend din't go further when either it goes default "indexAction" or goes "notFoundAction".
Footnote, you need to avoid action parameter to get "JsonStrategy" works as expected. If you can't avoid action parameter in your router you can fix it by overloading "onDispatch" method of "AbstractRestfulController" controller.
Here is my code that works for me -
public function onDispatch(MvcEvent $e){
$routeMatch = $e->getRouteMatch();
if (! $routeMatch) {
/**
* #todo Determine requirements for when route match is missing.
* Potentially allow pulling directly from request metadata?
*/
throw new Exception\DomainException(
'Missing route matches; unsure how to retrieve action');
}
$request = $e->getRequest();
// Was an "action" requested?
#die('get_class($routeMatch): '.get_class($routeMatch).' #'.__LINE__.': '.__FILE__);
$action = $routeMatch->getParam('action', false);
if ($action) {
// Handle arbitrary methods, ending in Action
$method = static::getMethodFromAction($action);
if (! method_exists($this, $method)) {
if($method=='indexAction'){
$routeMatch->setParam('action', false);
return parent::onDispatch($e);
}
$method = 'notFoundAction';
}
$return = $this->$method();
$e->setResult($return);
return $return;
}
return parent::onDispatch($e);
}
I used authentication in zend module but when i render it gives me error like
Zend\View\Renderer\PhpRenderer::render: Unable to render template "calendar/index/login"; resolver could not resolve to a files
here is my module.config.php:
<?php
return array(
'controllers' => array(
'invokables' => array(
'Calendar\Controller\Index' => 'Calendar\Controller\IndexController',
'Calendar\Controller\User' => 'Calendar\Controller\UserController',
'Calendar\Controller\Calendar' => 'Calendar\Controller\CalendarController',
'Calendar\Controller\Event' => 'Calendar\Controller\EventController'
),
),
'router' => array(
'routes' => array(
/*###############*/
//index
'admin_index' => array(
'type'=>'segment',
'options' => array(
'route'=>'/calendar/admin[/]',
'defaults'=>array('controller'=>'Calendar\Controller\Index','action'=>'index')
)
),
//login
'admin_login' => array(
'type'=>'literal',
'options' => array(
'route'=>'/calendar/admin/login',
'defaults'=>array('controller'=>'Calendar\Controller\Index','action'=>'login')
)
),
//logout
'admin_logout' => array(
'type'=>'literal',
'options' => array(
'route'=>'/calendar/admin/logout',
'defaults'=>array('controller'=>'Calendar\Controller\Index','action'=>'logout')
)
),
//user index
'admin_user' => array(
'type'=>'segment',
'options' => array(
'route'=>'/calendar/admin/user[/]',
'defaults'=>array('controller'=>'Calendar\Controller\User','action'=>'index')
)
),
//user add
'admin_user_add' => array(
'type'=>'segment',
'options' => array(
'route'=>'/calendar/admin/user/add[/]',
'defaults'=>array('controller'=>'Calendar\Controller\User','action'=>'add')
)
),
//user edit
'admin_user_edit' => array(
'type'=>'segment',
'options' => array(
'route' =>'/calendar/admin/user/edit[/:id]',
'constraints' => array(
'action' => 'edit',
'id' => '[a-zA-Z0-9_-]+',
),
'defaults'=>array('controller'=>'Calendar\Controller\User','action'=>'edit')
)
),
//user profile
'admin_profile' => array(
'type'=>'segment',
'options' => array(
'route'=>'/calendar/admin/profile[/]',
'defaults'=>array('controller'=>'Calendar\Controller\Index','action'=>'profile')
)
),
'calendar' => array(
'type' => 'segment',
'options' => array(
'route' => '/calendar[/:action][/:id]',
'constraints' => array(
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
'id' => '[0-9]+',
),
'defaults' => array(
'controller' => 'Calendar\Controller\Calendar',
'action' => 'index',
),
),
),
'event' => array(
'type' => 'segment',
'options' => array(
'route' => '/event[/:action][/:id][/:unixTime][/:allDay]',
'constraints' => array(
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
'id' => '[0-9]+',
'unixTime' => '[0-9]+',
'allDay' => '0|1',
),
'defaults' => array(
'controller' => 'Calendar\Controller\Event',
'action' => 'index',
),
),
),
),
),
'view_manager' => array(
'template_path_stack' => array(
'calendar' => __DIR__ . '/../view',
),
),
);
and here is my controller action:
public function loginAction(){
//$this->layout('layout/login-layout.phtml');
$login_error=false;
$loginForm = new LoginForm();
if ($this->request->isPost())
{
$loginForm->setData($this->request->getPost());
if ($loginForm->isValid())
{
//die("dgdgdgdgdgdgdgdg");
$data = $loginForm->getData();
$authService = $this->getServiceLocator()
->get('doctrine.authenticationservice.odm_default');
$adapter = $authService->getAdapter();
$adapter->setIdentityValue($data['username']);
$adapter->setCredentialValue(md5($data['password']));
$authResult = $authService->authenticate();
//for disable authentication comment here////////////////////////////
if ($authResult->isValid()) {
$identity = $authResult->getIdentity();
//$authService->getStorage()->write($identity);
$this->redirect()->toRoute('admin_index');
}
else {
$identity =false;
$login_error= true;
}
//for disable authentication comment here////////////////////////////
}
}
//
return new ViewModel(array(
'loginForm' => $loginForm,
'login_error' => $login_error,
));
}
That error occurs when you forgot to make the actual for your view. You need to create that template and place it in the appropriate view directory. Then this error should go away.
I'm trying to do some routing in Zend Framework 2, but it's not working.
The basics of the skeleton application are working, so I added a new module called User and the following code in the file \module\User\config\module.config.php
'controllers' => array(
'invokables' => array(
'User\Controller\User' => 'User\Controller\UserController',
),
),
'router' => array(
'routes' => array(
'login' => array(
'type' => 'Literal',
'options' => array(
'route' => '/login',
'defaults' => array(
'__NAMESPACE__' => 'User\Controller',
'controller' => 'User',
'action' => 'login',
),
),
),
'user_create' => array(
'type' => 'Literal',
'options' => array(
'route' => '/user/create',
'defaults' => array(
'__NAMESPACE__' => 'User\Controller',
'controller' => 'User',
'action' => 'create',
),
),
),
),
),
If I try to access the first route (/login), it works.
But the second route (/user/create) results in the error:
File:
F:\www\ZendVendas\library\Zend\Mvc\Router\Http\TreeRouteStack.php:313
Message:
Route with name "create" not found
If I do create a route without the controller name, it works:
'create' => array(
'type' => 'Literal',
'options' => array(
'route' => '/create',
'defaults' => array(
'__NAMESPACE__' => 'User\Controller',
'controller' => 'User',
'action' => 'create',
),
),
),
But I would want the route were "/user/create", and don't "/create".
I have searched for many topics, but can't see where is my mistake.
Appreciate any help ;)
Edit: ajusted code with suggestions of #Jurian
'router' => array(
'routes' => array(
'user' => array(
'type' => 'Literal',
'options' => array(
'route' => '/user',
'defaults' => array(
'controller' => 'User\Controller\User',
'action' => 'profile',
),
),
'child_routes' => array(
'login' => array(
'type' => 'Literal',
'options' => array(
'route' => '/login',
'defaults' => array(
'controller' => 'User\Controller\User',
'action' => 'login',
),
),
),
'create' => array(
'type' => 'Literal',
'options' => array(
'route' => '/create',
'defaults' => array(
'controller' => 'User\Controller\User',
'action' => 'create',
),
),
),
),
),
),
),
You have to understand how routing works in Zend Framework 2. Routes have a name and some configuration. The structure looks as follows:
'router' => array(
'routes' => array(
'route_name_1' => array( /* config here */ ),
'route_name_2' => array( /* config here */ ),
'route_name_3' => array( /* config here */ ),
),
),
Here the route names are route_name_1 etc. If you assemble an url, you use that route name. So if route_name_1 has the url /foo/bar/baz, you can ask for the url of route_name_1 by using the url view helper:
echo $this->url('route_name_1'); // prints /foo/bar/baz
Your url /user/create is mapped to the route name user_create so to assemble this url, you need to pass on the route name:
echo $this->url('user_create'); // prints /user/create
CHILD ROUTES
There is also a concept of child routes. This can give you a route user which maps to /user and then this user route has a child create which maps to /create and as such the "total" route of create is /user/create. This can be configured as follows:
'router' => array(
'routes' => array(
'route_name_1' => array( /* config here */ ),
'route_name_2' => array(
/* config here */
'child_routes' => array(
'child_name_1' => array( /* config here */ ),
'child_name_2' => array( /* config here */ ),
),
),
),
),
Now, if you want to assemble an url for route_name_2 it just looks as above:
echo $this->url('route_name_1');
But if you need to assemble the url for child_name_1 you construct a "path" with a / between the name and its parent(s):
echo $this->url('route_name_1/child_name_1');
So although you can access the /user/create route fine with the route name you already have, you might want to use child routes as this gives you a more flexible routing system:
'router' => array(
'routes' => array(
'user' => array(
'type' => 'Literal',
'options' => array(
'route' => '/user/create',
'defaults' => array(
'controller' => 'User\Controller\User',
'action' => 'profile',
),
),
),
'child_routes' => array(
'login' => array(
'type' => 'Literal',
'options' => array(
'route' => '/login',
'defaults' => array(
'action' => 'login',
),
),
),
'create' => array(
'type' => 'Literal',
'options' => array(
'route' => '/create',
'defaults' => array(
'action' => 'create',
),
),
),
),
),
),
),
Then you have a route user which maps to a "profile". If you assemble user/create you go to /user/create and it uses the "createAction" from the user controller. The same hapens with user/login route.
I have found what I was doing wrong.
In one of my view files, there was a URL function pointing to the route /create.
It would be much helpful if Zend indicated the file with the invalid route, but, once I found the mistake, everything is working now.
'router' => array(
'routes' => array(
'login' => array(
'type' => 'Literal',
'options' => array(
'route' => '/login',
'defaults' => array(
'controller' => 'User\Controller\User',
'action' => 'login',
),
),
),
'logout' => array(
'type' => 'Literal',
'options' => array(
'route' => '/logout',
'defaults' => array(
'controller' => 'User\Controller\User',
'action' => 'logout',
),
),
),
'user' => array(
'type' => 'Literal',
'options' => array(
'route' => '/user',
'defaults' => array(
'controller' => 'User\Controller\User',
'action' => 'profile',
),
),
'child_routes' => array(
'create' => array(
'type' => 'Literal',
'options' => array(
'route' => '/create',
'defaults' => array(
'controller' => 'User\Controller\User',
'action' => 'create',
),
),
),
'edit' => array(
'type' => 'Literal',
'options' => array(
'route' => '/edit',
'defaults' => array(
'controller' => 'User\Controller\User',
'action' => 'edit',
),
),
),
),
),
),
),
Thank you for the help!
I am having problem while implementing Multiple routes as defined Below in my snippet
EDIT: i am getting this exception too
Additional information:
Zend\Mvc\Exception\InvalidControllerException
with Message
Controller of type Account\Controller\VoucherController is invalid; must implement Zend\Stdlib\DispatchableInterface
<?php
namespace Account;
return array(
'controllers' => array(
'invokables' => array(
'Account\Controller\Account' => 'Account\Controller\AccountController',
'Account\Controller\Voucher' => 'Account\Controller\VoucherController',
),
// --------- Doctrine Settings For the Module
'doctrine' => array(
'driver' => array(
'account_entities' => array(
'class' => 'Doctrine\ORM\Mapping\Driver\AnnotationDriver',
'cache' => 'array',
'paths' => array(__DIR__ . '/../src/Account/Entity')
),
'orm_default' => array(
'drivers' => array(
'Account\Entity' => 'account_entities'
)
)
)
),
// The following section is new and should be added to your file
'router' => array(
'routes' => array(
'account' => array(
'type' => 'segment',
'options' => array(
'route' => '/account[/][:action][/:id]',
'constraints' => array(
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
'id' => '[0-9]+',
),
'defaults' => array(
'controller' => 'Account\Controller\Account',
'action' => 'index',
),
),
),
'voucher' => array(
'type' => 'segment',
'options' => array(
'route' => '/account/voucher[/][:action][/:id]',
'constraints' => array(
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
'id' => '[0-9]+',
),
'defaults' => array(
'controller' => 'Account\Controller\Voucher',
'action' => 'index',
),
),
),
),
),
'view_manager' => array(
'template_path_stack' => array(
'account' => __DIR__ . '/../view',
),
),
),
);
Now the issue is i am getting a 404, when i try to access MyHost/account/Voucher
P.S: I already have A Controller under Account/Controller/Voucher and a view under Account/View/Voucher named as index.phtml now i dont know what am i missing here.
As Adnrew and Timdev comments above that there is something not right in your controller, you can check few basic things in your controller, that you have following code correct. specially the typos.
namespace Account\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
class VoucherController extends AbstractActionController {
// you acctions
}