Polymorphic relation in Eloquent ORM (Laravel) - laravel

I am trying to achieve an inheritance by using polymorphic relations in Eloquent ORM.
My model schema looks like this:
class Section extends Model {
public function blocks() { // section has many blocks }
}
abstract class Block extends Model {..}
class Exercise extends Block {..}
class Info extends Block {..}
So in my case Section has an array of blocks (and each element could be Exercise or Info).
I tried to tell Eloquent that Section.blocks is an hasMany relation to Block, and Block is morphedTo by it's blockable relation to Exercise or Info, but i failed (and it also doesn't seem like a proper way to do it, because it creates one additional property like $section->blocks[0]->blockable, which should be $section->blocks[0] ).
I also tried to morphTo from Section.blocks right away, but also failed.
Maybe somebody already achived that, and could point me towards right direction.

The question is a little vague but your models should be like below. If there are any difference then add exact errors you get when you fail.
class Section extends Model {
public function blocks() {
return $this->morphTo();
}
}
class Exercise extends Block {
public function sections() {
return $this->morphMany('App\Section', 'blocks');
}
}
class Info extends Block {
public function sections() {
return $this->morphMany('App\Section', 'blocks');
}
}

Related

Simple use of Fouladgar's Eloquent Builder class return error "it is not an interface"

I am having a problem creating a simple filter to use the Eloquent Builder class. Returns me the error
App\EloquentFilters\Property\RoomsFilter cannot implement Fouladgar\EloquentBuilder\Support\Foundation\Contracts\Filter - it is not an interface
basically copied and pasting from how to get started
<?php
namespace App\EloquentFilters\Property;
use Fouladgar\EloquentBuilder\Support\Foundation\Contracts\Filter;
use Illuminate\Database\Eloquent\Builder;
class RoomsFilter implements Filter
{
public function apply(Builder $builder, $value): Builder
{
return $builder->where('rooms', $value);
}
}
Thanks guys for the help
You need to extend it, not implement it, as the error is saying.
Change:
class RoomsFilter implements Filter
{ }
to
class RoomsFilter extends Filter
{ }
From the gitHub repo:
Writing a filter is simple. Define a class that extends the Fouladgar\EloquentBuilder\Support\Foundation\Contracts\Filter abstract class. This class requires you to implement one method: apply.

How to write a custom function in a model?

There is a model data:
class Order extends Model
{
}
How to write a custom method inside the Order class so that it can be called in constructor like this:
Order::myMethod()
Order->myMethod()
Where myMethod is:
public function myMethod() {
return DB::query(<SQL QUERY>);
}
Purpose is to move SQL queries inside model's class, that don't mess this code in controllers.
Rather create a custom function in Model, You can use traits to achieve the desired output.
Please follow either steps:-
https://medium.com/#kshitij206/traits-in-laravel-5db8beffbcc3
https://www.conetix.com.au/blog/simple-guide-using-traits-laravel-5
Guess you are asking about the static functions:
class Order extends Model {
public static function myMethod() {
}
}
and you can call it anywhere like
Order::myMethod();
You can achieve the desired behavior using magic methods __call and __callStatic
if your real method is static you can use __call() to intercept all "non static" calls and use it to call the static and use __callStatic to forward the calls to a new instance to that class .
Your methods should be always static because if a non static method exists and you are calling it statically php raises an error
Non-static method Foo::myMethod() should not be called statically
No problem if your method is static
class Order extends Model {
public static function myMethod() {
return static::query()->where(...)->get(); // example
}
public function __call($name, $arguments) {
return forward_static_call_array([__CLASS__, $name], $arguments);
}
public static function __callStatic($name, $arguments) {
return call_user_func_array([app(__CLASS__), $name], $arguments);
}
}
(new Order())->myMethod();
Order::myMethod();
I can't understand your exact problem is. but if you are using laravel, then you can write custom method inside the ABC model like this
class ABC extends Model
{
//here is your fillable array;
public function abc()
{
//Here is your Eloquent statement or SQL query;
}
}
just call this abc() method inside the controller like this
use ABC;
class AbcController extends Controller
{
private $_abc; // it is private variable
// this is constructor
public function __construct(ABC $abc)
{
$this->_abc= $abc;
}
public function abcMethod()
{
$this->_abc->abc();
}
}
Thanks
I don't believe I'm understanding your intention. You've stated:
Purpose is to move SQL queries inside model's class, that don't mess this code in controllers.
Why does the Order->myMethod() need calling inside the constructor? If you're trying to design your data access layer to work efficiently, you can use data repositories.

Laravel: use extended controller or Traits or something else?

To maintain my Laravel application and save myself from a lot of duplicate code I have made the following solution:
BaseController
class BaseController extends Controller
{
public function get($id){
return $this->baseService->get($id);
}
public function getAll(){
return $this->baseService->getAll();
}
}
BaseService
class BaseService
{
protected $model;
public function __construct($model){
$this->model = $model;
}
public function get($id){
return response()->json($this->model->where('id', $id)->first());
}
public function getAll()
{
return $this->model->get();
}
}
MyController
class MyController extends BaseController
{
protected $model;
protected $baseService;
public function __construct(){
$this->model= new Model();
$this->baseService = new BaseService($this->model);
}
/**
* This controller has all the functionality from BaseController now
*/
}
What I'm wondering if this is a good method. Should I stick with this or should I use a different approach? I've heard about Traits but not sure if they are doing the same thing. It's Laravel 5.5 I'm using.
Yes, traits are used to move methods out of a controller regularly. A good example that the Laravel framework uses is the ThrottlesLogin trait. Take a look at https://github.com/laravel/framework/blob/5.5/src/Illuminate/Foundation/Auth/ThrottlesLogins.php#L20
to see how the methods are moved outside of a controller but can be still accessed by importing the trait using the use keyword.
While traits would work for your use case I wouldn't use them here for the functionality you are looking for. I would use the repository pattern. It would better separate your code and make it more reusable.
Take a look at https://bosnadev.com/2015/03/07/using-repository-pattern-in-laravel-5/ for more information on the repository pattern. Basically, you would separate your code into a separate repository and use Laravel's built in IoC to inject the repository into your controller.
MyController
class MyController extends Controller
{
protected $repo;
public function __construct(MyRepository $myRepository)
{
$this->repo = $myRepository;
}
public function index()
{
$myStuff = $this->repo->all();
}
// you can also inject the repository directly in the controller
// actions.
// look at https://laravel.com/docs/5.5/controllers#dependency-injection-and-controllers
public function other(MyRepository $repo)
{
$myStuff = $repo->all();
}
}
This is the perfect use case for a Trait. Traits are intended for reusable functions. They're super simple to implement, and won't take more than a few minutes to change what you have.
Here is a great article on them: https://www.conetix.com.au/blog/simple-guide-using-traits-laravel-5

Extending Eloquent Models in Laravel (use different tables)

I’m building a Laravel application that involves tracking different types of leads. For example, there are Refinance leads and Purchase leads.
Since the leads share a lot of information and functionality, but not all, my thinking was to create a Lead class, which extends Laravel’s Model class, and then a RefinanceLead class, which extends the Lead class.
So I’d have:
class Lead extends Model
{
// shared lead stuff
}
class RefinanceLead extends Lead
{
// stuff specific to refinance leads
}
My questions are:
Does this strategy make sense?
If it does, how is Eloquent going to handle the data? Will I have a leads table and a refinance_leads table?
Will a new instance of the RefinanceLead class utilize anything in the leads table?
I’ve had trouble answering this question via the documentation, but if I missed where this is explained, please let me know. Thanks.
1. Yes, it makes perfect sense to have all the common functionality in a parent model.
2. Basically each Eloquent model will handle the data from its own table defined in the protected $table variable. You can override the parent variable to set a separate table for all the different child models. Laravel Table Names
For example if you use the getId() method on a RefinanceLead instance it will return the id from refinance_lead table. If you use it on a PurchadeLead instance it will retirn the id from purchade_table
class Lead extends Model
{
public function getId() {
return $this->id;
}
}
class RefinanceLead extends Lead
{
protected $table = 'refinance_leads';
}
class PurchaseLead extends Lead
{
protected $table = 'purchase_leads';
}
3. I don't know what are your exact needs, but in general I'll suggest making the Lead class abstract and so you don't associate a table for it. Use it only to separate common functionality, relations, etc...
Of course as it was suggested in the comments, implementing an interface is always a good idea.
abstract class Lead extends Model implements LeadContract
{
// class body
}

Implementing class inheritance in codeigniter

I am confused, again, about implementing OOP in CodeIgniter.
By design, I have two classes, namely Customer and Supplier. Both classes extends a super class I call Institution.
It was not a problem for me when I wrote them using only php (without framework).
class Customer extends Institution {
public function __construct() {
parent::__construct();
}
}
class Supplier extends Institution {
public function __construct() {
parent::__construct();
}
}
class Institution extends DBConnection {
public function __construct() {
parent::__construct();
}
}
class DBConnection {
// do CRUD activities here
}
The questions are:
How do I write them using CI?
Is it as Controller or in Model the best way to implement them? What factors should be considered?
A friend suggested a way I thought a bit hacky, model extends model. I try, if possible, to do it in codeigniter-appropriate way.
Any suggestion will be appreciated.
Well, as it is going to be your domain model entities, it should be models. And there is nothing wrong in having another model class as a base class for model class. So, you'll just need to make your Institution (or DBConnection if you prefer to keep it) class extend CI_Model.

Resources