How do I centralize code from my init functions in all controllers? - php

public function init(){
$this->view->user = Zend_Auth::getInstance()->getIdentity();
$this->view->siteName = Zend_Registry::get('config')->site->name;
$this->view->menu = $this->_helper->generateMenu(Zend_Auth::getInstance()->getIdentity());
$this->view->slogan = Zend_Registry::get('config')->site->slogan;
}
This is the init file in all of my controllers across all modules, is there a place I can put this code so it executes every request irregardless of the module/controller being called?

I'd rather advise you to write a plugin by extending Zend_Controller_Plugin_Abstract, it is its purpose.
By this way, you will have no need to do anything anywhere in your controller.
Then you can use the registry to access to your data...
class My_Controller_Plugin_Acl extends Zend_Controller_Plugin_Abstract
{
protected $_auth = null;
protected $_acl = null;
public function __construct (Zend_Auth $auth, Zend_Acl $acl)
{
$this->_auth = $auth;
$this->_acl = $acl;
}
public function preDispatch(Zend_Controller_Request_Abstract $request)
{
//some code
}
}
And then in your bootstrap.php
$this->_front->registerPlugin(new My_Controller_Plugin_Layout());
http://framework.zend.com/manual/en/zend.controller.plugins.html

To share code across controllers, create an Action Helper which was designed primarily to solve the problem you have.
They can be run "on demand":
$myHelper = $this->_helper->MyHelper;
$myHelper->someFunction();
and also have a set of hooks that the dispatch process will call automatically. To use the hooks, you need to register the action helper with the broker:
$helper = new App_Controller_Action_Helper();
Zend_Controller_Action_HelperBroker::addHelper($helper);
The available hooks are:
init()
preDispatch()
postDispatch()
For more info,the manual page can be found at http://framework.zend.com/manual/en/zend.controller.actionhelpers.html and I have written a couple of articles about them: http://akrabat.com/2008/10/31/using-action-helpers-in-zend-framework/ and http://akrabat.com/2008/11/05/hooks-in-action-helpers/

You can extend Zend_Controller_Action:
public class My_Controller_Action extends Zend_Controller_Action
{
public function init()
{
$this->view->user = Zend_Auth::getInstance()->getIdentity();
$this->view->siteName = Zend_Registry::get('config')->site->name;
$this->view->menu = $this->_helper->generateMenu(Zend_Auth::getInstance()->getIdentity());
$this->view->slogan = Zend_Registry::get('config')->site->slogan;
}
}
Then you just change your controllers to extend My_Controller_Action rather than Zend_Controller_Action. Just keep in mind that if you need to add additional code to the init method of a controller, you'll have to invoke parent::init() as well:
public class FooController extends My_Controller_Action
{
public function init()
{
parent::init();
// Do something.
}
public function IndexAction()
{
// ...
}
}

Related

Custom BaseController in Silex

I have created a simple aplication in Silex 1.3.4 and I want to have a base controller that will have a __construct method accepting $app and $request. All inheriting controllers then should have their respective constructors and calling the parent controller construct method.
//Use statements here....
class AppController
{
public function __construct(Application $app, Request $request){
$this->app = $app;
$this->request = $request;
}
}
Inheriting controllers would be written as below:
//Use statements here....
class ItemsController extends AppController
{
public function __construct(Application $app, Request $request){
parent::__construct($app, $request);
}
public function listAction()
{
//code here without having to pass the application and request objects
}
}
The approach I have decided on routing is as shown below:
$app->post(
'/items/list', 'MySilexTestDrive\Controller\ItemsController::listAction'
)->bind('list');
I was thinking of using the dispatcher and override some processes there and create my controller instances my own way but I do not have any idea how and if this is a great idea at all.
Anyone who has done something similar to this? Please help.
You can use ServiceControllerServiceProvider to define your controller as a service in the application. But you can't inject a Request in that way. BTW you can have more than one request and the request instance can change if you do sub-request. You can inject RequestStack instead, then call $requestStack->getCurrentRequest() when you need to get the current request.
$app = new Silex\Application();
abstract class AppController
{
protected $app;
protected $requestStack;
public function __construct(Silex\Application $app, Symfony\Component\HttpFoundation\RequestStack $requestStack)
{
$this->app = $app;
$this->requestStack = $requestStack;
}
public function getRequest()
{
return $this->requestStack->getCurrentRequest();
}
}
class ItemsController extends AppController
{
public function listAction()
{
$request = $this->getRequest();
// ...
}
}
$app->register(new Silex\Provider\ServiceControllerServiceProvider());
$app['items.controller'] = $app->share(function() use ($app) {
return new ItemsController($app, $app['request_stack']);
});
$app->get('/items/list', "items.controller:listAction");
It makes sense to do such a thing? I do not think so. Especially if the framework gives you a request instance thanks to the type hinting. Just do
public function listAction(Application $app, Request $request)
{
// ...
}
and work with that.
You can try this too :
class BaseController
{
protected $app;
protected $request;
public function __call($name, $arguments)
{
$this->app = $arguments[0];
$this->request = $arguments[1];
return call_user_func_array(array($this,$name), [$arguments[0], $arguments[1]]);
}
protected function getSystemStatus(Application $app, Request $request)
{
[...]
}
[...]
}
#Rabbis and #Federico I have come up with a more elegant solution for this where I have created a BeforeControllerExecuteListener that I dispatch with my application instance. This listener accepts the FilterControllerEvent object and then from my base controller I call a method where I inject both the Silex Application and the request from the event.
public function onKernelController(FilterControllerEvent $event)
{
$collection = $event->getController();
$controller = $collection[0];
if($controller instanceof BaseControllerAwareInterface){
$controller->initialize($this->app, $event->getRequest());
}
}
The I simple dispatch this in my bootstrap file as shown below:
$app['dispatcher']->addSubscriber(new BeforeControllerExecuteListener($app));
This allows me to have access to this object without having to add them as parameters on my actions. Below is how one of my actions in the making looks:
public function listAction($customer)
{
$connection = $this->getApplication()['dbs']['db_orders'];
$orders= $connection->fetchAll($sqlQuery);
$results = array();
foreach($orders as $order){
$results[$order['id']] = $order['number'] . ' (' . $order['customer'] . ')';
}
return new JsonResponse($results);
}
If the currently running controller being called honors the BaseControllerAwareInterface interface as I have defined it then it means I should inject that controller with the Application and Request instances. I leave the controllers to deal with how they manage the Response of each action as with my example above I may need the Response object itself of JsonResponse even any other type of response so it entirely depends on the controller to take care of that.
Then the routing remains as simply as:
$app->match('/orders/list/{cusstomer}', 'Luyanda\Controller\OrdersController::listAction')
->bind('list-orders');

PHP OOP-based login system

Lets say I am building an OOP-based user authentication system, and I would like to incorporate the following principles: Direct Injection, Inheritance, Encapsulation, Polymorphism and the Single Responsibility Principle.
My background in programming is has always relied on procedural programming, and thus, am finding it difficult to really put these practices into correct use.
Assume I have these classes:
class Config
{
public function set($key, $value);
public function get($key, $default = null);
}
class User
{
public function __construct(PDO $dbh, $id = null);
public function setProfile(Profile $profile);
}
class Auth
{
public function __construct(Config $config);
public function login($username, $password, $keepLoggedIn = true);
public function isLoggedIn();
public function getLoggedInUser();
public function logout();
public function register(array $data);
}
class Session
{
public function start($sessionName = null);
public function write($key, $value);
public function read($key, $default = null);
}
class Profile
{
public function setAddress(Address $address);
public function setName($name);
public function setDOB(DateTime $date);
public function getAge();
}
class Validator
{
public function validate($input);
}
I have intentionally left off the function bodies to keep things simple.
To the best of my knowledge, I believe I'm using the principles correctly. However, I am still unclear as to how you would connect classes like: the Validator to the User model, the User model to the Auth and the Session to the Auth class. All of which depend on each other.
You are on the right track. The way these classes connect to each other is called extending. I tend to go towards an MVC setup, meaning Model, View, Controller.
Your logic goes into the controller, all your DB queries and concrete back end methods go in the model. The controller receives requests and returns responses. It's the middleman. It talks to the back end after a request has been made to it, and feeds the front in via response.
So you have a core controller (keep it bare minimal), then each class you make extends the core controller. So your controller is where you tie all this together.
<?php
//your main core controller, where you load all these things you need avilable, so long as this class is extended
class CoreController {
public $auth
public $session;
public $view;
function construct__ ()
{
$this->auth = instantiateAuthClassHere();
$this->session = instantiateSessionClassHere();
$this->view = instantiateViewClassHere();
}
public function anotherHelperForSomething(){
//helper stuff for this method
}
}
//index, page, or content controller, depending on how many you need, i.e. if you want a controller for each page, thats fine, e.g indexController, etc..
//this is the middle man, has logic, receives requst, returns response to view.
class Controller extends CoreController {
public function index (){
$userModel = new userModel();
//do something with this
$session = $this->session;
$content = 'some html';
$userInfo = $userModel->getUsers();
$view = $this->view->render( array(
'content' => $content,
'userInfo' => $userInfo,
));
return $view;
}
}
//Core LIbraries
class Validator {
//your validator stuff
}
//Core LIbraries
class Session {
//your validator stuff
}
//Core LIbraries
class Auth {
//your validator stuff
}
class CoreModel{
public $validator;
function __construct(){
$this->validator = instantiateValidatorClassHere();
}
}
//a user model class (back end). you want a model class for each db table pretty much.
class UserModel extends CoreModel {
// if you need the validator anywhere inside this class, its globally available here inside any class that extends the CoreModel, e.g. $this->validator->methodName()
public function getUsers (){
$sql = 'SELECT * from users';
$result = $db->get($sql);
return $result;
}
}
Notice, on the Controller, this is a generic name for something like indexController, or anything custom. Also, I have the word extends there. It inherits all the objects from the parent that it extends. Inside it, now they will be available via $this->. See my example where I get $this->session.
Try to avoid constructs - you probably don't need them anywhere except for the core, and under special circumstances, which you might then need to check for yourself before you do even that. I dont use constructs much anymore. It can be a bit clunky and unmanageable.

Cakephp call an component method inside a helper

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 :)

Zend Framework how to do this in order to not repeat myself

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();
...

Best way to deal with session handling in Zend Framework

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');
}

Categories