To create a flexible controller and to use the IoC of Laravel, one would do the following (say for a table User)
Create interface UserInterface
Create class EloquentUserRepository implements UserInterface
App::bind the interface to the implement
But, then you also create a model User that extends Eloquent, and your EloquentUserRepository then basically calls this model. Other than the provided Eloquent functions, if you create a custom function or relation in User, then you need to create a function in EloquentUserRepository that simply returns that. Isn't that repetitive? Is there a way to directly have the model implement the interface?
Isn't that repetitive?
Yes. Unless you have a specific need - you can run the risk of 'over engineering' or 'over abstracting' your application.
If you dont plan to swap out your 'users' with anything in the future - there is no need to do so much. Just because you "can" do something doesnt mean you "should".
You could just have UserInterface - then your model does
class User extends Eloquent implements UserInterface
and just skip the Repository completely.
Related
I know this has been asked quite a long time.
This was answered at 2012-03-16.
Repository pattern - Why exactly do we need Interfaces?
I never used repository one month ago. I use laravel: Controller, Service, Model, View.
Several months ago, I start to use trait. So many articles talk about interface, ok, one month ago, I start to use repository with interfaces. Now I feels that I'm doing things that seems not necessary.
There is Order model I forgot to draw. And I have to bind interface with repository in RepositoryServiceProvider
public function register()
{
$this->app->bind(RepositoryInterface::class, Repository::class);
$this->app->bind(MemberRepositoryInterface::class, MemberRepository::class);
$this->app->bind(OrderRepositoryInterface::class, OrderRepository::class);
$this->app->bind(OrderItemRepositoryInterface::class, OrderItemRepository::class);
//...
}
Now go back to that question's answer in 2012. Why we need to use interfaces? Because:
public class EmployeeRepositoryEF: IEmployeeRepository
{
public Employee[] GetAll()
{
//here you will return employees after querying your EF DbContext
}
}
public class EmployeeRepositoryXML: IEmployeeRepository
{
public Employee[] GetAll()
{
//here you will return employees after querying an XML file
}
}
public class EmployeeRepositoryWCF: IEmployeeRepository
{
public Employee[] GetAll()
{
//here you will return employees after querying some remote WCF service
}
}
But with the bindings in RepositoryServiceProvider, we can not use these different repositories at the same time. I cannot imaging how. We have to change the bindings. But if so, why not just change the type hint in service layer?
Ok, I saw many articles actually use:
Controller > SomeRepositoryInterface $someRepository > Model
They don't have service layer.
Does it mean, since I have service layer, So I don't need interface?
Controller > SomeService $someService> SomeRepository $someRepository > Model
If we want to change repository, just do:
In SomeService:
use App\Repositories\Abc\SomeRepository;
or
use App\Repositories\Xyz\SomeRepository;
Then
use App\Repositories\Eloquent\Sale\OrderRepository;
use App\Repositories\Eloquent\Sale\OrderItemRepository;
use App\Repositories\Eloquent\Sale\RmaRepository;
use App\Repositories\Eloquent\Member\MemberRepository;
use App\Repositories\Eloquent\Member\MemberGroupRepository;
or
use App\Repositories\MSSQL\Sale\OrderRepository;
use App\Repositories\MSSQL\Member\MemberRepository;
or
use App\Repositories\Oracle\Sale\OrderRepository;
use App\Repositories\Oracle\Member\MemberRepository;
Eloquent can change driver to use mssql or oracle. Then...
use App\Repositories\DbBuilder\Sale\OrderRepository;
use App\Repositories\DbBuilder\Member\MemberRepository;
or
use App\Repositories\RawSql\Sale\OrderRepository;
use App\Repositories\RawSql\Member\MemberRepository;
or
use App\Repositories\AnyOtherKind\Sale\OrderRepository;
use App\Repositories\AnyOtherKind\Member\MemberRepository;
Can someone give me some suggestion?
Because we need a contract for the classes that people create over time. They should implement the same thing, and the customer should be able to use them interchangeably. If you don't have an interface, the next developer might forget implementing some methods and this means bad!
For example we have implemented our repositories to work with MySQL, and we exit the company. After a year, they plan for using something else rather than MySQL, so they have to implement new repositories that are compatible with the previous repositories and this is why we need an interface.
I hope my answer is simple and clear.
To begin with, using Repository pattern is bad with Active Record (which is Eloquent). AR (active record) models already have all the methods to all possible CRUD operations and scopes to encapsulate logic within. Using repositories over them is a good example of overengineering, so I'd recommend not using them at all in Laravel.
When working with DM (data-mapper) models, repositories are used to switch between different databases (like in your example in RepositoryServiceProvider). So, in case there is a need to change database over the project, you just create another implementation of repository for different database type. And again, in Laravel this is already done at query builder level, so you just don't need to do that by yourself.
I have been struggling with this problem for couple of days and I've searched everywhere but couldn't find a logical solution.
I need multiple types of users in my project(admin, customer) because I need completely different backend logic for each type. So I decided to use multi-auth method in laravel(which AFAIK is the best solution for these cases). So I have multiple user classes for each type(and multiple tables in DB) including Admin and User classes. AdminAuth and UserAuth classes manage the Login and Register logic and routes are handled using middlewares.
Up till now there is no problem. The problem is that I need to use a single user class in another classes. For example consider the messaging logic(and there are many many similar use cases):
a Message class Model should have:
protected $fillable = [
'from_id', 'to_id', 'content', 'state'
];
public function sender(){
return $this->belongsTo(**User::class**);
}
public function receiver(){
return $this->belongsTo(**User::class**);
}
...
In the above model, I need to specify the User::class for senders and receivers, which can be either admins or users. So how can I tell Eloquent to use both models. Is it even possible? If not, what is the solution here?
I thought of using a higher level class named Person, for example, to hold the Admin or User object instances, but this way ORM can't manage to retrieve or store users from/in the appropriate tables automatically.
Any Suggestion is greatly appreciated.
I would advise you to use the following guidelines to handle such functionality; create a model for each user type but all of them should have a relationship with Laravel's default user class by keeping the user's id. Also, keep general properties in the user class and specific properties in each sub class, like customer's can have addresses and admins can have phone numbers, while the common things like the username can be kept in the user model. Then you won't need multiply forms for login, when a user logs in, you redirectly accordingly to the user's type in the default user record. Now for your messaging problem, use user the default user model to establish the relationship in messages as you shown above. Then defenping on the user's type, grant him different priviledges or features in the chat.
All about laravel authentication is based on users, but I have deleted the user model and replaced that with a company model, so, basically, I want my users (laravel authentication users) to be companies.
Laravel doesn't like this, it gives me
Type error: Argument 1 passed to Illuminate\Auth\SessionGuard::login() must be an instance of Illuminate\Contracts\Auth\Authenticatable, instance of App\company given, called in /home/dhiraj1site/Desktop/Documents/blog/vendor/laravel/framework/src/Illuminate/Auth/AuthManager.p
This error, and if I import authenticable class as suggested in similar questions. Laravel hates this and gives me a blank page.
I have companies model and a companies table, I want the users to sign up as companies, and login as companies. How should I go about this, I am really confused and stuck on this stage, please help me understand how authentication works (I have read authentication documentation several times) and how should I change 'Users' to 'companies'.
There are a couple of ways to skin this cat zuif. The 'Laravel' way would be to edit the settings in app/config/auth.php
In that file you'll need to change the line: 'model' => 'App\User' to 'model' => 'App\Company'.
The 'gotcha' with Laravel is that you must remember to implement the right interfaces in your new 'user' class, Company:
use Illuminate\Auth\UserInterface;
use Illuminate\Auth\Reminders\RemindableInterface;
class Company extends \Eloquent implements UserInterface, RemindableInterface
{
...
}
Or for newer versions of Laravel, its' just one interface:
use Illuminate\Foundation\Auth\User as Authenticatable;
class Company extends Authenticatable
I've done this before and it worked well for me. You could also get creative with extending the User class, but I think above is what you are hunting for.
HTH
My apologies if this exists already but my search-fu can not find the answer.
I have a composer package, and want to use my model ONLY IF an existing model doesn't exist (or extend the custom model), but I can't seem to figure out how to specify the "use" command properly inside my composer model. Since I won't know the name of the "app" using the package, I can't extend it.
<?php
namespace MyComposer\Package\Models;
use Illuminate\Database\Eloquent\Model;
class MyPackageModel extends Model
{
If I put it as a config option, I can't use that in the extends i.e class MyPackageModel extends config('custom_model_name')
I had thought I should do the check in the ServiceProvider but I can't seem to find the right code to register the proper model name to use in there.
Thanks.
I've done something similar to this before, I believe. But my approach was slightly different. See if it makes sense:
Create a base class in your own package. This will be the fallback
model which will be used if the "local" package (the one consuming
your package) doesn't have it's own version of it;
Create a config file which states which model will be used. The default is the model inside your own package (i.e. the fallback);
After installing and setting up your package, if a user does nothing they will automatically have your base model available. If they wish to override your base model with a custom local version, they can simply extend your base model and alter the model to be used in their config file.
I've also found that sometimes it's useful for the base model to 1) implement an interface that can be checked in your package's logic without relying on a specific class (which, after all, is meant to be overridden, right?); and 2) have most of it's logic inside a trait which the "local" model can use without ever having to extend your model (crucial if the local model already extends some other class for whatever reason).
How you approach the code would very much depend what you plan to do with that model. Say, for example, you have a supporting class that creates media entries in your database. Here's your packages model:
<?php
namespace Namespace\Package;
class Media
{
//...
}
And here's the default config:
<?php
return [
'model' => \Namespace\Package\Media::class,
];
And here's a sample manipulation, where you actually account for the local app to override your own model:
<?php
namespace Namespace\Package;
class MediaManager
{
protected function getModel()
{
$model = config('package.model');
return new $model;
}
public function createMedia($attributes = [])
{
$media = $this->getModel($attributes);
$media->save();
return $media;
}
}
That is to say, you never reference any Media model literally. You do your manipulations via the MediaManager. Of course the logic is very simplistic, but hopefully it's enough to get the bigger picture.
Can I use implements on a model in laravel and if so how can I define a attribute in the $fillable array, If I can't use it with a variable I can just have a interface with a method getBool()?
I have two models both with a attribute in the fillable array called bool i would like to have a function that operation on both of these models.
So how can I create a interface class that I can implement on the models?
I don't really understand your question maybe because of the lingo. However, interface is just a contract definition, it's not designed to add functionality per-se, just structure.
You could use a PHP traits to have shared code between models.
PHP Traits