Leng
Leng

Reputation: 2998

Laravel 4 Add Method to Class (IoC / Namespaces)

I'm trying to figure out how to add a method to a class in a Laravel package, so that all controllers and models that call that class can access the new method. How do I replace this class in the IoC?

This is the package in question, Angel CMS. The package is my creation, so I can modify it if we need to add aliases or anything to accomplish this.

Let's say I want to add a method to this class:

vendor/angel/core/src/models/PageModule.php

Okay, so I copy the class file to here:

app/models/PageModule.php

And then I modify the copied file, adding a namespace and the desired custom_function method:

<?php namespace MyModels;

use Eloquent;

class PageModule extends Eloquent {
    protected $table = 'pages_modules';

    public static function custom_function()
    {
        return 'It works!';
    }
}

As you can see, I am using the MyModels namespace here.

Then, I run a composer dump-autoload.

Next, I open up my app/routes.php and register the binding and set up a test route:

App::bind('PageModule', function($app) {
    return new \MyModels\PageModule;
});

Route::get('test-binding', function() {
    return PageModule::custom_function();
});

But, when visiting the test route, I always receive the same error that the method is undefined.

What am I doing wrong here? Thank you in advance for any help.

To Clarify:

I am attempting to replace the class application-wide so that all other classes (controllers/models/etc.) that call PageModule will have access to the custom_function method. Thanks.

Upvotes: 2

Views: 406

Answers (2)

Unnawut
Unnawut

Reputation: 7578

To be honest, I'm pretty new to all this IoC, dependency inversion/injection concept too. But I think I've gone through the same struggle before. What I would do, as much as my knowledge allows, is...

Add a constructor to src/controllers/admin/AdminPageController.php:

protected $pageModule;

public function __construct(PageModule $pageModule)
{
    $this->pageModule = $pageModule;
}

Then where you did $module = new PageModule in the same file. You replace it with:

$module = $this->pageModule;

The two modifications above makes use of Laravel's IoC to allow injecting a different PageModule object into your controller, instead of strictly creating PageModule in your code.

Now at this point Laravel should know that when it constructs the AdminPageController, it should create a PageModule and inject into the controller for you.

Since your controller now expects a PageModule class, you can no longer do class PageModule extends Eloquent in your app anymore, because even though the name is the same, PHP does not think that it is! You'll need to extend it:

So let's rename your app/models/PageModule.php to app/models/CustomPageModule.php, and in the file change the class to:

class CustomPageModule extends \PageModule {

Up to this point, you also have a CustomPageModule class that is a child of your package's PageModule. All you need to do now is to let Laravel knows that if any controllers ask for PageModule, it should serve the controller with your MyModels\CustomPageModule instead.

So at the top of your app's routes.php file:

App::bind('PageModule', 'MyModels\CustomPageModule');

Your AdminPageController should now be using your CustomPageModule and can use whatever public methods that are in there!


I'm expecting to be editing this answer heavily since this will be quite a long discussion. My first try at answering above isn't the best code you can write, but I hope it takes the least amount of edit to the original code, and then we can work up from there.

Or fast track by reading up articles like http://culttt.com/2013/07/08/creating-flexible-controllers-in-laravel-4-using-repositories

Upvotes: 1

Valentin
Valentin

Reputation: 602

You probably have a alias for the PageModule facade, you should override this alias using your class \MyModels\PageModule in your app/config/app.php file.

Be careful, it seems like you are overwriting the PageModule class instead of extending it. You should probably extend the parent class instead of Eloquent.

Upvotes: 0

Related Questions