I was going through the Zend document but I didn't get clear idea how routing is done in Zend framework 1.12.
What I understand from the document is when we hit the URL in the browser then request is going the index.php in public folder.
But I am not getting how Zend framework decomposes the URL and calls the particular controller and action.
Eg.
consider the URL: http://zendtutorial.local/blog/new
How Zend evaluates newAction from BlogController
When We hit the URL First following things happens:
Very first index.php in public directory gets called.
In Index.php the constants like APPLICATION_PATH, APPLICATION_ENV are defined and Application object gets created.
The settings in the application.ini file get initialized.
application.ini contains all the information like the default controller, default modules, database settings, etc.
Then the bootstrap function of Zend_Application gets called.
This function calls the Bootstrap class from bootstrap.php.
Then run() method of Zend_Application_Bootstrap_Bootstrap gets called.
Zend_Application_Bootstrap_Bootstrap :: run() method gets called.
Finally, dispatch() method of Zend_Controller_Front gets called.
dispatch() method routes the requested URL to specific controller and action.
In ZF1 I used to use a ACL plugin to check if a user is trying to access a non-authorized controller via preDispatch method.
I need to do something similar in ZF2. How do I do that?
In ZF2 hooks such as pre/post dispatch has been replaced with Events . The new MVC uses EventManager to fire MVC events such as dispatch .
In your Module.php add
public function onBootstrap(MvcEvent $e)
{
$eventManager = $e->getApplication()->getEventManager();
$eventManager->attach(MvcEvent::EVENT_DISPATCH,function(MvcEvent $event){
//dispach code comes here
});
}
Alternativly you can use prebuilt module for this purpose which also integrates with Zfc-User
https://github.com/bjyoungblood/BjyAuthorize
I extended the Zend Frontcontroller with a personal one and also extended the frontcontroller application resource to use my personal front controller. All it basically does for the moment is assign the front variable within the application resource method getFrontController to my personal front controller. Lastly, I added the pluginpaths variable within application.ini to use my personal Application Resources. In any case, I'm getting the Zend Frontcontroller returned to me instead of my personal one. Anybody know why my personal application frontcontroller resource
isnt being used?
`
Since Zend_Controller_Front is a singleton, you will also need to override the getInstance() method to ensure it creates an instance of your class instead of the base class. You can just cut and paste the method to do this:
public static function getInstance()
{
if (null === self::$_instance) {
self::$_instance = new self();
}
return self::$_instance;
}
I've got a pretty standard ACL system in my application. There's a Login controller and a bunch of other controllers redirecting back to Login if user is not authorized. I use a Controller Plugin for checking the ID and redirecting and I obviously don't want Login controller and Error controller to perform such a redirect.
Now I've read several times that using Controller Plugins is a better practice than subclassing the Action Controller. Yet what I see is it's much easier to extend all my controllers from this abstract base controller class which performs the necessary checking in its init method, except for the Login controller which extends Zend_Controller_Action directly.
So the question is, is there a way to attach the plugin to the controllers selectively? Of course I can always make an array out of certain controllers, send it to a plugin through a setter method and do something like:
$controller = $request->getParam('controller');
if (count($this->exceptions))
if (in_array($controller, $this->exceptions)) return;
//...check ID, perform redirect, etc...
Yet something tells me it's not the best way doing it.
And advices?
EDIT 1: #Billy ONeal
Thank you for your reply, but I don't quite catch. I can do
public function init()
{
$this->getRequest()->setParam('dropProtection', true);
}
(or run some method that sets some private variable of the plugin) in my login controller, and then say if 'dropProtection' is not true then check the user ID. But the actual dispatch process looks like this:
Plugin::dispatchLoopStartup
Plugin::preDispatch
Controller::init
Plugin::postDispatch
Plugin::preDispatch
Plugin::postDispatch
Plugin::dispatchLoopShutdown
So I cannot check this 'dropProtection' param earlier than in Plugin::postDispatch and that's a bit late. (by the way, why the preDispatch and postDispatch are being called twice?)
If you want to do it earlier, I think you can use the first method (passing an array of exceptions to the plugin) and test the module name or the controller name in routeShutdown.
Personnaly I use an action helper to check the auth in all my actions. It's more flexible and give me more control. It's only one line for each private action.
And DON'T SUBCLASS your action controller. I did it on one of my project and now my base class is a piece of shit. Use action helper instead.
is there a way to attach the plugin to the controllers selectively?
Of course. Just don't register the plugin if the request doesn't contain the parameters you're looking for. Alternately, assume all pages are protected, and have those pages which should not be protected call some method on your plugin during the init stage.
If you want to protect just a single controller, you could reverse that -- have the plugin only take action if there's some method called during the init stage.
Finally, you could make the entire logged-in section of the page it's own module, which would allow you to have the plugin check for that module before checking credentials and redirecting.
I have a project in which I want to be able to call wp_list_pages() on a page that also uses the Zend Framework to power some complex interfaces manages custom data outside of wordpress.
This page should also redirect the user to the wordpress login screen if they're not already logged in with the appropriate level of authorization.
How would this work at a high level, i.e. do I need to edit the wordpress bootstrap file to conditionally implement the custom interface based on a specific URL or something, but still include certain files to be able to call wp_list_pages() on that custom interface?
I've developed a couple of WordPress plugins, and I've found it's really easy to extend. Haven't worked with Zend though.
You should check the WordPress plugin api. Mostly the part about actions, filters and hooks: http://codex.wordpress.org/Plugin_API
You can even override some functions (not sure if wp_list_pages() is overridable).
It's pretty well documented, and there's a large developer community behind it on IRC, forums, etc.
Thanks Fernando.
I just read this thread which suggests that you can use Zend in any script by just including:
require_once('Zend/Loader.php');
Zend_Loader::registerAutoload();
So given that all I need to use Zend for is on one page, can I just include that code in a custom template file that I assign to the appropriate page in the navigation? If I used javascript to submit the form via XHR, the requested URL would take the form '/controller/action' - but Zend wouldn't know the controller directory.
Could I put Zend code into the wordpress bootstrap, i.e. the above code plus the frontController configuration, and then use Zend wherever however?
So I've created a page in Wordpress and a custom template for that page, in which I've placed the following Zend Framework code:
require_once('Zend/Loader.php');
Zend_Loader::registerAutoload();
$db = Zend_Db::factory('Pdo_Mysql', array(
'host' => 'localhost',
'username' => 'username',
'password' => 'password',
'dbname' => 'dbname'
));
Zend_Db_Table::setDefaultAdapter($db);
class Users extends Zend_Db_Table_Abstract {
protected $_name = 'wp_users';
}
$users = new Users();
$users = $users->fetchAll()->toArray();
print_r($users[0]['user_login']);
This all works fine, so it's clearly possible to use Zend in conjuction with Wordpress at least to some extent.
It's becoming apparant that the problem is about who controls the URL rewriting, or the routing, or the bootstrapping (not sure of the correct terminology). If I were to put the end of the above code, starting $users = new Users();, into a controller as follows:
class UsersController extends Zend_Controller_Action {
function getUserAction() {
$this->_helper->viewRenderer->setNoRender();
$users = new Users();
$users = $users->fetchAll()->toArray();
echo $users[0]['user_login'];
}
}
How would I then call that function? My intention would be to call it from javascript via an XHR request in response to an event on the page, but requesting the URL 'index.php/Users/getUser/' returns 'No input file selected'. Trying to access the URL http://www.domain.com/Users/getUser/ produces a Wordpress 404 page.
Is there a way around this? It doesn't just apply to wordpress, of course - I expect it applies to any existing application that rewrites/routes requests via a bootstrap.
I guess you could do that, just import the framework into the one page you need it for. I don't know how Zend works, but check the paths as to where to put your directories so that Zend finds them.As I said I guess you could do that, just experiment and tell us how it went!
Beware of name conflicts for functions and/or variables, this shouldn't be much of a problem coming from such popular products as WordPress and Zend though... (which should be theoretically well coded)
I guess you could do that, just import the framework into the one page you need it for. I don't know how Zend works, but check the paths as to where to put your directories so that Zend finds them.As I said I guess you could do that, just experiment and tell us how it went!
Beware of name conflicts for functions and/or variables, this shouldn't be much of a problem coming from such popular products as WordPress and Zend though... (which should be theoretically well coded)
I've built a plugin for wordpress that has a similar goal to yours, more modeled on CodeIgniter though. Not knowing Zend terribly well, I think this should help:
Make a file named routes.php in your plugins directory with the following code:
add_action( 'init', 'add_custom_urls' );
function add_custom_urls(){
global $wp, $wp_rewrite;
$wp_rewrite->add_rule( '(.*)$', 'index.php?&cPath=$matches[1]', 'top' );
$wp->add_query_var( 'cPath' );
}
Be sure to activate both plugins in your admin. These two files will allow you to catch the url before Wordpress tries to figure out what to do with it. You can use regular expressions to have finer control over which pages to catch. You may have to delete the record in your _options db table where option_name = 'rewrite_rules' before this works.
Next, make another plugin with the following code:
add_action( 'template_redirect', 'bootstrap' );
function bootstrap(){
global $cPath;
echo( "cPath : $cPath" );
if( $cPath ){
dosomethingwith( $cPath );
}
}
Put all your code in the dosomethingwith() function. You'll need to figure out if the url requested can me mapped to a zend controller, etc. http://www.domain.com/Users/getUser/ would give you $cPath = Users/getUser/ If successful, you'll also probably want to die(), so once it is completed Wordpress won't try and take over again.