I'm working on zf2 to make one of my routes only accessible when a query string parameter is passed. Otherwise, it will not. I've added a filter on the route section but when accessing the page without the query parameter, it is still going thru.
'router' => array(
'routes' => array(
'show_post' => array(
'type' => 'segment',
'options' => array(
'route' => '[/]show/post/:filter',
'constraints' => array(
'filter' => '[a-zA-Z0-9-.]*',
),
'defaults' => array(
'controller' => 'blog_controller',
'action' => 'show'
)
),
),
),
),
http://example.com/show/post/?postId=1235 = This should work
http://example.com/show/post?postId=1235 = This should work
http://example.com/show/post/ = This should not work
http://example.com/show/post = This should not work
The way you currently have this setup you would have to structure your url like this
http://example.com/show/post/anything?postId=1235
I think what you are wanting is to structure your route like this
'route' => '[/]show/post',
Not sure what you are trying to accomplish with [/] before show though, you are making that dash optional there?
I would write it like this
'route' => '/show/post[/:filter]',
This way you can structure your urls like this
http://example.com/show/post/anything?postId=1235
or
http://example.com/show/post?postId=1235
Then in your action you can access those parameters like this
$filter = $this->params('filter');
$post_id = $this->params()->fromQuery('post_id');
or just
$post_id = $this->params()->fromQuery('post_id');
***************UPDATE***************
It looks like zf2 used to include what you are trying to do and removed it because of security reasons.
http://framework.zend.com/security/advisory/ZF2013-01
Don't try to bend ZF2 standard classes to your way. Instead write your own route class, a decorator to the segment route, which will do exactly as you please:
<?php
namespace YourApp\Mvc\Router\Http;
use Zend\Mvc\Router\Http\Segment;
use use Zend\Mvc\Router\Exception;
use Zend\Stdlib\RequestInterface as Request;
class QueryStringRequired extends Segment
{
public static function factory($options = [])
{
if (!empty($options['string'])) {
throw new Exception\InvalidArgumentException('string parameter missing');
}
$object = parent::factory($options);
$this->options['string'] = $options['string'];
return $object;
}
public function match(Request $request, $pathOffset = null, array $options = [])
{
$match = parent::match($request, $pathOffset, $options);
if (null === $match) {
// no match, bail early
return null;
}
$uri = $request->getUri();
$path = $uri->getPath();
if (strpos($path, $this->options['string']) === null) {
// query string parametr not found in the url
// no match
return null;
}
// no query strings parameters found
// return the match
return $match;
}
}
This solution is very easy to unit test as well, it does not validate any OOP principles and is reusable.
Your new route definition would look like this now:
// route definition
'router' => array(
'routes' => array(
'show_post' => array(
'type' => YourApp\Mvc\Router\Http\QueryStringRequired::class,
'options' => array(
'string' => '?postId=',
'route' => '[/]show/post/:filter',
'constraints' => array(
'filter' => '[a-zA-Z0-9-.]*',
),
'defaults' => array(
'controller' => 'blog_controller',
'action' => 'show'
)
),
),
),
),
Related
Need to achieve dynamic router param segmenting in Zend Router. The idea is:
have the url: /route/:route/resource/:resource/:identifier, with the following configuration:
'orchestration.rest.dynamic-router' => array(
'type' => 'Segment',
'options' => array(
'route' => '/route/:route/resource/:resource[/:identifier]',
'defaults' => array(
'controller' => 'Controller',
),
),
),
Need to make it support n-number different key=>value router params in the following format:
/route/:route/resource/:resource/:identifier/key1/value1/key2/value2/key3/value3
The second problem is that this should work only if you have the optional :identifier parameter provided.
This is what I've checked, but not sure how to achieve the goal:
https://docs.zendframework.com/zend-router/routing/#zend92router92http92segment
Leave static routes.
1) They are cached for better performance
2) if you use rest logic, use POST method, not GET(params in url)
the route
'orchestration.rest' => array(
'type' => 'Segment',
'options' => array(
'routerest' => '/routerest/:action',
'defaults' => array(
'controller' => 'Controller',
),
),
),
use post to consume rest action on server, with Ajax, or other...
(pseudo code)
datas={key1 : param1 , key2 : param2, etc...}
url=yourDomain/routerest/show (show=the action)
send Ajax Request(or something else in another langage with METHOD=POST)
other action like "getdatas"
... use post to consume rest action on server, with Ajax, or other...
datas={id1 : param1 , id2 : param2, etc...}
url=yourDomain/routerest/getdatas (getdatas=the action)
... in your Controller.php
...handle show action in route
function showAction() {
$request = $this->getRequest();
if ($request->isPost()) {
$param1=$this->params()->fromPost('key1','defaultvalue');
$param2=$this->params()->fromPost('key2','defaultvalue');
...
...
} else {... ERROR..}
}
...handle getdatas action in route
function getdatasAction() {
$request = $this->getRequest();
if ($request->isPost()) {
$id1=$this->params()->fromPost('id1','defaultvalue');
$id2=$this->params()->fromPost('id2','defaultvalue');
...
...
if ($id1$=='all') { return $this->redirect()->toRoute ('otherroute', array ('action' => 'xxx', 'paramxxx' => 'xx'));
...
...
} else {... ERROR..}
}
My application uses Zend Framework 2 and I am trying to pass some options to it when ran via command line:
php index.php generate --date="2015-01-01"
However I am getting the error: Invalid arguments or no arguments provided
My controller looks like:
namespace Application\Controller;
use Zend\Mvc\Controller\AbstractActionController;
class GenerateController extends AbstractActionController
{
public function indexAction()
{
$longopts = array(
'date::',
);
$opts = getopt('', $longopts);
if (isset($opts['date'])) {
$date = $opts['date'];
} else {
$date = date('Y-m-d');
}
var_dump($date);
die();
}
}
I would like the var_dump to show the date provided in the options or today's date. The script runs but just gives the above error. Any help is greatly appreciated.
My module.config.php is functioning correctly:
// Placeholder for console routes
'console' => array(
'router' => array(
'routes' => array(
'get-happen-use' => array(
'options' => array(
//php index.php get happen --verbose apache2
// add [ and ] if optional ( ex : [<doname>] )
'route' => 'generate',
'defaults' => array(
'__NAMESPACE__' => 'Application\Controller',
'controller' => 'generate',
'action' => 'index'
),
),
),
)
)
),
You need to define your console params or flags in route. According documentation, your route definition should looks like
'route' => 'generate [--date=]',
for optional value flag date, or if flag date is mandatory:
'route' => 'generate --date=',
Then you can access value of this flag in controller from request (documentation):
$date = $this->getRequest()->getParam('date', null); // default null
There was a similar thread but it didn't address this exact problem so I thought I would create a new thread to make this clear.
Code/problem explained:
This is my SystemsController.
Here I have viewsystemAction(). This is loaded, and from the view a script is called to load ajaxviewsystemAction().
In the viewsystemAction(), I use the params function to get the "id" parameter from my route. For example systems/viewsystems/222 ( <-- 222 is id. ). I echo this out just to show that it is correct, and it gives the correct id for the page.
The ajaxviewsystemsAction is kind of where the problem is. This is because the route of ajaxviewsystemsAction id is not the same as viewsystemsAction. If I echo the id from the params here, it displays as 0.
Although if i go to this page in the browser for example ajaxviewsystemsAction/222 then it is working perfectly. However, nothing is rendered here except the ajax table, as remember it is called in viewsystemAction from a script.
What i need to do, is somehow pass the id route value from viewsystemAction into ajaxviewsystemAction, to both use this same route id.
This is so when someone clicks on the link, it loads viewsystems/222, the correct id is executed in both viewsystemsAction and ajaxviewsystemsAction.
Is this possible? If not how could i make something similar like this. I am using zftable which integrates ajax. I need to pass this id parameter through into a query.
private function getSourceViewAllSystems($id)
{
return $this->getSystemsTable()->fetchViewAllSystems($id); //paramater to model which executes sql ->where system = $id
}
public function viewsystemAction()
{
$id = (int) $this->params()->fromRoute('id', 0);
echo $id; //i see the correct id for example 220 from the route in the browser
}
public function ajaxviewsystemAction()
{
$id = (int) $this->params()->fromRoute('id', 0);
echo $id; //to see the id of the route with the ajax page
//displays 0 and not the route id from the viewsystemAction
$table = new TableExample\Advance();
$table->setAdapter($this->getDbAdapter())
->setSource($this->getSourceViewAllSystems($id))
->setParamAdapter($this->getRequest()->getPost())
;
return $this->htmlResponse($table->render('custom' , 'custom-b2'));
}
--- update ---
<?php
return array(
'controllers' => array(
'invokables' => array(
'Systems\Controller\Systems' => 'Systems\Controller\SystemsController',
),
),
// The following section is new and should be added to your file
'router' => array(
'routes' => array(
'systems' => array(
'type' => 'segment',
'options' => array(
'route' => '/systems[/][:action][/:id]',
'constraints' => array(
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
'id' => '[0-9]+',
),
'defaults' => array(
'controller' => 'Systems\Controller\Systems',
'action' => 'index',
),
),
),
),
),
'view_manager' => array(
'template_path_stack' => array(
'systems' => __DIR__ . '/../view',
),
),
);
I want to make my url seo friendly. www.example.com/posts/view/1 change for www.example.pl/:slug-:id. Everything works fine, but probably I'm doing something wrong with routing, because when after clicking the urls in paginator, the url is correct, it looks like www.example.pl/:slug-:id , but it appears an error
"The requested address 'www.example.pl/:slug-:id' was not found on this server."
I don't know what's wrong. Here's my code:
Router::connect(
'/:slug-:id',
array(
'controller' => 'posts',
'action' => 'view'
),
array(
'pass' => array('slug' , 'id'),
'id' => '[0-9]+'
)
);
in paginator view:
echo $this->Html->link($ad['Post']['title'], array(
'controller' => 'posts',
'action' => 'view',
'slug' => Inflector::slug($post['Post']['title'],'-'),
'id'=>$post['Post']['id'])
);
I solved the problem.
Its too simple i'll give you an example from my project ..
in your routes.php
Router::connect(
'/:slug-:id',
array('controller'=>'posts','action'=>'view'),
array('pass'=>array('slug','id'),'slug'=>'[a-zA-Z0-9 -]+','id'=>'[0-9]+')
);
your link in views should be like .
$this->Html->link(__('link desu'),array('controller'=>'posts','action'=>'view','id'=>$post['Post']['id'],'slug'=>$post['Post']['slug']));
and your PostsController.php
public function view($slug,$id){
$this->Post->id = $id;
// ....
}
Quick tip : try to create an array in your PostModel to avoid creating it every time in your view .
example :
Post.php
class Post extends AppModel{
// ....
public function afterFind($results,$primary = false){
foreach ($results as $key => $value) {
if(isset($value[$this->alias]['id'])){
$results[$key][$this->alias]['url'] = array(
'controller'=>'posts',
'action'=>'view',
'id'=>$results[$key][$this->alias]['id'],
'slug'=>$results[$key][$this->alias]['slug']
);
}
// ....
}
return $results;
}
}
}
so you can call it in your view simply like that
$this->Html->link(__('link desu'),$post['Post']['url']);
It's probably a problem with the regex on the route. Your slug contain hyphens - which you also use to separate between the slug and the id. i.e.:
example.com/my-slug-has-hyphens-1
The regex is not smart enough to know that the "last" hyphen separates the slug from the id.
To test if this is the problem, try using a route like this '/:slug__:id', just to see if it works.
I solved the problem. In the posts controller my view function was wrong. Here's right correct:
function view($id = null, $slug = null) {
$this->Post->id = $this->params['post'];
$this->set('post', $this->Post->read());
Pass is order sensitive
In the question the route is as follows:
Router::connect(
'/:slug-:id',
array(
'controller' => 'posts',
'action' => 'view'
),
array(
'pass' => array('slug' , 'id'), # <-
'id' => '[0-9]+'
)
);
That means the post function will recieve:
public function view($slug, $id)
As indicated by the edited question, the code is expecting the id to be the first parameter. The easiest solution is simply to specify the passed parameters in the order that they are expected:
...
'pass' => array('id', 'slug'), # <-
Router::connect(
'/:slug/:id',
array(
'controller' => 'posts',
'action' => 'view'
),
array(
'pass' => array('slug' , 'id'),
'id' => '[0-9]+'
)
);
the above code will create correct link as www.example.com/posts/view/title/1
echo $this->Html->link($post['Post']['title'], array('controller' => 'posts', 'action' => 'view', Inflector::slug($post['Post']['title'],'-'),$post['Post']['id']));
I'm having troubles with (german) special characters in URIs and want to try to resolve it with a RegEx Route and a PCRE pattern modifier for UTF-8 u.
'router' => array(
'routes' => array(
// ...
'city' => array(
'type' => 'regex',
'options' => array(
'regex' => '/catalog/(?<city>[a-zA-Z0-9_-äöüÄÖÜß]*)\/u',
'defaults' => array(
'controller' => 'Catalog\Controller\Catalog',
'action' => 'list-sports',
),
'spec' => '/catalog/%city%',
),
'may_terminate' => true,
),
),
),
But when I set it, the route stopps to work at all (error 404) -- neither for URIs with nor to ones without special characters.
How to set the modifier correctly?
Since I already had this open here's a handler that solves the problem.
<?php
namespace Application\Mvc\Router\Http;
use Zend\Mvc\Router\Http\Regex;
use Zend\Mvc\Router\Http\RouteMatch;
use Zend\Stdlib\RequestInterface as Request;
class UnicodeRegex extends Regex
{
/**
* match(): defined by RouteInterface interface.
*
* #param Request $request
* #param integer $pathOffset
* #return RouteMatch
*/
public function match(Request $request, $pathOffset = null)
{
if (!method_exists($request, 'getUri')) {
return null;
}
$uri = $request->getUri();
// path decoded before match
$path = rawurldecode($uri->getPath());
// regex with u modifier
if ($pathOffset !== null) {
$result = preg_match('(\G' . $this->regex . ')u', $path, $matches, null, $pathOffset);
} else {
$result = preg_match('(^' . $this->regex . '$)u', $path, $matches);
}
if (!$result) {
return null;
}
$matchedLength = strlen($matches[0]);
foreach ($matches as $key => $value) {
if (is_numeric($key) || is_int($key) || $value === '') {
unset($matches[$key]);
} else {
$matches[$key] = $value;
}
}
return new RouteMatch(array_merge($this->defaults, $matches), $matchedLength);
}
}
Assuming you place the file in Application/Mvc/Router/Http/UnicodeRegex your route definition should look like this
'router' => array(
'routes' => array(
// ...
'city' => array(
'type' => 'Application\Mvc\Router\Http\UnicodeRegex',
'options' => array(
'regex' => '/catalog/(?<city>[\p{L}]+)',
// or if you prefer, your original regex should work too
// 'regex' => '/catalog/(?<city>[a-zA-Z0-9_-äöüÄÖÜß]*)',
'defaults' => array(
'controller' => 'Catalog\Controller\Catalog',
'action' => 'list-sports',
),
'spec' => '/catalog/%city%',
),
'may_terminate' => true,
),
),
),
Well,
I guess you can solve it as easily as many other ones had this same problem. So take a look at some of them:
UTF-8 in * regular expressions
There uses the following modifiers like \\s, \\p{L}, and \\u to help you. I hope it solves! Good luck.
Edit
See my own test:
<?php
$toss_the_dice = utf8_decode ("etc/catalog/Nürnberg");
preg_match ('/\/catalog\/([\\s\\p{L}]*)/m', $toss_the_dice, $dice);
echo utf8_encode ($dice[1]);
// Now it prints
// Nürnberg
?>
Can you realize?
Edit 2
It can be better for you!
<?php
$toss_the_dice = "etc/catalog/Nürnberg";
preg_match ('/\/catalog\/([\\s\\p{L}]*)/u', $toss_the_dice, $dice);
echo $dice[1];
// Now it also prints
// Nürnberg
?>