How to observe all models implementing an interface in Laravel 5.1? - php

I have an audit class which extends the Eloquent Model...
class Audit extends Model {
}
I have an auditable interface...
interface IAuditiable {
public function audit();
}
I have a trait which fulfils the interface and defines the relation between the model and the audit...
trait Auditable {
public function audit(){
return $this->hasMany('Audit');
}
}
I have a model which extends the Eloquent Model implements the interface and uses the trait...
class Post extends Model implements IAuditable {
use Auditable;
}
I'd like to add the functionality in there to create or update an audit whenever the Post model is created or updated. I've solved this by registering an observer on the Post which would catch the 'saved' event and add a new audit.
However, there will eventually be many models using implementing IAuditable and using the Auditable trait.
So, my question is, is it possible to implement an observer which would pick up all 'saved' events for any model which implements the IAuditable interface in Laravel 5.1?

You can try hooking into eloquent events. Do something like this in a service provider:
Event::listen(['eloquent.created: *', 'eloquent.updated: *'], function($model) {
// Check if the model implements your interface (could use class_implements(...)
});
I had to do something very similar to what you're looking to do. This solution isn't perfect because you catch events from every model, but it works well enough.
EDIT: Just noticed this question was asked almost two years ago. Hopefully this helps someone out, though :)

Related

How can I provide hints to PhpStorm to find my Laravel custom query builder methods?

I'm using custom query builders in Laravel like this:
class MyModel extends Model {
public function newEloquentBuilder($query): MyModelQueryBuilder
{
return new MyModelQueryBuilder($query);
}
}
class MyModelQueryBuilder extends Illuminate\Database\Eloquent\Builder {
// various query methods...
}
Because of Laravel's so-called Facades and use of magic methods, PhpStorm cannot find references to the methods in my custom query builder.
I use the barryvdh/laravel-ide-helper package to generate hints for my Models, so their methods are findable and hintable. How can I do the same thing in an easy, maintainable way for my query builder classes?
For example, I'd like to be able to press Command-B while on a query builder method, and get the list of users of that method, for example, as I can with other fully cross-referenced classes.
You'll need to add the class methods to the model using the unofficial #mixin PHPDoc directive. PhpStorm has had support for it for a few years now. A trait is probably the easiest way to do this on multiple models:
/**
* #mixin MyModelQueryBuilder
*/
trait HasCustomBuilder {
public function newEloquentBuilder($query): MyModelQueryBuilder
{
return new MyModelQueryBuilder($query);
}
}
class MyModel extends Model {
use HasCustomBuilder;
}

Extending one model with another model in Laravel

I am pretty new to laravel and currently exploring its concepts. In some videos I saw a concept of models inheritance. I wonder if we can use models relationships in laravel 5.6 then why we need to inherit models. In which case we need to or should inherit models.
eg Base Model:
class User extends Authenticatable
{
}
eg Child Model:
Class UserTypeOne extends User()
{
}
eg Child Model2:
Class UserTypeTwo extends User
{
}
Thanks in advance.
You don't really need to inherit Models like class inherit. You should use Eloquent Relationship instead. Prior to development, you have to do proper database designing.
https://laravel.com/docs/5.6/eloquent-relationships

Laravel 5.1 - Dry on same characteristics models

In my Laravel 5.1 App I have a lot of aux Models with the same structure. I was thinking in the posibility of make one model and controller for using all of them, but I cannot figure how to do.
I explain, all the database aux tables have the fields ID and name, and are made for CRUD operations and for filling the forms all over the App.
Is possible to specify the table on the methods implemented by Laravel? I mean, stablish the table on construct, on get(), etc. This would made the work a much more simple if I could do AuxTable::create("sex") or even in requests like $request->auxtable("studies")->get().
Am I explaining?
you can do it with single model like below in Model class there is a method called setTable($table) which can set the table name you want to use so consider below
use Illuminate\Database\Eloquent\Model;
class AuxTable implements Model {
//other class properties
}
in your controller use the model like below
class SampleController extends BaseController {
public function index() {
$model = new AuxTable;
$model->setTable('sex');
$model->get();
}
}
this should do the trick

Is it a good practice to extend Laravel models more than one layer?

I'm reworking a project on Laravel 5.1
What I realize is that the old classes have become much complicated and do not really follow the 'single responsibility' principle anymore.
So I'm planning to do such:
<?php
class User extends Model
{
}
class SocialUser extends User
{
}
So I have a few questions,
Is it possible to achieve that?
If yes, then does the SocialUser class link back to the same database table which is Users and would it conflict with the User model itself?
Is this all a good design practice at the first place? Or I better make use of traits?
Thank you.
What you’re doing (extending the User model) is perfectly fine, and an approach I use myself in projects.
For example, if an application I’m building has shop-like functionality, then I may create a Customer model that extends my User model, and contains say, order-related relations:
class Customer extends User
{
public function orders()
{
return $this->hasMany(Order::class, 'customer_id');
}
public function worth()
{
return $this->orders()->sum(function ($order) {
return $order->total();
});
}
}
In a recent project, I’ve been working on email campaign functionality and created a Recipient class that extends the User model to add campaign-related methods:
class Recipient extends User
{
public function campaigns()
{
return $this->belongsToMany(Campaign::class, 'recipient_id');
}
}
Because both of these classes extend the User model, I get all of those (and Eloquent) methods:
$customers = Customer::with('orders')->get();
So long as you set the table in your base User model, any classes that inherit it will use that same table, even though the model may be named differently (i.e. Customer, Recipient, Student etc).
IMHO I would go for the Repository pattern. It make's a lot of sense in your situation.
I would do the following:
interface UserRepository {
public function find($id);
public function getAll();
public function create(array $attributes);
public function destroy($id);
//you get the point
}
class CoreUserRepository implements UserRepository
{
//implement the interface rules
}
class SocialUserRepository extends CoreUserRepository
{
//implement the specific logic related to a SocialUser
}
Update
As Mjh described in the comments simply implementing the interface on all UserTypeRepository caused repetition - probably not what you want!
By extending your CoreUser you avoid repetition & maintain a design that will work for your situation.
Although, in your case it could be argued that you are still following SRP because everything in the User model is relating to a user, it's only the type of user which is differing.
Why go for the Repository Pattern?
You are ensuring you have a contractual agreement that all User
Repositories need to implement.
Code is easier to maintain.
Business and data access logic can be tested separately
Should you extend your User model?
Here you are in danger of model pollution. While you can do anything with a model - not everything is a good idea.
Defining relationships on this approach would be a headache due to the confusion caused.

separating relationships and model functions in Laravel

Everytime I'm writing a Laravel model it just gives me a feeling of messy code. I have relationships and other model functions specially when using domain driven design. So I though about separating relationships and functions.
Example I have a User class that extends Eloqeunt:
class User extends Eloquent{}
and inside this class I have register functions and password hashing functions etc. Also, we can declare the relationships so:
class User extends Eloquent{
function post(){
return $this->hasMany('POST');
}
}
For some reason this smells funky to me. My solution was to create a Entities folder and inside create a User folder which will hold 2 files one would be UserRelationship which would hold of the the relationships for this class:
class UserRelationship extends Eloquent{
function post(){
return $this->hasMany('POST');
}
}
and a second which would be the actual User class where I would write all of the functions and this class would extend the UserRelationship class instead of Eloquent:
class User extends UserRelationship{
public static function register($email, $password, $activate_token)
{
$user = new static(compact('email', 'password', 'activate_token'));
$user->raise(new UserWasRegistered($user));
return $user;
}
}
What do you guys think of this approach I am relatively new to all this so I don't know if this is bad practice or to much work for little reward. What do you guys recommend?
For a user model, it is too much work. The easiest way and still a better approach is to define the relationship in the user model. If for example it is a post model where you have relationships for post to "user, comment, reply etc" then you can attempt splitting your relationships

Categories