Sorry if the title is a little vague, I do not know how else to describe it.
I am making my own small framework. Things are going nicely and I am enjoying looking at topics that I usually do not need to check out as 'the magic' does it for me.
My framework is PHP based and I want it to run from a single instance. What I mean by this is the following.
class Controller_Name extends Controller {
public function __construct() {
$this->load->library('session');
$this->load->model('Model_Name');
}
}
class Model_Name extends Model {
public function something() {
if ($this->session->get($something))
// Do something Amazing
}
}
As hopefully illustrated above I want all controllers / Models / Views to share already loaded libraries.
So if a class is loaded in the Controller, I will be able to use it in a view file.
Does anyone know how this done? Can you point me in the direction of an article covering it, what this is called or some php function calls either completely or partly do the job.
As always, any answers are greatly appreciated.
If your aim is to make sure all dependencies inside your classes are resolved, have a look at the Service Containers from the Symfony Dependency Injection Component or the Stubbles framework.
Your controller can implement __get and intercept requests for libraries that have been loaded. Ideally you'd store the libraries in a static field to get the reuse you mentioned you wanted.
Also, to get load to behave like you want I'd personally create a Loader class and create an instance of it in the Controller. Then in the __get magic method I'd make it fetch it from the loader.
Related
i have created a controller that extends TCPDF to be able to customise a bunch of stuffs ,
also i need to use inside it Helpers .
knowing that i can not have multiple inheritance in php , i tried to create an instance of the view inside the constructor of my new controller to grab the target Helper
like this
class NewPDF extends TCPDF{
public function __construct()
{
$fakeView=new View($this);
$htmlHelper=$fakeView->loadHelper("Html");
# some code ..... parent::__construct()
}
}
it does not work . it gave me weird errors !!!
how can i use a helper inside a controller that does not extend AppController ?
it does not work . it gave me weird errors !!!
It does because you're doing everything totally wrong. That you want to extend a controller with a helper and even throw a view in the mix tells me you have seriously no idea at all how a MVC framework works.
Design patterns in general (MVC is one)
Wikipedia about MVC
CakePHP book explanation of MVC
Random Google article about MVC
Start over here when you understoog the above
At least I'm not going to write in detail what is wrong because like I said, everything is wrong, start with the very basics. The links will explain how to do it right. What you wrote shows a huge lack of knowledge that can't be fixed by a short answer.
I got a Tank Auth library installed in my Codeigniter package, the problem is that I don't like how to is_logged_in functions need to be called because it's simply long and not so friendly, as I need to use:
$this->tank_auth->is_logged_in()
Everytime I want to check if user is logged in...
So is there a way to make it shorter? By saying shorter I mean something like $this->logged();?
I would really appreciate if someone could help me.
Thank you.
Head into the tank_auth library and define a new public function:
public function logged(){
return $this->is_logged_in();
}
You can now access it with $this->tank_auth->logged();
If you want to shorten the name of tank_auth, you'll have to rename the class and the filename.
UPDATE:
The more important question is, why are you calling this so many times that it is becoming an annoyance? You should only have to write it once if your code follows the Don't Repeat Yourself (DRY) principle.
Have a look at Phil Sturgeon's blog post entitled Keeping It DRY. He will show you how to write a base controller that all your controllers will inherit from. If you write the login check in the constructor of the base controller, you don't have to write it in every controller.
I would argue against doing this as the method logged() in your instance lacks context. However, if you wanted to do this, you could write a base controller which has a logged() method which ends up returning $this->tank_auth->is_logged_in(). All controllers would inherit from this base controller, which isn't a bad idea to begin with.
If you're using libraries, you could implement a similar pattern in them.
You probably don't want to edit anything in the TankAuth library if you didn't create it as doing so affects the updatability of the library. Instead, you might add a method to your controller called logged and have it reach out to Tank Auth. Although, I would choose a better name for your function as pointed out by a previous answer.
Create or edit your controller base class to have something like this:
function is_logged() {
return $this->tank_auth->is_logged_in();
}
Then you may call it like so: $this->is_logged();
I'm building a small framework that I can use for repeated mundane stuff on future small projects.
I'm stuck on the best way to access libraries from inside a controller. I originally implemented a system similar to CodeIgniter's whereby my main controller class is basically a super object and loads all the classes into class variables which are then accessed by extending the controller and doing like $this->class->method()
I find that a little ugly, though. So I thought of just loading each class individually on a per-use basis in each controller method.
What's the best (cleanest) way of doing this?
To only ever have one instance of each class, you could create a simple service container.
class ServiceContainer
{
protected $services;
public function get($className)
{
if (!array_key_exists($className, $this->services)) {
$this->services[$className] = new $className;
}
return $this->services[$className]
}
}
Then create one ServiceContainer instance per application. Inject the container into all of your controllers and use
public function someAction()
{
$this->container->get('Mailer')->send($email_data);
}
Simple example, and obviously needs a lot of work to make useable (for instance autoloading needed and handling of file paths for ease of use, or easier way to add services without getting them, etc).
I dont like the way CodeIgniter does it. Its never seemed right to me. I favor an auto loading class pushed onto the spl_autoload stack. And then just calling the class as normal like:
$class = new SomeClass();
PHP provides autoload functionality with SPL and spl_autoload (and related functions). You can register a custom autoloader for your library code.
For the shared functionality handled by your application, have you considered the Front Controller design pattern?
I am trying to put this function ((click_add)) in library so that i can call it from all the controllers. I already have get_ads() function in library. I tried various ways to shift the click_add(id) function to library and call it to view along with get_ads but doesn't work. Please help
function __construct() {
parent::__construct();
$this->load->library('ads');
$this->load->model('MGlobal');
}
public function index(){
$data['banner']= $this->ads->get_ads();
$this->load->view('test',$data);
}
//i want this in library but no luck
public function click_add($ads_id){
$ads_site = $this->MGlobal->getAds($ads_id);
$this->MGlobal->add_ads_view();
redirect($ads_site['url']);
}
//and views is like this
foreach($banner as $k=>$list){
echo anchor('test/click_add/'.$list['bannerid'],'<img src="'. $list['image']. '"/>');
}
please suggest me how do i achieve that with library
It's also important to remember the role of each part of the MVC pattern. In your click_add() method, it looks like you're rendering a view and causing a redirect. These are two things best suited for a controller rather than a library. Rendering views and redirecting are two things that must be a controller's responsibility, and indeed, you won't be able to access them through the URL, which is what you're trying to do here.
If you want to reuse this method across multiple controllers in your site, try creating a MY_Controller core class and extending your controllers from that. That way, any methods you define in the MY_Controller will be available in any controller you subclass from.
Without any specific error messages or a more verbose description of the problem you're having, I'm afraid there's little more help I can give you.
For projects written in php, can I call more than one (or multiple) controller in class controller? Example in http://img192.imageshack.us/img192/7538/mvc03.gif
ASK: I need to call an action from another controller... And if I do like the picture above, I'm being out-ethics?
Thanks,
Vinicius.
I'm sure that you can do what you want with whichever framework you're using. If you can't do it natively for whatever reason, then you can extend your framework as required.
Having said that, I personally don't like the idea of a controller calling another controller. It seems to somewhat break the MVC paradigm if only from a theoretical standpoint. What I might do instead is build a library class that contains the functionality required and then have both controllers instantiate that class as a member and call the functions required.
For example, using CodeIgniter:
libraries/MyLib.php:
class MyLib
{
public function MyFunc()
{ /* do whatever */ }
}
controllers/ControllerA.php:
class ControllerA extends Controller
{
public function index()
{
$this->load->library('MyLib');
$this->mylib->MyFunc();
}
}
controllers/ControllerB:
class ControllerB extends Controller
{
public function index()
{
$this->load->library('MyLib');
$this->mylib->MyFunc();
}
}
out-ethics? Anywhose... back to reality.
Yes, a controller can call another controller's action. For instance, in cakePHP, this functionality is afforded via requestAction
// pass uri to request action and receive vars back
$ot3 = $this->requestAction('/stories/xenu');
If you're rolling your own, the details of how to implement it will be very specific to your framework.
then you need to modify framework, find place where controller is lounched and add there your second controller.
what framework you are using?
You can do it any way that you want. You don't have to use MVC if you don't want to. However, in MVC you really should only have one controller active at a time. You probably want multiple Views or Models, not another Controller. There is nothing at all wrong in loading, say, a header and footer view for the menu and footer of the site.
If you are building another Controller, then feel that you need to access the functionality of a previous Controller to access its functionality (because it works with a specific / desired Model), then the Model you developed for the latter probably needs to be refactored. IN plain speak, your target Model may be doing too much. Break it up.
You are trying to avoid repeating yourself (DRY) by using calling the methods of a Controller that has already been developed, but in doing so your are creating TIGHT coupling between both controllers! If something changes in the borrowed controller, it will have an effect on the borrowing controller. Not good, Dr. Jones.