Just a quick logical question.
I have 2 Zend Controllers namely Merchant and Account. Merchant Controller has an action called editAction. My question is whether it is possible to have same action in Account as well without duplicating the code. I managed to create a include file for the view but I like to have a best way to manage my code. I currently have an idea of having an Helper class and invoke that helper class to both these Controllers. But I know someone would have got better solution than this. Please help me.
Thank you
The simplest solution would be to extend Zend_Controller_Action into your own base class and put editAction() into that. For example, assuming you have model classes named 'Account' and 'Merchant':
abstract class My_Controller_Action extends Zend_Controller_Action
{
protected $_modelName;
public function editAction()
{
$model = new $this->_modelName();
// Do your editing here.
}
}
class AccountController extends My_Controller_Action
{
protected $_modelName = 'Account';
}
class MerchantController extends My_Controller_Action
{
protected $_modelName = 'Merchant';
}
Keep in mind that this design implies that the code in editAction() would work for both Accounts and Merchants.
I think the best course of action would be to put majority of the logic inside your Models and keep your controllers lean. Your models can extend your own class which would have common operations in it.
You could also write your own class, it doesn't have to be a helper, and use it in the controllers to save the entity:
$saver = new My_Editing_Class();
$saver->edit("account",$this->getRequest()->getPost()); // Editing "account" with the POST data.
You then do your magic inside "My_Editing_Class".
Related
I want to create a base controller class for all my controllers in Symfony, I am very new to Symfony, so don't be angry with dumb question. I am asking this question because I can't do something like this
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class AbstractController extends Controller
{
public function __construct()
{
//...... check access level
$user = $this->getUser(); //This is not working, I don't have access to the Controller(the base class) properties
}
}
Now one of my controllers
class UserController extends AbstractController
{
public deleteUserAction(Request $request)
{
var_dump($this);// this will dump an empty class that is not instance of Symfony\Bundle\FrameworkBundle\Controller\Controller
//.... delete user
}
}
What is the best way to do this? please...
EDIT....
What I really want to do is to check whether a user privilege level is enough to access a particular action(e.g. deleteUserAction()) in a particular controller(e.g. UserController), I have a class that attach privilege level to all actions in all controllers. The check will be very efficient if it happens in a parent controller (e.g. BaseController's constructor) which is executed before UserController->deleteUserAction() but in the base controller I don't have access to $this.
I have tried voter and ACL none help my situation.
Thanks in advance.
I think second one is the best way to create your own class and use common function in it.
If you want to add some common functions of controller then it is not the proper way to add it into the Symfony default controller, Instead you can create BaseController and extend your all the controller with BaseController and your BaseController should extends Controller.
By this way the default controller of the symfony stay untouched.
simply use service controller... is shared:
http://symfony.com/doc/current/controller/service.html
I'm building a simple MVC framework in PHP and I'm stuck at the part where I have to create a BaseController class.
Every "page" controller needs to extend from this BaseController. Because this BaseController class will have properties that will give the user access to a template engine and a Logger class (and some other things).
The problem I have is that I'm not sure how to instantiate those things in the BaseController class. I can obviously hard code it in the __constructo() like this:
class BaseController
{
protected $view;
protected $log;
public function __construct()
{
$this->view = new \namespace\view('param1', 'param2');
$this->log = new Logger('name');
$this->log->pushHandler(new StreamHandler('path/to/your.log', Logger::WARNING));
}
}
But this doesn't make it very modular. It makes it hard to change the Logger class for example. Or if the user wants to change the template engine to Smarty for example.
I also can't really use a form of Dependancy Injection. Because then every controller that extends from the BaseController will have to pass those instances to the BaseController.
That would look something like this:
class BaseController
{
protected $view;
protected $log;
public function __construct($view, $log)
{
$this->view = $view;
$this->log = $log;
}
}
HomeController
class HomeController extends BaseController
{
public function __construct($view, $log)
{
parent::__construct($view, $log);
// Do my own stuff
}
}
To me that's not really user friendly when a user only wants to do a simple thing in the __constructor. Not even with an IoC.
So the only thing that I can think of now is to use a Service Provider from the __construct method in the BaseController. But I'm not really sure if that's the way to go? Maybe there is a better alternative?
So what would be a good solution to solve this problem?
PS. And if I do need a Service Locator, are there any good examples out there? The ones I've found were written by people that seemed like they didn't really know what they were talking about. They were basically copying each others blog posts.
You first need to think what's a controllers responsibility, why would it need access to logging functionality or why would it be setting the template engine or switching templates?
The controllers job is simply to extract the data from the request(mostly form data/user input) and sending it to the model layer via a service, it should not be selecting templates, that's the views job.
You obviously want you keep the dependencies of your base controller to a minimum so that when instantiating child controllers you don't have a big list of dependencies to inject.
My base controller has two dependencies, the request object and a view which are both injected in. Controllers are simple and light, no logic or anything fancy should happen in them. Once ever I had to use a logger in one of my controllers but that was just because PayPal was sending a request to it using the IPN system and I needed to log all the data in the request to a file to see what was going on, other than special cases like that I can't see why a controller would need a logger. In this case only the controller which dealt with the PayPal request held an instance of a logger, not the parent base controller.
You should always inject your dependencies. Don't instantiate objects in constructors, it makes your class tightly coupled to those objects.
If you end up using a service locator it can be a sign that your classes break the single responsibility principle of OOP.
Controllers are meant to be simple, don't over complicate them by adding in dependencies you think they might need in the future, especially not to the base controller or you may have a lot of refactoring to do.
In my application I have got a main controller in which I have a few methods. One of them checks if the user is logged in and if not it redirects the user to login form etc.
class FA_Controller_Auth extends Zend_Controller_Action {
public function preDispatch() {
//chceck user is login
}
}
aand all controllers extend from this main class
IndexController extends FA_Controller_Auth{}
but now I am building multi payment gatwey from Zend_Payment_Controllerso Payment_GatewayController should extend from Zend_Payment_Controller. But I need to chack if the user is logged in or not and I am looking for somthing like multi extend
Payment_GatewayController extends Zend_Payment_Controller, FA_Controller_Auth
I know there is no way to use multi extend class in PHP but maybe there is a better way to do this, action helper or plugin to check authorisation ?
Regards.
Regards.
You can only extend one class. This is exactly why using a base controller class is considered bad practice, as it limits you somewhat. Instead you should move the logic for both checks into controller plugins instead.
I am trying to learn how to use the Zend Framework and ive ran into trouble. Im trying to place the current users name in the header of the application (displayed on every page), specifically /layouts/scripts/default.phtml.
The MVC architecture is very new to me and confusing me greatly. I do not want to have to place the logic to display this username in the controller every time (this is probably the wrong way to do it anyway), so where would I place the code to assign this variable if not in each controller?
Cheers
This is the kind of thing that action helpers were designed for. A full tutorial on them is a bit beyond the scope of SO, but there are several good tutorials available.
Start with the Zend Framework Documentation and then take a look at Mathew Weier O'Phinney's tutorial and also this one by Rob Allen.
The issue with using a base controller for this kind of thing is that the resources are loaded regardless of wether your controller needs them or not, whereas action helpers are loaded only if needed.
I almost forgot the excellent ZendCasts have a video on action helpers.
You want a base controller and to assign that in the preDispatch method:
class MyApp_Controller_Action extends Zend_Controller_Action {
public function preDispatch() {
parent::preDispatch();
Zend_Layout::getMvcInstance()->assign('username', getCurrentUserName());
}
}
Then extend your own controllers with that new class:
class MyApp_Module_ActionController extends MyApp_Controller_Action {
}
Then in your layout view:
echo $this->layout()->username;
First, read the manual, and than try to accomplish something like this:
class BaseController extends Zend_Controller_Action {
public function preDispatch() {
// your logic to show the user name goes here
}
}
class SomePageController extends BaseController {}
class SomeOtherPageController extends BaseController {}
This will most likely solve your problem.
In my CI system\libraries directory I have a new class named DD_Controller.php. This file looks like this:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class DD_Controller extends Controller
{
protected $ddauthentication;
function __construct()
{
parent::Controller();
$this->ddauthentication = "Authenticated";
}
}
?>
My application controller is defined like this:
class Inquiry extends DD_Controller
{...}
The Inquiry class works fine when I extend Controller, but I get a
Fatal error: Class 'DD_Controller' not
found in
C:\development\localhost\applications\inquiry\controllers\inquiry.php
on line 4
When I extend DD_Controller. In the config file I have the prefix defined as such:
$config['subclass_prefix'] = 'DD_';
Any idea of what I'm missing?
TIA
This is a better approach. Do the following:
Go to the following directory: your_ci_app/application/core/ and create a php file called MY_Controller.php (this file will be where your top parent classes will reside)
Open this the file you just created and add your multiple classes, like so:
class Admin_Parent extends CI_Controller {
public function __construct() {
parent::__construct();
}
public function test() {
var_dump("from Admin_Parent");
}
}
class User_Parent extends CI_Controller {
public function __construct() {
parent::__construct();
}
public function test(){
var_dump("from User_Parent");
}
}
Create your children controllers under this directory your_ci_app/application/controllers/ . I will call it adminchild.php
Open adminchild.php and create your controller code, make sure to extend the name of the parent class, like so:
class Adminchild extends Admin_Parent {
function __construct() {
parent::__construct();
}
function test() {
parent::test();
}
}
DD_Controller.php should be in /system/application/libraries/
If you're using the same CI for multiple apps, and you want them all to be able to extends their controllers to your custom one then you can extend the base Controller class in the same file.
In system/libraries/Controller.php below the Controller class:
class Mega_Controller extends Controller {
function Mega_Controller()
{
parent::Controller();
// anything you want to do in every controller, ye shall perform here.
}
}
Then you'll be able to do this in your app controllers:
class Home extends Mega_Controller {
....
Since the extended controller class you created will be available. I think this is better then overwriting the base controller, but that would work as well.
I recommend to avoid "cracking" CodeIgniter core files.
Better use its native extending possibilities and try to fit into them.
The same rule I would recommend for any PHP library / CMS.
This rule has few reasons:
- ability to quiclky upgrade without takint into account thousands of notes where and how was cracked in core files;
- portability;
- possibility to share your code - eg, this will be usable by both you and your friends in case of need, and it will help them to keep their library up to date, the same as you.
In other words, this is much more professional and it pays to you in the future by usability, portability and by update application possibility.
Regarding your personal question...
As for me, there is nothing bad to create your own library with everything you need to extend native CodeIgniter Controller, then load this library in Controller's constructor and you are done. The only thing to make better usability is to give short name to your library.
This way you can even divide what you need in different pieces and put into separate libraries:
WebFeatures
AdminFeatures
etc.
Then you just load needed libraries in your controller's constructor and you are done.
P.S. I know that proposed way does not fit into "right" OOP concept, but in the same time you must never forget about the integrity of the libraries used.
Everything above is just one more view of mine 7-years experience in professional web development, so I hope it will be helpful if not to follow, then at least to take into account.
Regards,
Anton