I need get plugin before load routes. I use routeStartup and preDispatch in plugin, but it doesn't help.
class Base_Controller_Plugin_Website extends Zend_Controller_Plugin_Abstract
{
public function routeStartup(Zend_Controller_Request_Abstract $request)
{
Base_Website::setRequest($request);
}
}
I need method from Base_Website.
The earliest front-controller plugin event is routeStartup, so if you want to perform some action prior to that, you'll need to do it in Bootstrap.
Unfortunately, the methods that run during bootstrap don't pass the Request and Response objects to you. You'll have to dig them out yourself. Something like:
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
// all your other _initXXX() bootstrap methods
// etc...
protected function _initSomethingUsingRequest()
{
$this->bootstrap('frontController');
$front = $this->getResource('frontController');
$request = $front->getRequest();
// Now do whatever you want with your Request object
// etc...
}
}
Related
What I want to do: Register a component to an event raised by a controller.
In my config main.php:
'preload' => array(MessageConsumer) // actually an impl class of interface
In my MessageConsumer impl
public function init() {
Yii::app()->getController()->onMessageReceived = array($this, 'onMessageReceived');
}
Expected result: when the init method fires the consumer is registered to the current controller.
Actual result: there's no current controller yet. It seems the pre-load is performed before the webapplication does the controller magic.
So I tried something like:
In my MessageConsumer impl:
public function init() {
$self = $this;
Yii::app()->onBeginRequest(function() use ($self) {
$controller = Yii::app()->getController();
if($controller instanceof MessagingController) {
Yii::app()->getController()->onMessageReceived = array($self, 'onMessageReceived');
}
});
}
Which doesn't work either because it seems the init() is called after the onBeginRequest() event is raised by the webapp.
Is there a way to register to events raised by a controller without explicitly linking the component to the controller class? Obviously I could register the listener in the constructor of the controller but I want to loosely couple the 2 components by using configuration.
Maybe there's some event like "onComponentLoaded" for which I could register? Since a Controller is a component I'd expect the Yii core to fire the event whenever there's a component loaded if there's such an event at all.
I presume this is what you looking for, the onBeforeAction();
<?php
class YourController extends Controller
{
//this action is executed before any controller action
protected function beforeAction($action)
{
//do stuff before controll action
return true;
}
//the rest ofyour controller actions and stuff
public function actionIndex(){
//[...]
}
}
?>
I use Cakephp 2.1 and I need to call a component method which resides in a plugin, from a view helper:
The component is here:
/app/Plugin/Abc/Controller/Component/AbcComponent.php
The helper is here:
/app/View/Helper/SimpleHelper.php
I tried inside helper:
App::import('Component', 'Abc.Abc');
$this->Abc = new Abc(); or $this->Abc = new AbcComponent;
or
$this->Abc = $this->Components->load('Abc.Abc');
inside the controllers this component works with no problem.
I know this isn't recommended (MVC design etc.) but if I don't use it this way I need to duplicate a lot of code. I need to make something like:
MyHelper extends Helper{
$simpleVar = Component->get_data();
}
I use CakePHP 2.4
This is how I successfully call Component from a Helper:
App::uses('AclComponent', 'Controller/Component');
class MyHelper extends AppHelper {
public function myFunction() {
$collection = new ComponentCollection();
$acl = new AclComponent($collection);
// From here you can use AclComponent in $acl
if ($acl->check($aro, $aco) {
// ...
}
}
}
Passing data from CakePHP component to a helper
This seems to be a very nice way to handle this.
I tried working the way you are before, and, although it seems to be a nice immediate solution, in the long run, it is better to just work with the component and helper as 2 separate entities in your controller.
lee
You can put logic in trait and use this from component and helper, if your porpouse is to use the same business logic in different places, to avoid duplication code.
By example
the trait (file app/Lib/NameOfTrait.php or app/PluginName/Lib/NameOfTrait.php)
trait NameOfTrait {
public function theTraitFunc($a, $b) {
// Code here
}
}
The Component:
App::uses('Component', 'Controller');
App::uses('NameOfTrait', 'PluginName.Lib');
class NameOfComponent extends Component {
use NameOfTrait;
private $member;
private $controller;
public function __construct(ComponentCollection $collection, $settings = array()) {
parent::__construct($collection, $settings);
$this->member = $settings['memberName'];
}
function startup(Controller $controller) {
$this->controller = $controller;
}
/**
* Wrap function call of trait function,
* I think the function doesn't have the same name,
* I don't try this but I think is obvious,
* to avoid the function to call itself
*/
public function theTraitFuncWrap($a) {
return $this->theTraitFunc($a, $this->member);
}
}
Do The same for the Helper.
I hope this help someone, bye :)
I searched on Google, and I got this code to check if a controller exists or not.
$front = Zend_Controller_Front::getInstance();
if ($front->getDispatcher()->isDispatchable($request)) {
// Controller exists
}
But I don't know where I should put this code. What is $request?
I'm in Boostrap.php. I have _initRoute, I need to check if a controller doesn't exist, if it doesn't then I will add a new route.
Updated after first answer. I have some routes in Boostrap.php
public function _initRoute() {
$front = Zend_Controller_Front::getInstance();
$router = $front->getRouter();
$router->addRoute(
'username',
new Zend_Controller_Router_Route(':username',
array('controller'=>'profile',
'action'=>'index')
)
);
$router->addRoute(
'username/sets',
new Zend_Controller_Router_Route(':username/sets',
array('controller'=>'profile',
'action'=>'sets')
)
);
}
This Routes, will make mydomain.com/{username} show content same as mydomain.com/profile/index/username/{username}
But the problem is, when I type mydomain.com/{anything or any controller} , it routes as I define on Boostrap. So, I think, I need to check the controller is existing or not, if it doesn't then do the routes.
Am I wrong? After first answer, I added the plugin, and put it under _initPlugin to register it. But look like it not work.
This is my boostrap file:
<?php
//Zend_View_Helper_PaginationControl::setDefaultViewPartial('paginator.phtml');
class Plugin_MyX extends Zend_Controller_Plugin_Abstract {
public function routeStartup(Zend_Controller_Request_Abstract $request) {
$front = Zend_Controller_Front::getInstance();
$dispatcher = $front->getDispatcher();
if (!$dispatcher->isDispatchable($request)) {
$front = Zend_Controller_Front::getInstance();
$router = $front->getRouter();
$router->addRoute(
'username',
new Zend_Controller_Router_Route(':username',
array('controller'=>'profile',
'action'=>'index')
)
);
$router->addRoute(
'username/sets',
new Zend_Controller_Router_Route(':username/sets',
array('controller'=>'profile',
'action'=>'sets')
)
);
} else {
// exist
}
}
}
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
protected function _initPlugin() {
$front = Zend_Controller_Front::getInstance();
$front->registerPlugin(new Plugin_MyX());
}
public function _initRoute() {
}
}
You should put that code in a Controller Plugin since the request object does not yet exist at bootstrap time.
The $request variable in question is an object of Zend_Controller_Request_Http. This object is initially created when the front controller goes to dispatch a request.
You could register a routeStartup plugin and place the code there. That would be the earliest point at which you can use the Request object. All controller plugin chains will pass the request object to your plugin except for dispatchLoopShutdown().
Here is sample plugin code:
class Application_Plugin_Example
{
public function routeStartup(Zend_Controller_Request_Abstract $request)
{
$front = Zend_Controller_Front::getInstance();
if ($front->getDispatcher()->isDispatchable($request)) {
// Controller exists
}
}
}
If you are trying to just handle 404 errors, this is what the ErrorHandler plugin can be used for this purpose.
You should have your routes from most specific to less specific. Also think about whether you can't have any other option in your URL - like /u/:username or /user/:username, which would solve the problem ;)
Also defining routes for each end every controller would solve it - create:
/controller-name/
/profile-controller-name/
... with
/:username
at the end of the list
That way any controller would be matched earlier and would work. And only controllers not listed would "fall through" to the :username route.
I have this thing that I need in multiple places:
public function init()
{
$fbLogin = new Zend_Session_Namespace('fbLogin'); #Get Facebook Session
if(!$fbLogin->user) $this->_redirect('/'); #Logout the user
}
These two lines:
$fbLogin = new Zend_Session_Namespace('fbLogin'); #Get Facebook Session
if(!$fbLogin->user) $this->_redirect('/'); #Logout the user
Whats the best way to do it in ZendFramework?To create a plugin or? I mean I want to execute it in multiple places but If I need to edit it I want to edit it in one place.
Here is an example of an Action Helper that you can call from your controllers easily.
<?php
class My_Helper_CheckFbLogin extends Zend_Controller_Action_Helper_Abstract
{
public function direct(array $params = array())
{
// you could pass in $params as an array and use any of its values if needed
$request = $this->getRequest();
$view = $this->getActionController()->view;
$fbLogin = new Zend_Session_Namespace('fbLogin'); #Get Facebook Session
if(!$fbLogin->user) {
$this->getActionController()
->getHelper('redirector')
->gotoUrl('/'); #Logout the user
}
return true;
}
}
In order to use it, you have to tell the helper broker where it will live. Here is an example code you can put in the bootstrap to do so:
// Make sure the path to My_ is in your path, i.e. in the library folder
Zend_Loader_Autoloader::getInstance()->registerNamespace('My_');
Zend_Controller_Action_HelperBroker::addPrefix('My_Helper');
Then to use it in your controller:
public function preDispatch()
{
$this->_helper->CheckFbLogin(); // redirects if not logged in
}
It doesn't go into much detail, but Writing Your Own Helpers is helpful as well.
If you need this check in every Controller you could even set up a baseController from which you extend instead of the default one:
class My_Base_Controller extends Zend_Controller_Action
{
public function init()
{ ...
class IndexController extends My_Base_Controller
{ ...
Shift your init() into the base controller and you don't need to repeat yourself in every specific controller.
Need a varying init() in a specific controller?
class FooController extends My_Base_Controller
{
public function init()
{
parent::init();
...
So I'm starting up in Zend framework and looking to implement a site-wide "User" session.... something I can easily access from ALL modules/controllers in the application.
I'm like, should I make a new namespace in the library and extend the controller, like:
class MYCUSTOMLIB_Controller_Action extends Zend_Controller_Action
{
protected $_userSession;
function preDispatch(Zend_Controller_Request_Abstract $req)
{
$this->_userSession = new Zend_Session_Namespace('user');
}
}
ANd then have all my controllers/modules/etc extend from that?
Or should I create a Plugin or what? How would you go about making this plugin to pass the user session to the controller?
Or do I do it in the bootstrap?? Again how to pass to controller?
Also should I use Zend_Session_Namespace or Zend_Http_Cookie and also how do I encrypt and xss clean the cookie or is that done automagically?
I would initialise in the bootstrap too:
//Bootstrap.php
protected function _initUserSession()
{
return new Zend_Session_Namespace('user');
}
Then I would use an action helper:
// library/App/Controller/Action/Helper/Session.php
class App_Controller_Action_Helper_Session extends Zend_Controller_Action_Helper_Abstract
{
function direct()
{
return $this->getFrontController()->getParam('userSession');
}
}
You access it in your controller like this:
function indexAction()
{
$session = $this->_helper->session;
}
You should initialize your session in the bootstrap. You can either put it in the Zend_Registry and access it that way or from your controllers you can access your bootstrap by calling $this->getInvokeArg('bootstrap').
// in your controllers
public function init()
{
$bootstrap = $this->getInvokeArg('bootstrap');
$this->_session = $bootstrap->getResource('session');
}