I want to make routing for form when submitting the form,
$reportRoute = new Zend_Controller_Router_Route('blogsedit/blog_id/:blog_id', array('module' => 'blogs', 'controller' => 'blog', 'action' => 'edit','blog_id' =>NULL));
$routesArray = array('blogs' => $reportRoute);
$router->addRoutes($routesArray);
and in the form I used to make like this
<form action="/blogs/blog/edit/blog_id/<?php echo $blogId?>"
</form>
How can I make the custom routing of the form action ?
You can use the view helper url().
url($urlOptions, $name, $reset): Creates a URL string based on a named
route. $urlOptions should be an associative array of key/value pairs
used by the particular route.
Generates an url given the name of a route.
#access public
#param array $urlOptions Options passed to the assemble method of the Route object.
#param mixed $name The name of a Route to use. If null it will use the current Route
#param bool $reset Whether or not to reset the route defaults with those provided
#return string Url for the link href attribute.
In your case, you would have something like:
url(array('blog_id' => $blogId), 'blogs', true)
Related
I want to embed a contact form in multiple places on my website.
I developed a contact form in a contact() function within my MessagesController.php:
// MessagesController.php
public function contact()
{
$this->set('title', 'Contact');
$message = $this->Messages->newEntity();
... // shortened for brevity
$this->set(compact('message'));
$this->set('_serialize', ['message']);
}
I loaded the CSRF component in the initialize() function of the AppController.php:
// AppController.php
public function initialize()
{
parent::initialize();
$this->loadComponent('Csrf');
... // shortened for brevity
}
The form is rendered with a contact.ctp and it works fine.
I followed CakePHP's cookbook which suggests using requestAction() within an element, then echoing the element where I want it:
// contact_form.ctp
<?php
echo $this->requestAction(
['controller' => 'Messages', 'action' => 'contact']
);
?>
And:
// home.ctp
<?= $this->element('contact_form'); ?>
The problem is that the form is rendered fine, but the CSRF hidden field is missing. It should be automatically added to the form since the CSRF component is called in the AppController.php.
I guess either using an element with a requestAction() isn't the solution for this particular case, or I am doing something wrong.
Any ideas? Thanks in advance for the input!
Request parameters need to be passed manually
requestAction() uses a new \Cake\Network\Request instance, and it doesn't pass the _Token and _csrf parameters to it, so that's why things break.
While you could pass them yourself via the $extra argument, like
$this->requestAction(
['controller' => 'Messages', 'action' => 'contact'],
[
'_Token' => $this->request->param('_Token'),
'_csrf' => $this->request->param('_csrf')
]
);
Use a cell instead
I would suggest using a cell instead, which is way more lightweight than requesting an action, also it operates in the current request and thus will work with the CSRF component out of the box.
You'd pretty much just need to copy your controller action code (as far as the code is concerned that you are showing), and add a loadModel() call to load the Messages table, something like
src/View/Cell/ContactFormCell.php
namespace App\View\Cell;
use Cake\View\Cell;
class ContactFormCell extends Cell
{
public function display()
{
$this->loadModel('Messages');
$this->set('title', 'Contact');
$message = $this->Messages->newEntity();
// ... shortened for brevity
$this->set(compact('message'));
$this->set('_serialize', ['message']);
}
}
Create the form in the corresponding cell template
src/Template/Cell/ContactForm/display.ctp
<?php
echo $this->Form->create(
/* ... */,
// The URL needs to be set explicitly, as the form is being
// created in the context of the current request
['url' => ['controller' => 'Messages', 'action' => 'contact']]
);
// ...
And then wherever you want to place the form, just use <?= $this->cell('ContactForm') ?>.
See also
API > \Cake\Routing\RequestActionTrait::requestAction()
Cookbook > Views > Cells
The title might be misleading but I'm trying to do something very simple but cant figure it out.
Lets say I have a Question controller and show action and question id is the primary key with which I look up question details - so the URL looks like this
http://www.example.com/question/show/question_id/101
This works fine - So when the view is generated - the URL appears as shown above.
Now in the show action, what I want to do is, append the question title (which i get from database) to the URL - so when the view is generated - the URL shows up as
http://www.example.com/question/show/question_id/101/how-to-make-muffins
Its like on Stack overflow - if you take any question page - say
http://stackoverflow.com/questions/5451200/
and hit enter
The question title gets appended to the url as
http://stackoverflow.com/questions/5451200/make-seo-sensitive-url-avoid-id-zend-framework
Thanks a lot
You will have to add a custom route to your router, unless you can live with an url like:
www.example.com/question/show/question_id/101/{paramName}/how-to-make-muffins
You also, if you want to ensure that this parameter is always showing up, need to check if the parameter is set in the controller and issue a redirect if it is missing.
So, in your bootstrap file:
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
public function _initRoutes ()
{
// Ensure that the FrontController has been bootstrapped:
$this->bootstrap('FrontController');
$fc = $this->getResource('FrontController');
/* #var $router Zend_Controller_Router_Rewrite */
$router = $fc->getRouter();
$router->addRoutes( array (
'question' => new Zend_Controller_Router_Route (
/* :controller and :action are special parameters, and corresponds to
* the controller and action that will be executed.
* We also say that we should have two additional parameters:
* :question_id and :title. Finally, we say that anything else in
* the url should be mapped by the standard {name}/{value}
*/
':controller/:action/:question_id/:title/*',
// This argument provides the default values for the route. We want
// to allow empty titles, so we set the default value to an empty
// string
array (
'controller' => 'question',
'action' => 'show',
'title' => ''
),
// This arguments contains the contraints for the route parameters.
// In this case, we say that question_id must consist of 1 or more
// digits and nothing else.
array (
'question_id' => '\d+'
)
)
));
}
}
Now that you have this route, you can use it in your views like so:
<?php echo $this->url(
array(
'question_id' => $this->question['id'],
'title' => $this->question['title']
),
'question'
);
// Will output something like: /question/show/123/my-question-title
?>
In your controller, you need to ensure that the title-parameter is set, or redirect to itself with the title set if not:
public function showAction ()
{
$question = $this->getQuestion($this->_getParam('question_id'));
if(!$this->_getParam('title', false)) {
$this->_helper->Redirector
->setCode(301) // Tell the client that this resource is permanently
// residing under the full URL
->gotoRouteAndExit(
array(
'question_id' => $question['id'],
'title' => $question['title']
)
);
}
[... Rest of your code ...]
}
This is done using a 301 redirect.
Fetch the question, filter out and/or replace URL-illegal characters, then construct the new URL. Pass it to the Redirector helper (in your controller: $this->_redirect($newURL);)
I have some trouble with the router.
I have a custom route :
$router->addRoute('showTopic',
new Zend_Controller_Router_Route('/forum/topic/:topic',
array('module' => 'forum',
'controller' => 'topic',
'action' => 'show'),
array('topic' => '\d+')));
But when I try to access this url : localhost/forum/topic/16
I get this error :
Fatal error: Uncaught exception 'Zend_Controller_Router_Exception' with message 'topic is not specified'
But I don't want to put a default value for topic, because I also want the route /forum/topic to list all topics...
Secondly, I know that if I add a custom route, the default router is overridden, but I need to have some default routes too. The only way I have found is to set 'default' in the second parameter of the url view helper, like this
$this->url(array(
'module' => 'forum',
'controller' => 'topic',
'action' => 'add'
), 'default', true)
Is there a more elegant way instead of doing this for all url where I want to use the default behavior ?
You should have a default value for a topic and add the more general route (the one for forum/topic) after the more specific one. Route_Rewrite checks the routes beginning with the last one (it actually does an array_inverse).
The url helper delegates assembly urls to a route, its second paremeter being the name of the route to pull from the router. Since the default route is registered under the name of 'default', there is nothing really inelegant in using the name (it is not a magic string or a special case). If this really bugs you, you could write a custom helper (to be placed under "views/helpers"):
class Zend_View_Helper_DefaultUrl extends Zend_View_Helper_Abstract {
public function defaultUrl($params) {
return $this->view->url($params, 'default');
}
}
And use it in your view like defaultUrl(array('action'=>'test')) ?>.
Is there any more or less standard way to specify a route that would create URL's with explicitly specified scheme?
I've tried the solution specified here but it's not excellent for me for several reasons:
It doesn't support base url request property. Actually rewrite router ignores it when URL scheme is specified explicitly.
It's needed to specify separate static route for each scheme-dependent URL (it's not possible to chain module route with hostname route because of base url is ignored).
It's needed to determine HTTP_HOST manually upon router initialization in bootstrap as long as request object is not present within FrontController yet.
Use a combination of the ServerUrl and Url view helpers to construct your URLs, eg (view context)
<?php $this->getHelper('ServerUrl')->setScheme('https') ?>
...
<a href="<?php echo $this->serverUrl($this->url(array(
'url' => 'params'), 'route', $reset, $encode)) ?>">My Link</a>
You can write your own custom View helper for composing an URL. Take a look at the http://www.evilprofessor.co.uk/239-creating-url-in-zend-custom-view-helper/
<?php
class Pro_View_Helper_LinksUrl
extends Zend_View_Helper_Abstract
{
/**
* Returns link category URL
*
* #param string $https
* #param string $module
* #param string $controller
* #param string $action
* #return string Url-FQDN
*/
public function linksUrl($https = false, $module = 'www',
$controller = 'links', $action = 'index')
{
$router = Zend_Controller_Front::getInstance()->getRouter();
$urlParts = $router->assemble(array(
'module' => $module,
'controller' => $controller,
'action' => $action,
), 'www-index');
$FQDN = (($https) ? "https://" : "http://") . $_SERVER["HTTP_HOST"] . $urlParts;
return $FQDN;
}
}
Is it possible to use paginator with $_GET parameters?
For example i have a route like this:
$router->addRoute('ajax_gallery',
new Routes_Categories(
'/:lang/:category/age/:dep/:cat/:towns',
array(
"page" => 1,
"dep" => 0,
"cat" => 0,
"towns" => 0
),
array(
"dep" => "[0-9]+",
"cat" => "[0-9]+"
)
));
And i'm making request like this via ajax:
http://localhost/en/gallery?dep=9&cat=27&towns=1
But links that returned from results are without ?dep=9&cat=27&towns=1
How to force zend paginator to use passed $_GET params inside pagination link generation?
So that returned links were:
http://localhost/en/gallery/2?dep=9&cat=27&towns=1
http://localhost/en/gallery/3?dep=9&cat=27&towns=1
http://localhost/en/gallery/4?dep=9&cat=27&towns=1
etc...
or even
http://localhost/en/gallery/2/9/27/1
http://localhost/en/gallery/3/9/27/1
http://localhost/en/gallery/4/9/27/1
like they are defined inside route
etc...
Thanks
The view URL helper will always output params as part of the URL (separated by forward slashes) and doesn't, to my knowledge, support the GET parameter format.
I don't know what Routes_Categories class does, but working from the default ZF route classes try this:
$route = new Zend_Controller_Router_Route(
'/:lang/:category/:age/:dep/:cat/:towns/*',
array(
"dep" => 0,
"cat" => 0,
"towns" => 0
),
array(
"dep" => "[0-9]+",
"cat" => "[0-9]+"
)
);
$router->addRoute('ajax_gallery', $route);
The * supports any additional named params after your route. The above assumes lang, category and age are required, and dep, cat and towns are optional. Bear in mind if you want to set cat you have to set dep otherwise the route will get confused which variable is what.
In your controller access the page param via the following, which sets a default of 1.
$page = $this->_getParam('page', 1);
Access the URL via AJAX as: http://localhost/en/gallery/2/9/27/1
If you want the page param, use a named parameter: http://localhost/en/gallery/2/9/27/1/page/2
To get this route to work in your pagination you need to update your paginator view controls to use the right route. See: http://framework.zend.com/manual/en/zend.paginator.usage.html#zend.paginator.usage.rendering.example-controls
Look for the code where the URL is outputted and add the route name to the URL view helper. So replace code like this:
<?php echo $this->url(array('page' => $this->previous)); ?>
With:
<?php echo $this->url(array('page' => $this->previous), 'ajax_gallery'); ?>