Zend_Navigation incompatible with Zend_Router when writing controller/actions? - php

Novice Zend Framework developer here trying to figure out a simple solution to a Zend Routing problem. I'm sure one of you pros can lend a hand.
I have a website (built in Zend Framework using Zend_Navigation) that contains 75% static HTML page content and a few controllers. Top level navigation is built in Zend_Navigation, looping through partials.
Because of my work I build a lot of sites along these lines (containing lots of static pages) so I want to get this right. I don't want to set up controllers and actions for each and every one of these static pages (there are many) and I wanted to create a solution where I used Zend_Controller_Router_Route to route all static content automatically through to a StaticController whose job it would be to include or render .phtml pages based on a controller/action pairing in the URL from some sort of directory like /layouts/staticpages
Because of SEO and various reasons I don't want to have the controller pairing in the URL for these static pages be visible as /static/page/page1... It has to be "real world descriptions" of the /section/page (eg. advantages/someadvantage )
Here is the problem: Using Zend_Controller_Router_Route can do the job when I set up the correct routes BUT it messes something awful with Zend Navigation... I assume because Zend_Navigaion doesn't play nice with on-the-fly controller/action switching.
Code example:
$router = Zend_Controller_Front::getInstance()->getRouter();
$route = new Zend_Controller_Router_Route('advantages/:page/*',
array('controller' => 'static', 'action' => 'display', 'mode' => 'advantages',
'page' => 'index'));
$router->addRoute('advantages', $route);
This handles the job of switching pages in the "advantages" section well enough, but Zend_Navigation's automatic controller/action writing AND the highlighting of "active" nodes ends up being all screwed up because it now thinks that its controller is "static" and action is "display".
Is Zend_Navigation fundamentally incompatible with Zend_Controller_Router_Route? Is there a better way of doing this single static page controller or handling static content across the board?

Since you are using one controller/action for all static pages, you must customize your Zend Navigation before displaying it.
Check Example 4 in the Zend Documentation.
// the following route is added to the ZF router
Zend_Controller_Front::getInstance()->getRouter()->addRoute(
'article_view', // route name
new Zend_Controller_Router_Route(
'a/:id',
array(
'module' => 'news',
'controller' => 'article',
'action' => 'view',
'id' => null
)
)
);
// a page is created with a 'route' option
$page = new Zend_Navigation_Page_Mvc(array(
'label' => 'A news article',
'route' => 'article_view',
'module' => 'news', // required for isActive(), see note above
'controller' => 'article', // required for isActive(), see note above
'action' => 'view', // required for isActive(), see note above
'params' => array('id' => 42)
));
// returns: /a/42
$page->getHref();

Related

Is it possible to dynamically change view name or create a view that does not exist yet in phalcon?

I would like to know how can i do this in phalcon. I have a web site build with phalcon. All is working great now i stumbled upon a problem, here is what i need.
When a user clicks on a post that was created by another user. It takes him to this post with pictures and all things he entered to DB. I would like that in browser the name of this view is not like www.website.com/posts/index but that it is like www.website.com/posts/Nameofthepost, and like that for each other postings on the website. So that all posts (really ads) show their name up in browser. I hope i wrote everything understandable.
Appreciate all suggestions
That has to do with routing doesn't it? I modified this from my own code, I used grouping, you don't have to. I didn't test this code.
// routes.php
$router = new \Phalcon\Mvc\Router();
$router->setDefaultModule("__YOUR_MODULE__");
$router->removeExtraSlashes(true);
... your other routes ...
// posts group
$posts = new \Phalcon\Mvc\Router\Group(array(
'module' => '__YOUR_MODULE__',
'controller' => 'posts',
'action' => 'index'
));
// All the routes start with /post
$posts->setPrefix('/post');
$posts->add('/{postName}/:params', array(
'action' => 'index',
'params' => 2
));
// Maybe this will be enough for your needs,
// the one above has a catch all params, which
// has to be manually parsed
$posts->add('/{postName}', array(
'action' => 'index',
));
$posts->add('[/]*', array(
'action' => 'index',
));
$router->mount($posts);
unset($posts);
... other routes ...
return $router;
On your controller, you can get the postName param this way:
$this->dispatcher->getParam('permaPath');
As shown in the phalcon routing documentation, you can use regex in your routing config, something like this?
$posts->add('/{postName:[-0-6_A-Za-z]+}/:params', array(
'action' => 'index',
'params' => 2
));
So, only -_, 0-9, A-Z, a-z allowed for postName. If the URL had a comma in there or something, then route doesn't match, 404 page not found.

Can't manage to create a static page with Zend Framework 2

I'm trying to make a website using the Zend Framework 2, but I have a simple problem driving me crazy.
I'd like to make a simple about-us.html page with static content because there is no need to do anything else than display html.
There is no need to create a Controller / model etc...
Maybe you have to question why you're using ZF in the first place. If you just want to create a static internet page, do that without a PHP framework!
If you didn't ask your question well and you're actually just adding a static page to an existing ZF application, why not just using the existing IndexController, add an empty action and add your static content to the corresponding .phtml?
Alternatively you can look at PhlySimplePage, a ZF2 module for the purpose of adding simple static pages to a ZF app. It's written by Matthew Weier O'Phinney, the lead dev of ZF.
As the readme says, this module eliminates the need to create a controller and an action. So all you need to do is create a route and a view script.
I know this question might be old, but I was in trouble with that as well.
Here is what I did to create a generic router for my application, so I could just add as many actions as I need and have then created as phtml files in my view
on module.config.php
'application' => array(
'type' => 'Segment',
'options' => array(
'route' => '/[:action][/]',
'constraints' => array(
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
),
'defaults' => array(
'controller' => 'Application\Controller\Index',
'action' => 'index',
),
),
),
So basically what it does is gets any action you might have in your application and use as a page... like any other controller
Instead of http://yoursite.com/application/test
you can do now http://yoursite.com/test
if you have your testAction set in your indexController file.
Hope I had helped future people looking for this information.
You have to create controller and view file.
suppose there is a about us menu with link
<a href="<?php $this->url('aboutus'array('action'=>'aboutus'));?>">
About Us
</a>
Just go to aboutus view file and write static html code.
Thanks
Alok

Zend router, omit controller in URL for single module

I have a module based Zend application.
One of my modules, called portfolio has only one controller, called index. For this single module, I'd like my route to look like this:
$route = new Zend_Controller_Router_Route('portfolio/:action',
array(
'module' => 'portfolio',
'controller' => 'index',
'action' => 'index'
)
);
This works but messes up all links generated through Zend_Navigation.
Can this routing behavior be achieved, without messing up Zend_Navigation? (i.e. only inbound links are routed through this route. Outbound links are generated with the default route)
I can't use mod_rewrite.

Zend Framework - Optional Router Labels

Very likely I'm going about this in the wrong way entirely. I'm completely new to the framework..
The site I am developing has two "parts" that are mainly separate. An informational/community half, and a commerce half. I'm using the following directory structure:
--application
----default
------controllers
------layouts
------models
------views
----store
------controllers
------layouts
------models
------views
--config
--library
--public
I would like to have a URL structure when browsing for products as follows:
/view/category/model/revision
This would pull up a specific product/revision - but I would like to back-track as well (browsing all revisions, all models, etc). I can't figure out how to achieve this.. My route is setup like this:
Bootstrap.php
$front = Zend_Controller_Front::getInstance();
$router = $front->getRouter();
$route = new Zend_Controller_Router_Route(
'view/:cid/:sku/:rev',
array('module' => 'store', 'controller' => 'index', 'action' => 'index')
);
$router->addRoute('view', $route);
This works fine for pulling up a specific product, but throws an exception (it reverts to the default module and complains that the controller 'view' does not exist) when leaving out any of the 3 labeled parameters. Is it possible to put in optional labels, where it would continue to use the view controller under the store module for 1-3 parameters? Am I missing the point?
I found nothing in the framework docs, but I wouldn't be surprised if I just couldn't find the page.. There's something about the Zend Framework documentation that drives me crazy.
Thank You
I'm not really a ZendFramework guy, but it's obvious the missing parameters are causing the issue. Routes are matched in reverse order. Could it be passing a NULL value to the view when 3 parameters are passed and it is expecting 4?
What if you tried something like:
$route = new Zend_Controller_Router_Route(
'view/:cid/:sku/:rev',
array('module' => 'store', 'controller' => 'index', 'action' => 'index', 'cid' => 0, 'sku' => 0, 'rev' => 0)
);
It should pass default values if they are not provided.

PHP Application URL Routing

So I'm writing a framework on which I want to base a few apps that I'm working on (the framework is there so I have an environment to work with, and a system that will let me, for example, use a single sign-on)
I want to make this framework, and the apps it has use a Resource Oriented Architecture.
Now, I want to create a URL routing class that is expandable by APP writers (and possibly also by CMS App users, but that's WAYYYY ahead in the future) and I'm trying to figure out the best way to do it by looking at how other apps do it.
I prefer to use reg ex over making my own format since it is common knowledge. I wrote a small class that I use which allows me to nest these reg ex routing tables. I use to use something similar that was implemented by inheritance but it didn't need inheritance so I rewrote it.
I do a reg ex on a key and map to my own control string. Take the below example. I visit /api/related/joe and my router class creates a new object ApiController and calls it's method relatedDocuments(array('tags' => 'joe'));
// the 12 strips the subdirectory my app is running in
$index = urldecode(substr($_SERVER["REQUEST_URI"], 12));
Route::process($index, array(
"#^api/related/(.*)$#Di" => "ApiController/relatedDocuments/tags",
"#^thread/(.*)/post$#Di" => "ThreadController/post/title",
"#^thread/(.*)/reply$#Di" => "ThreadController/reply/title",
"#^thread/(.*)$#Di" => "ThreadController/thread/title",
"#^ajax/tag/(.*)/(.*)$#Di" => "TagController/add/id/tags",
"#^ajax/reply/(.*)/post$#Di"=> "ThreadController/ajaxPost/id",
"#^ajax/reply/(.*)$#Di" => "ArticleController/newReply/id",
"#^ajax/toggle/(.*)$#Di" => "ApiController/toggle/toggle",
"#^$#Di" => "HomeController",
));
In order to keep errors down and simplicity up you can subdivide your table. This way you can put the routing table into the class that it controls. Taking the above example you can combine the three thread calls into a single one.
Route::process($index, array(
"#^api/related/(.*)$#Di" => "ApiController/relatedDocuments/tags",
"#^thread/(.*)$#Di" => "ThreadController/route/uri",
"#^ajax/tag/(.*)/(.*)$#Di" => "TagController/add/id/tags",
"#^ajax/reply/(.*)/post$#Di"=> "ThreadController/ajaxPost/id",
"#^ajax/reply/(.*)$#Di" => "ArticleController/newReply/id",
"#^ajax/toggle/(.*)$#Di" => "ApiController/toggle/toggle",
"#^$#Di" => "HomeController",
));
Then you define ThreadController::route to be like this.
function route($args) {
Route::process($args['uri'], array(
"#^(.*)/post$#Di" => "ThreadController/post/title",
"#^(.*)/reply$#Di" => "ThreadController/reply/title",
"#^(.*)$#Di" => "ThreadController/thread/title",
));
}
Also you can define whatever defaults you want for your routing string on the right. Just don't forget to document them or you will confuse people. I'm currently calling index if you don't include a function name on the right. Here is my current code. You may want to change it to handle errors how you like and or default actions.
Yet another framework? -- anyway...
The trick is with routing is to pass it all over to your routing controller.
You'd probably want to use something similar to what I've documented here:
http://www.hm2k.com/posts/friendly-urls
The second solution allows you to use URLs similar to Zend Framework.
Use a list of Regexs to match which object I should be using
For example
^/users/[\w-]+/bookmarks/(.+)/$
^/users/[\w-]+/bookmarks/$
^/users/[\w-]+/$
Pros: Nice and simple, lets me define routes directly
Cons: Would have to be ordered, not making it easy to add new things in (very error prone)
This is, afaik, how Django does it
I think a lot of frameworks use a combination of Apache's mod_rewrite and a front controller. With mod_rewrite, you can turn a URL like this: /people/get/3 into this:
index.php?controller=people&method=get&id=3. Index.php would implement your front controller which routes the page request based on the parameters given.
As you might expect, there are a lot of ways to do it.
For example, in Slim Framework , an example of the routing engine may be the folllowing (based on the pattern ${OBJECT}->${REQUEST METHOD}(${PATTERM}, ${CALLBACK}) ):
$app->get("/Home", function() {
print('Welcome to the home page');
}
$app->get('/Profile/:memberName', function($memberName) {
print( 'I\'m viewing ' . $memberName . '\'s profile.' );
}
$app->post('/ContactUs', function() {
print( 'This action will be fired only if a POST request will occure');
}
So, the initialized instance ($app) gets a method per request method (e.g. get, post, put, delete etc.) and gets a route as the first parameter and callback as the second.
The route can get tokens - which is "variable" that will change at runtime based on some data (such as member name, article id, organization location name or whatever - you know, just like in every routing controller).
Personally, I do like this way but I don't think it will be flexible enough for an advanced framework.
Since I'm working currently with ZF and Yii, I do have an example of a router I've created as part of a framework to a company I'm working for:
The route engine is based on regex (similar to #gradbot's one) but got a two-way conversation, so if a client of yours can't run mod_rewrite (in Apache) or add rewrite rules on his or her server, he or she can still use the traditional URLs with query string.
The file contains an array, each of it, each item is similar to this example:
$_FURLTEMPLATES['login'] = array(
'i' => array( // Input - how the router parse an incomming path into query string params
'pattern' => '#Members/Login/?#i',
'matches' => array( 'Application' => 'Members', 'Module' => 'Login' ),
),
'o' => array( // Output - how the router parse a query string into a route
'#Application=Members(&|&)Module=Login/?#' => 'Members/Login/'
)
);
You can also use more complex combinations, such as:
$_FURLTEMPLATES['article'] = array(
'i' => array(
'pattern' => '#CMS/Articles/([\d]+)/?#i',
'matches' => array( 'Application' => "CMS",
'Module' => 'Articles',
'Sector' => 'showArticle',
'ArticleID' => '$1' ),
),
'o' => array(
'#Application=CMS(&|&)Module=Articles(&|&)Sector=showArticle(&|&)ArticleID=([\d]+)#' => 'CMS/Articles/$4'
)
);
The bottom line, as I think, is that the possibilities are endless, it just depend on how complex you wish your framework to be and what you wish to do with it.
If it is, for example, just intended to be a web service or simple website wrapper - just go with Slim framework's style of writing - very easy and good-looking code.
However, if you wish to develop complex sites using it, I think regex is the solution.
Good luck! :)
You should check out Pux https://github.com/c9s/Pux
Here is the synopsis
<?php
require 'vendor/autoload.php'; // use PCRE patterns you need Pux\PatternCompiler class.
use Pux\Executor;
class ProductController {
public function listAction() {
return 'product list';
}
public function itemAction($id) {
return "product $id";
}
}
$mux = new Pux\Mux;
$mux->any('/product', ['ProductController','listAction']);
$mux->get('/product/:id', ['ProductController','itemAction'] , [
'require' => [ 'id' => '\d+', ],
'default' => [ 'id' => '1', ]
]);
$mux->post('/product/:id', ['ProductController','updateAction'] , [
'require' => [ 'id' => '\d+', ],
'default' => [ 'id' => '1', ]
]);
$mux->delete('/product/:id', ['ProductController','deleteAction'] , [
'require' => [ 'id' => '\d+', ],
'default' => [ 'id' => '1', ]
]);
$route = $mux->dispatch('/product/1');
Executor::execute($route);
Zend's MVC framework by default uses a structure like
/router/controller/action/key1/value1/key2/value2
where router is the router file (mapped via mod_rewrite, controller is from a controller action handler which is defined by a class that derives from Zend_Controller_Action and action references a method in the controller, named actionAction. The key/value pairs can go in any order and are available to the action method as an associative array.
I've used something similar in the past in my own code, and so far it's worked fairly well.
Try taking look at MVC pattern.
Zend Framework uses it for example, but also CakePHP, CodeIgniter, ...
Me personally don't like the MVC model, but it's most of the time implemented as "View for web" component.
The decision pretty much depends on preference...

Categories