Reputation: 2998
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
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
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