How to share scopes between classes in Laravel 5 - php

I have several Laravel models which have the same functionallity.
I'm trying to implement some sort of ::All() functionallity but with another logic behind it.
For example: all my models have an "Active" boolean flag, which means that I get all of my languages like: $language = Language::where('active', 1)->orderBy('name')->get();. The same goes for hobbies, semesters, etc.
I'm trying to do something like this in my base_model from which all other models extend:
public static function getActive()
{
return this::where('active', 1)->orderBy('name')->get();
}
this would save me lots and lots of redundant code, but as a newbie I'm struggling with the code.
How can I dynamically define the Model I want to retrieve?
Any ideas?

You can use Laravel query scopes for this. For example:
//your base model
class BaseModel extends Model
{
//every class inheriting from this will have this scope
public function scopeActive($query)
{
return $query->where('active', 1)->orderBy('name')->get();
}
}
//your child models will inherit the scope from the parent class
class Language extends BaseModel
{
//your model's methods
}
//use the scope to get all the active languages
$languages = Language::active();

Related

Laravel way to add a column value on all models like created_at

I need to add a column to some of my database tables and populate that on Model::create().
All I want is functionality like Laravel built in timestamps i.e created_at and updated_at
I know of some solutions but I wanted to know if something else could be done in such case.
For example:
protected static function booted()
{
static::created(function ($user) {
//
});
}
OR
class UserObserver
{
public function creating(User $user)
{
//
}
}
I will need to do that for every model which is repeating myself.
Another solution that comes to my mind is creating a BaseModel and then extend everything from that.
I wanted to do something like we have in SoftDeletes trait, Add whatever logic inside of that and populate that column using some laravel hook that I am not aware of. If someone can guide me to accomplish such thing using traits and HOW?
You can extend all your models off of a base model class (a small refactor), and then in that class add a booted method with your custom logic.
If you then need (or already have) extra logic in a model (say the user model) that uses the booted method, you can still keep that, but make sure you call parent::booted();
class BaseModel extends Model {
protected static function booted()
{
static::created(function ($model) {
//logic
});
}
}
class User extends BaseModel {
protected static function booted()
{
parent::booted();
//any other logic you may have/want in user
}
}
This is in my opinion the most scalable approach. Make use of OOP! You can also then reuse this base class for other global logic in the future.

Get the calling object from superclass

I've built a "model" superclass for a MVC framework. In most methods i do need only the class name so i've used get_called_class() but for save and edit methods i need to pass the object with values.
In my design, when you create a model object and you save or edit you have to do:
$object->save($object); or $object->update($object, $id).
I really don't like this, because looks as a bad design. I would like just to say:
$object->save(); and $object->update($id);
Since you are effectively saving the current object.
Models classes extends a Model parent that defines their behaviour and create the DB connection for them.
The methods of superclass that i would like to make does not take as an argument $object but rather i would like to say "get the calling object".
public function save($object) {
return self::$db->save($object);
}
public function update($object,$id) {
return self::$db->update($object, $id);
}
I know that this can be easily doable the in the object model with
public function save () {
parent::save($this);
}
But i would like not to have to reimplement this behaviour for every single model!
Thank you in advance.
The use of any existing ORM library isn't discussed here, since i want to provide a querybuilder and simple ORM that is PDO based as default. Because i do not want to have any 3rd party dependency as default
Define your base model as abstract class and inherit default behavior to child model classes.
abstract class Model
{
public function save() {
return self::$db->save($this);
}
public function update($id) {
return self::$db->update($this, $id);
}
}
class UserModel extends Model;
$myModel = new UserModel();
$myModel->save();

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

Would PHP traits be a good solution

I'm working on a MVC application in which the Model is implemented using an abstract base class that all actual models have to extend. In every model there is some info about that model, currently implemented as an array, let call that protected static $info. So, every model has a different $info array. Now, the base class has lots of functions that use data from that array, and at the moment every one of those functions starts with something like the example save() function below.
abstract class BaseModel {
function save(){
$className = get_called_class();
$modelInfo = $className::$info;
/* lots of other stuff */
}
}
class User extends BaseModel {
protected static $info = array("tableName" => "tblUsers", etc...)
}
In my understanding, this can be resolved by making the BaseModel a trait instead of a constructor, since when traits define static properties, each inheriting class does have their own values. I would copy the $info array from the implementation of the Model to the trait, probably in the constructor, so that I can use self::info['tableName'] in all the functions in the BaseModel...
Would this be a good idea?
The simplest and most appropriate tool for the job would be to use late static binding:
function save(){
$modelInfo = static::$info;
/* lots of other stuff */
}

Is it possible to dynamically extend a model in Codeigniter?

my models in CI are set up so that they load "sub"-models whenever they need certain functions. In order to keep my code as accessible and clean as possible, I want those submodels to extend the model they are called to.
So if I have two models:
<?php
class Mymodel extends Model
{
}
And:
<?php
class Submodel extends Model
{
function test() { do something.. }
}
Then I need to, somehow, be able get the submodel to extend mymodel, so that I can do something like $this->mymodel->test(). It doesn't have to be mymodel that submodel extends, it could be any model. Any ideas?
Thanks for your time.
You have an incorrect understanding of inheritance between classes.
Inheritance only flows one way, Down.
if Myodel extends Submodel your $this->mymodel->test() would work, but it does not make sense as sub (child) objects are suppose to inherit from parent objects, not the other way around.
As an analogy, you wouldn't look at a child and tell the parent, "You look just like your child", because it is the child that is a part representation of the parent.
you need to take the word extends very literally, you are literally 'extending' the functionality of the parent.
===================
One way i believe you could accomplish this is to create ghost functions that simply load the proper model and call that models function (though I do not recommend this as it could get very confusing for debugging.
per your example
<?php
class Mymodel extends Model
{
function test() {
$this->load->model('submodel');
$this->submodel->test();
}
}
Submodel
<?php
class Submodel extends Model
{
function test() { do something.. }
}
BUT again, if you are going for clean code, this is NOT the way to go, try and observe inheritance, and design your data with that in mind.
You can create utility model which may extends codeigniter's model and then all your models can extend that utility model. The methods you are going to add to the utility model will be available to all it's child classes aka your models.
How can you call a method which your class does not have or does not inherit from any other classes? Looking at your code, there is no relationship in your classes between Mymodel and Submodel.

Categories