Laravel Structure - dependency injecting a controller - php

I have a laravel app and have created a SocialMediaController to get the latest posts from twitter and instagram and store them in the database.
I need them to be universally accessible and know I can access it via the IOC.
public function doSomething(App\Http\Controllers\SocialMediaController
$SocialMedia) {
}
However if feels wrong to inject a controller like this. What is be best way to wrap up these methods for global use?

It seems like you want to share some logic you have in the SocialMediaController with another controller, right?
Instead of trying to pass a controller instance to the controller action using the service container, you may move the current logic to a service. Refer to Service Container and Service Providers in the Laravel docs on how to create your own services.
Another way to achieve that is using a trait. Check this answer on how you can do that https://stackoverflow.com/a/30365349/1128918. You would end up with something like this:
trait SocialFeeder {
public function getLatestFromTwitter() {
...
}
}
And, then, you can use that new trait with your controllers:
class SocialMediaController extends Controller {
use SocialFeeder;
public function doSomething() {
...
$tweets = $this->getLatestFromTwitter();
...
}
}

Related

How to access data some specific Controllers in Laravel?

For sharing data with all views I read in documentation we can create
View::share('key', 'value');
I found that also we can make View Composer to share data with only some specific views.
But how to actually share data with only some specific controllers?
Few controllers we list to have injected some variables, objects arrays etc ready to use.
One Idea that comes to my mind is to create for them middleware... But I don't think it should be done something this way
Looking for this in documentation and web but cannot found, so how actually share data only with some specific controllers that we want to?
Maybe this will help for you:
Some snippets from conetix.com.au/blog/simple-guide-using-traits-laravel-5
You can use use ExampleCode; in the controller you wish
<?php
namespace App\Traits;
trait ExampleCode
{
public function asd()
{
return [1,2,3];
}
}
namespace App\Something;
use App\Traits\ExampleCode;
class Someclass
{
use ExampleCode;
public $yourarray;
public function __construct()
{
$this->yourarray = $this->asd();
}
public function hi(){
dd($this->yourarray);
}
}
If multiple controllers need to have access to the same data, then you may want to consider creating a base controller that they inherit from and setting that data in the constructor of the controller.
Alternatively you can store it in the session and retrieve it from there in the controllers that need it.
Maybe it's better to use decomposition for this purpose. Write some service class for your data, bind it to your service container and then inject it into controllers constructor or action methods.

Use of service providers within controllers in Laravel 5.2

As for the title I've googled about two hours searching for a efficient answer and read repeatedly the official documentation, but without any step further, considering I'm relatively new to the framework. The doubt arise while searching for a correct way to share some code between controllers and i stumbled in service providers, so:
I've created say a MyCustomServiceProvider;
I've added it to the providers and aliases arrays within the app.php file;
finally I've created a custom helpers class and registered it like:
class MyCustomServiceProvider extends ServiceProvider
{
public function boot()
{
//
}
public function register()
{
$this->app->bind('App\Helpers\Commander', function(){
return new Commander();
});
}
}
So far, however, if I use that custom class within a controller I necessarily need to add the path to it through the use statement:
use App\Helpers\Commander;
otherwise I get a nice class not found exception and obviously my controller does not his job.
I suspect there's something which escapes to me on service providers! :-)
So far, however, if I use that custom class within a controller I
necessarily need to add the path to it through the use statement:
`use App\Helpers\Commander;`
otherwise I get a nice class not found
exception and obviously my controller does not his job.
Yes, that's how it works. If you don't want to use the full name, you can use a Facade instead.
Create the Facade class like this:
class Commander extends Facade
{
protected static function getFacadeAccessor() { return 'commander'; }
}
register the service:
$this->app->singleton('commander', function ($app) {
return new Commander();
});
add the alias to your config/app.php:
'aliases' => [
//...
'Commander' => Path\To\Facades\Commander::class,
//...
],
and use it like a Facade:
\Commander::doStuff();
On why your code still works, even when you remove the bind:
When you type-hint a parameter to a function, and Laravel does not know about the type you want (through binding), Laravel will do its best to create that class for you, if it is possible. So even though you didn't bind the class, Laravel will happily create a instance of that class for you. Where you actually need the binding is when you use interfaces. Usually, you'd not type-hint specific classes but a interface. But Laravel can not create a instance of an interface and pass it to you, so Laravel needs to know how it can construct a class which implements the interface you need. In this case, you'd bind the class (or the closure which creates the class) to the interface.

How to use custom Service Providers in Laravel 5.2

I am creating a Laravel app that needs to communicate with a remote (in-house) service via API.
This API needs to be authenticated at least once per session, and after that other calls can work fine.
I think the best way is to use Laravel's service providers to do this, but I'm open to other solutions.
What I would like:
What I would like is a way to have this Service available for use whenever. I don't want to have to put the service in the parameters of a controller's method if I can avoid it. Something like this:
use MyServiceProvider;
class SomeController extends Controller
{
public function someMethod ()
{
MyServiceProvider::method();
}
}
I can post what I've started doing thus far, if needed - but I'd rather focus on doing what I want rather than fixing what I did wrong.
inb4: I did read the docs.
What you're trying to do is create a Facade. Facades are very similar to using dependency injection, except that they can be used globally without specific injection. Docs: https://laravel.com/docs/5.0/facades#creating-facades
In your service provider:
App::bind('foo', function()
{
return new \MyServices\Foo; //returns a concrete class
});
Foo.php
use Illuminate\Support\Facades\Facade;
class Foo extends Facade {
protected static function getFacadeAccessor() { return 'foo'; } //matches binding in SP
}
Now your service provider is available as Foo anywhere, even without explicitly injecting it:
use Foo;
class SomeController extends Controller
{
public function someMethod ()
{
Foo::method(); //creates a Foo object according to App::bind, then calls method();
}
}

Lumen (Laravel) include library & use class in Controller

I have a question! I have a library, whenever I need to call, I'll include it into & new Class() like the link below.
Now, I want to include it to use with Lumen framework & call usually inton Controller, then how to register service, class in Lumen to make it comfortable so that when needing, just call new FileMaker();
http://laravel.io/bin/E3d9x
Thank you so much!
What you're looking for is a Service Provider. Instead of including files in your Controllers, and then new'ing up instances of a class it is better to register the class within a service provider and then resolve the object out of the IoC container.
An example of how you can register a provider:
public function register()
{
$this->app->singleton('Full\Vendor\Namespace\FileMaker', function($app) {
return new FileMaker('someparameters');
});
}
Doing it this way means that you can inject dependencies into your Controllers and Laravel, or Lumen in this case will automatically resolve the object without you needing to instantiate the object.
For example, in your controller:
public function someControllerMethod(FileMaker $filemaker)
{
// The $filemaker instance is available to use
}

How to extend Laravel's Auth Guard class?

I'm trying to extend Laravel's Auth Guard class by one additional method, so I'm able to call Auth::myCustomMethod() at the end.
Following the documentation section Extending The Framework I'm stuck on how to exactly do this because the Guard class itself doesn't have an own IoC binding which I could override.
Here is some code demonstrating what I'm trying to do:
namespace Foobar\Extensions\Auth;
class Guard extends \Illuminate\Auth\Guard {
public function myCustomMethod()
{
// ...
}
}
Now how should I register the extended class Foobar\Extensions\Auth\Guard to be used instead of the original Illuminate\Auth\Guard so I'm able to call Auth::myCustomMethod() the same way as e.g. Auth::check()?
One way would be to replace the Auth alias in the app/config/app.php but I'm not sure if this is really the best way to solve this.
BTW: I'm using Laravel 4.1.
I would create my own UserProvider service that contain the methods I want and then extend Auth.
I recommend creating your own service provider, or straight up extending the Auth class in one of the start files (eg. start/global.php).
Auth::extend('nonDescriptAuth', function()
{
return new Guard(
new NonDescriptUserProvider(),
App::make('session.store')
);
});
This is a good tutorial you can follow to get a better understanding
There is another method you could use. It would involve extending one of the current providers such as Eloquent.
class MyProvider extends Illuminate\Auth\EloquentUserProvider {
public function myCustomMethod()
{
// Does something 'Authy'
}
}
Then you could just extend auth as above but with your custom provider.
\Auth::extend('nonDescriptAuth', function()
{
return new \Illuminate\Auth\Guard(
new MyProvider(
new \Illuminate\Hashing\BcryptHasher,
\Config::get('auth.model')
),
\App::make('session.store')
);
});
Once you've implemented the code you would change the driver in the auth.php config file to use 'nonDescriptAuth`.
Only way to add (and also replace existing functions) is to create copy of Guard.php file in your project and in app/start/global.php add:
require app_path().'/models/Guard.php';
Of course it's ugly method, but I spent over hour to test all possibilities [how to change things stored in Session by Auth] and it always end with error:
... _contruct of class HSGuard requires first parameter to be 'UserProviderInterface' and get 'EloquentUserProvider' ...

Categories