Why use static method in PHP's laravel model class? - php

In PHP laravel, we have codes like
$user = User::find(1);
var_dump($user->name);
I am not concerning how to use the find method, I am concerning why laravel use a static method? Shouldn't the use of static method make the method hard to test?
Will it be better if they designed using singleton?
e.g.
$user = User::getInstance()->find(1);
var_dump($user->name);

In fact, your example is very similar to what Laravel does behind the scene. When you do User::find(), you are actually asking for a new instance, either an instance of Collection or a QueryBuilder.
Illuminate\Database\Eloquent\Model (reference):
public static function find($id, $columns = array('*'))
{
if (is_array($id) && empty($id)) return new Collection;
$instance = new static;
return $instance->newQuery()->find($id, $columns);
}
As a side note, you'll also see another way of using static methods in Laravel e.g. Input::get(). These are called Facades.
Facades provide a "static" interface to classes that are available in the application's IoC container ... Laravel "facades" serve as "static proxies" to underlying classes in the IoC container, providing the benefit of a terse, expressive syntax while maintaining more testability and flexibility than traditional static methods.
When a user references any static method on the ... facade, Laravel resolves the cache binding from the IoC container and runs the requested method (in this case, get) against that object.
You can read more about Larave's Facades at: http://laravel.com/docs/facades

Unnawut has a very good answer, however I felt it necessary to add in further explanation.
In your example
$user = User::find(1);
var_dump($user->name);
Laravel isn't using a static method, you are. Another way to do this which you are probably looking for is to use dependency injection, which Laravel makes very easy because it can be done automatically. So in whatever class you are using your User model in, you should be setting up something like this in the constructor...
public function __construct(User $user)
{
$this->user = $user;
}
And then you can modify your code to not use the static bindings.
$user = $this->user->find(1);
var_dump($user->name);

This would restrict the system from only having one User. Whilst the find method may be static, the User class will have other methods and properties that aren't, a likely example is in your example: $user->name
A method that does not rely upon any instance variables, I.e variables who's value is specific to the particular object instance, but instead provides generic functionality that applies to all instances, can, and probably should, be static. This is why the $this operator is illegal within static methods, as it can make no reference to a particular object instance.

#unnawut reference link to the source code of Model.php is no longer using static find function as the class has been refactored. The function that get called eventually is in Builder.php (source code),
The logic still same
- magic function `__callStatic` of Model class get called
- a new instance of Builder is created and return
- call the find method of the Builder instance
Model.php
public function newEloquentBuilder($query)
{
return new Builder($query);
}
Builder.php
public function find($id, $columns = ['*'])
{
if (is_array($id) || $id instanceof Arrayable) {
return $this->findMany($id, $columns);
}
return $this->whereKey($id)->first($columns);
}

Related

How $this->app->singleton() works in laravel?

In my laravel project I have following interface, repository and controller.
This is Interface
interface TrainingClassTypeInterfaces
{
public function updateTrainingClassType($id, $request);
}
This is Repository
use App\Models\Trainings\AppTrainingClassType;
class TrainingClassTypeEloquent implements TrainingClassTypeInterfaces
{
protected $model;
public function __construct(AppTrainingClassType $appTrainingClassType)
{
$this->model = $appTrainingClassType;
}
public function updateTrainingClassType($id, $request)
{
$response = false;
$isUpdated = $this->model::where('training_class_id',$id)->update([
'app_id' => $request->app_id
]);
....
}
}
This is controller
class TrainingClassTypesController extends \TCG\Voyager\Http\Controllers\VoyagerBaseController
{
protected $trainingService;
public function __construct(TrainingClassTypeEloquent $trainingClassTypeInterfaces) {
$this->trainingService = $trainingClassTypeInterfaces;
}
public function insertOrUpdate()
{
...
$this->trainingService->updateTrainingClassType($id, $request);
..
}
}
Everything working fine till here
As you can see I am using TrainingClassTypeEloquent's method inside TrainingClassTypesController. But it was returning error something like
Argument 1 passed to ...::__construct() must be an instance of
Basically it was asking me to put instance of Model into TrainingClassTypeEloquent class. Then I did as following
$TCTypes = new AppTrainingClassType();
$TCT = new TrainingClassTypeEloquent($TCTypes);
$TCT->updateTrainingClassType($id, $request);
which was working fine but I was confused that this approach is not proper, there should be some proper way.
After googling I found another solution which is singleton binding, and then I tried following in AppServiceProvider
$this->app->singleton(
\App\Services\Voyager\Eloquent\TrainingClassType\TrainingClassTypeInterfaces::class,
\App\Services\Voyager\Eloquent\TrainingClassType\TrainingClassTypeEloquent::class
);
After adding this singleton binding, I notice script was working without providing model instance into TrainingClassTypeEloquent class.
I would like to know how $this->app->singleton() is working, so in this way my concept would be clear about it. If someone knows then kindly guide me about it.
Thank you so much
It is all about BINDING a service to the service container.
What does $this->app->singleton(); method do?
The singleton method binds a class or interface into the service container so that Laravel can maintain dependency (when using an interface as the constructor parameter).
(Actually Singleton is a design pattern. Singleton implementation always returns the same object on subsequent calls instead of a new instance). So $this->app->singleton(); method returns the same object again and again.
Point to be noted that Laravel doc says:
There is no need to bind classes into the container if they do not
depend on any interfaces. The container does not need to be instructed
on how to build these objects, since it can automatically resolve
these objects using reflection.
But your controller class depends on an interface, so the container needs to be informed and to do this, you need to use this $this->app->singleton(); method but there are other ways around.
Again, at the same time, this TrainingClassTypeEloquent::class has a dependency of AppTrainingClassType::class. But in this case, we do not need to worry about that because Laravel uses Reflection API to maintain its dependency as this class does not use interface as like TrainingClassTypesController::class class.
Once you are done with binding the service to the container, Laravel will then automagically put the service onto the constructor method as an argument where the interface is used.
I hope this would help you. You may find more help from this answer.
You need to register TrainingClassTypeEloquent
$this->app->singleton(TrainingClassTypeInterfaces::class, static function ($app) {
return new TrainingClassTypeEloquent(new AppTrainingClassType());
});
Then you can inject it in your Controller
public function insertOrUpdate(TrainingClassTypeInterfaces $trainingService, $id)
{
$trainingService->updateTrainingClassType($id, request());
}

How facades work in laravel? How the methods can be accessed with ::

I read about Facade Pattern
The facade pattern (also spelled façade) is a software design pattern commonly used with object-oriented programming. The name is an analogy to an architectural façade. A facade is an object that provides a simplified interface to a larger body of code, such as a class library.
But in Laravel all the Facade Classes methods are accessed via the ::(Scope Resolution Operator) even though the methods are not static at all.
How is this possible? Why PHP is not telling that the method is not static.
for example Auth::user() eventhough the user() method is not static how is is accessible, somewhere the class should be newed up or am I missing something?
The magic happens in Facade's __callStatic function.
public static function __callStatic($method, $args)
{
$instance = static::getFacadeRoot();
if (! $instance) {
throw new RuntimeException('A facade root has not been set.');
}
return $instance->$method(...$args);
}
It first gets the appropriate instance, and then simply invokes the requested method with the given arguments.

Laravel, Dependency Injection, and Eloquent

What the right/best way to use laravel's dependency injection system with multiple-instance objects like CRUD models?
Current fashion in some corners of PHP-land say the following code is "bad"
function someMethod()
{
/* .. stuff ... */
$object = new \App\SomeModel;
$object->some_prop = 'some value';
$object->save();
/* .. other stuff ... */
}
It's bad because this method is now dependent on that new object instantiation. The current fashion says objects ought to be injected via some sort of dependency injection system, like Laravel's automatic constructor dependency injection.
However -- injecting eloquent models seems problematic
/*...*
public function __construct(\App\SomeModel $object)
{
$this->someModel = $object;
}
function someMethod()
{
/* .. stuff ... */
$object = $this->someModel;
$object->some_prop = 'some value';
$object->save();
/* .. other stuff ... */
}
/*...*/
It's not clear if Laravel's automatic constructor dependency injection creates new instances each time, or if the objects injected are single instance objects. It also doesn't handle situations where you want to use Eloquent's static helpers
function someMethod($object_id)
{
//another dependency
\App\SomeModel::find($object_id);
//but this doesn't work
$this->someModel->find($object_id);
}
Is there a generally accepted way to handle this in a Laravel application? Some people say you should inject factories. Other people say repositories. I'd like to know what the general practice is with Laravel developers and if Laravel ships with anything that can help out here (base factory/repository implementations, etc.)
Thanks to some help from the LaraChat Slack I figured this one out on my own.
It turns out that, in addition to automatic constructor dependency injection, Laravel has a special form of dependency injection that works with any of a router's callback methods/functions.
Consider this code sample
Route::get('api/users/{user?}', function (App\User $user) {
return $user->email;
});
If you setup your route string with a variable ({user}), Laravel will scan your route handler's (above, an anonymous function, but it works with controller methods as well) parameters for a type hint whose short class name matches the variable name (App\User above). If found, instead of passing in the parameter from URL, Laravel will instantiate a loaded Eloquent object. If an optional parameter is ommited, you'll get a blank object of the specified type.
This extensive discussion of Laravel DI is great. Covers the use of classes and interfaces and more. Best reference I've found.
https://gist.github.com/davejamesmiller/bd857d9b0ac895df7604dd2e63b23afe
Laravel has a powerful Inversion of Control (IoC) / Dependency Injection (DI) Container. Unfortunately the official documentation doesn't cover all of the available functionality, so I decided to experiment with it and document it for myself. The following is based on Laravel 5.4.26 - other versions may vary.
I had a bit of a play with this (no serious testing) and it looks like it's possible - in fact, I rather like it doing it this way, and look to it in the future. Sample (untested) below:
use App/Models/Foo;
class FooController {
private $model;
public function __construct(Foo $model)
{
$this->model = $model;
}
public function show(Request $request, $id)
{
$foo = $this->model->where($this->model->getKeyName(), '=', $id)->first();
dd($foo);
}
public function store(Request $request)
{
$foo = $this->model->newInstance();
$foo->bar = $request->get('baz');
$foo->save();
}
}
The find helpers that are on the eloquent facades, such as find, are nice, but essentially under the hood they are a standard where(...)->get()->first().

Dependency Injection Container: Multiple instances of a single class

I am just starting with Dependency Injection Containers, and I am having a problem that makes my code messy. Let's take an example: I have a simple Container class that manages multiple services, a service can be "marked" as shared so it can only make one single instance.
So for example, I will make a simple (It's not the one I actually use) dependency injection container for, let's say, a User class, I would do so:
class Container
{
protected $parameters;
public function set($index, $value)
{
$this->parameters[$index] = $value;
}
public function getUser()
{
return new User($this->paramaters['id'], $this->parameters['nickname']);
}
}
$container = new Container();
$container->set('id', 1);
$container->set('nickname', 'Bob');
$container->getUser();
This works fine. But now, here is an other case: Let's say that now, instead of a User class, I want a Post class, for each post, I will need to set their title, text and date in the constructor, and each post shouldn't have the same parameters. In this case, is an dependency injection container adapted, if so, how should I achieve it without having a mess of a code?
Edit:
Will asked me my use case:
In my use case, I am actually doing this with a Router class that need to use Route instances. Each instantiated Route need to be passed two arguments: the pattern and the callback. So each time I ask my container to create a Route instance, it shouldn't use for all Routes the same pattern and callback, but a new pair of them (pattern + callback). How should I do so?
Your goal here is to create a Shared Abstraction which can be injected into the code that depends on its data. There's two approaches you can take, and I think you're mixing the two already.
A Generic Dependency-Injection Container - In this case, we make a very generic object that can store and retrieve other objects. An example is here:
<?php
class Container
{
protected $dependencies = array();
public function get($key)
{
return isset($this->dependencies[$key]) ? $this->dependencies[$key] : null;
}
public function register($key, $value)
{
$this->dependencies[$key] = $value;
}
}
You can then use the container like this:
$container = new Container();
$container->register('user', new User(1, 'Bob'));
$container->register('somethingElse', new SomethingElse(42));
And then you can just pass $container to another function, method, or object, where you can do:
$user = $container->get('user');
There are also many Open Source containers you can use like Pimple, or PHP-DI.
A Domain-Specific Shared Abstraction - Another approach is to make a specific shared abstraction, like, in your case, a UserPost perhaps:
<?php
class UserPost
{
protected $user;
protected $post;
public function __construct(User $user, Post $post)
{
$this->user = $user;
$this->post = $post;
}
public function getUser()
{
return $this->user;
}
public function getPost()
{
return $this->post;
}
}
You can then simply inject the UserPost and call $userPost->getUser() / $userPost->getPost(). The second method here is basically as simple as coming up with a name for the combination of data items you wish to pass. I prefer this approach, as it makes the code more readable, but this is a matter of opinion. I prefer to have my classnames correspond to "what I think of this object as" in plain English. This also aligns more closely with the core-OO principals of abstraction, in my opinion. But, the generic containers in Option 1 is an approach used successfully by many.

Dependency Injection: pulling required components when they are actually needed

The gist behind DI is to relieve a class from creating and preparing objects it depends on and pushing them in. This sounds very reasonable, but sometimes a class does not need all the objects, that are being pushed into it to carry out its function. The reason behind this is an "early return" that happens upon invalid user input or an exception thrown by one of the required objects earlier or the unavailability of a certain value necessary to instantiate an object until a block of code runs.
More practical examples:
injecting a database connection object that will never be used, because the user data does not pass validation (provided that no triggers are used to validate this data)
injecting excel-like objects (PHPExcel e.g.) that collect input (heavy to load and instantiate because a whole library is pulled in and never used, because validation throws an exception earlier than a write occurs)
a variable value that is determined within a class, but not the injector at runtime; for instance, a routing component that determines the controller (or command) class and method that should be called based on user input
although this might be a design problem, but a substantial service-class, that depends on a lot of components, but uses only like 1/3 of them per request (the reason, why i tend to use command classes instead of controllers)
So, in a way pushing in all necessary components contradicts "lazy-loading" in the way that some components are created and never used, that being a bit unpractical and impacting performance. As far as PHP is concerned - more files are loaded, parsed and compiled. This is especially painful, if the objects being pushed in have their own dependencies.
i see 3 ways around it, 2 of which don't sound very well:
injecting a factory
injecting the injector (an anti-pattern)
injecting some external function, that gets called from within the
class once a relevant point is reached (smtg like "retrieve a
PHPExcel instance once data validation finished"); this is what i
tend to use due to its flexibility
The question is what's the best way of dealing with such situations / what do you guys use?
UPDATE:
#GordonM here are the examples of 3 approaches:
//inject factory example
interface IFactory{
function factory();
}
class Bartender{
protected $_factory;
public function __construct(IFactory $f){
$this->_factory = $f;
}
public function order($data){
//validating $data
//... return or throw exception
//validation passed, order must be saved
$db = $this->_factory->factory(); //! factory instance * num necessary components
$db->insert('orders', $data);
//...
}
}
/*
inject provider example
assuming that the provider prepares necessary objects
(i.e. injects their dependencies as well)
*/
interface IProvider{
function get($uid);
}
class Router{
protected $_provider;
public function __construct(IProvider $p){
$this->_provider = $p;
}
public function route($str){
//... match $str against routes to resolve class and method
$inst = $this->_provider->get($class);
//...
}
}
//inject callback (old fashion way)
class MyProvider{
protected $_db;
public function getDb(){
$this->_db = $this->_db ? $this->_db : new mysqli();
return $this->_db;
}
}
class Bartender{
protected $_db;
public function __construct(array $callback){
$this->_db = $callback;
}
public function order($data){
//validating $data
//... return or throw exception
//validation passed, order must be saved
$db = call_user_func_array($this->_db, array());
$db->insert('orders', $data);
//...
}
}
//the way it works under the hood:
$provider = new MyProvider();
$db = array($provider, 'getDb');
new Bartender($db);
//inject callback (the PHP 5.3 way)
class Bartender{
protected $_db;
public function __construct(Closure $callback){
$this->_db = $callback;
}
public function order($data){
//validating $data
//... return or throw exception
//validation passed, order must be saved
$db = call_user_func_array($this->_db, array());
$db->insert('orders', $data);
//...
}
}
//the way it works under the hood:
static $conn = null;
$db = function() use ($conn){
$conn = $conn ? $conn : new mysqli();
return $conn;
};
new Bartender($db);
I've been thinking about this problem a lot lately in planning of a major project that I want to do as right as humanly possible (stick to LoD, no hard coded dependencies, etc). My first thought was the "Inject a factory" approach as well, but I'm not sure that's the way to go. The Clean Code talks from Google made the claim that if you reach through an object to get the object you really want then you're violating the LoD. That would seem to rule out the idea of injecting a factory, because you have to reach through the factory to get what you really want. Maybe I've missed some point there that makes it okay, but until I know for sure I'm pondering other approaches.
How do you do the function injection? I'd imagine you're passing in a callback that does the instantiation of the object you want, but a code example would be nice.
If you could update your question with code examples of how you do the three styles you mentioned it might be useful. I'm especially keen to see "injecting the injector" even if it is an antipattern.
One idea that did occur was that of a proxy object. It implements the same interface(s) as the actual object you want to pass in, but instead of implementing anything it just holds an instance of the real class and forwards method calls on to it.
interface MyInterface
{
public function doFoo ();
public function isFoo ();
// etc
}
class RealClass implements MyInterface
{
public function doFoo ()
{
return ('Foo!');
}
public function isFoo ()
{
return ($this -> doFoo () == 'Foo!'? true: false);
}
// etc
}
class RealClassProxy implements MyInterface
{
private $instance = NULL;
/**
* Do lazy instantiation of the real class
*
* #return RealClass
*/
private function getRealClass ()
{
if ($this -> instance === NULL)
{
$this -> instance = new RealClass ();
}
return $this -> instance;
}
public function doFoo ()
{
return $this -> getRealClass () -> doFoo ();
}
public function isFoo ()
{
return $this -> getRealClass () -> isFoo ();
}
// etc
}
Because the proxy has the same interface as the real class, you can pass it as an argument to any function/method that type hints for the interface. The Liskov Substitution Principle holds for the proxy because it responds to all the same messages as the real class and returns the same results (the interface enforces this, at least for method signitures). However, the real class doesn't get instantiated unless a message actually gets sent to the proxy, which does lazy instantiation of the real class behind the scenes.
function sendMessageToRealClass (MyInterface $instance)
{
$instance -> doFoo ();
}
sendMessageToRealClass (new RealClass ());
sendMessageToRealClass (new RealClassProxy ());
There is an extra layer of indirection involved with the proxy object, which obviously means that there is a small performance hit for every method call you make. However, it does allow you to do lazy instantiation, so you can avoid instantiating classes you don't need. Whether this is worth it depends on the cost of instantiating the real object versus the cost of the extra layer of indirection.
EDIT: I had originally written this answer with the idea of subclassing the real object so you could use the technique with objects that don't implement any interfaces such as PDO. I had originally thought that interfaces were the correct way to do this but I wanted an approach that didn't rely on the class being tied to an interface. On reflection that was a big mistake so I've updated the answer to reflect what I should have done in the first place. This version does mean, however, that you can't directly apply this technique to classes with no associated interface. You'll have to wrap such classes in another class that does provide an interface for the proxy approach to be viable, meaning yet another layer of indirection.
If you want to implement lazy loading you basically have two way to do it (as you have already written in the topic):
instead of injecting an instance of object you might need, you inject a Factory or a Builder. The difference between them is that instance of Builder is made for returning one type of object (maybe with different setups), while Factory makes different types of instances ( with same lifetime and/or implementing same interface ).
utilize anonymous function which will return you an instance. That would look something like this:
$provider = function() {
return new \PDO('sqlite::memory:');
};
Only when you call this anonymous function, the instance of PDO is created and connection to database established.
What I usually do in my code is combine both. You can equip the Factory with such provider. This, for example, lets you have a single connection for all the objects which where created by said factory, and the connection is create only, when you first time ask an instance from Factory.
The other way to combine both methods (which i have not used, though) would be to create full blow Provider class, which in constructor accepts an anonymous function. Then the factory could pass around this same instance of Provider and the expensive object (PHPExcel, Doctrine, SwiftMailer or some other instance) is only created once a Product from that Factory first time turns to the Provider (couldn't come up with better name to describe all objects created by same factory) and requests it. After that, this expensive object is shared between all Products of Factory.
... my 2 cents
I chose lazy-injection (i.e. injecting a Proxy class):
class Class1 {
/**
* #Inject(lazy=true)
* #var Class2
*/
private $class2;
public function doSomething() {
// The dependency is loaded NOW
return $this->class2->getSomethingElse();
}
Here, the dependency (class2) is not injected directly: a proxy class is injected. Only when the proxy class is used that the dependency is loaded.
This is possible in PHP-DI (dependency injection framework).
Disclaimer: I work in this project

Categories