Autour de Laravel

Heritage de model : Comment utiliser une methode avec plusieurs type d'objet d'injectés

Avatar de Adyllium
Adyllium

Bonjour,

Je souhaiterai un peu d'aide sur un sujet qui commence tout doucement à me courir sur le pavillon.

Donc voilà mon problème:

Je développe un système de gestion d'inventaire et pour une structure de fichiers plus cohérente j'ai décidé d'utiliser des classes héritée au niveau de mes modèles.

Contrétement, j'ai une class abstraite Product dont hérite plusieurs type de produits, à savoir :

  • Voiture
  • Equipement
  • Consommable
  • Virtuel

J'utilise, pour les vues index, yajra/datatables.

Bon, le cadre est posé. Mon problème maintenant c'est l'utilisation de yajra-datatables-html avec cet héritage. En effet, suite à la commande

php artisan datatable:make Product

j'ai un service qui se créer, lequel fais une requete à Eloquent via cette méthode :

    /**
     * Get query source of dataTable.
     *
     * @param \App\Models\Product $model
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function query(Product $model)
    {
        return $model->newQuery();
    }

Seulement, Product en paramètre est insolvable car abstraite...

Ainsi, comment puis-je me dépatouiller afin que cette méthode puisse recevoir n'importe quel modèle étandant Product en paramétre afin de générer correctement la requète ?

NOTE : à ma connaissance, les Repositories, les providers et les binding ne peuvent pas m'aider. Il doit pourtant y avoir un moyen non ?

Cordialement

Posté il y a 1 mois
Avatar de nash
nash

Salut,

Tu as une table Product donc un model Product. Tu as certainement des tables pour voiture, equipement, consomable,... Selon ton model de db il suffit de meetre en place de simple relation entre des models. Ton explication n'est pas tres claire. Pose toi les bonnes questions avec ton model object au niveau de l'heritage : Est un ou a un. Une voiture est un Product dans un model pure objet mais dans un model db une voiture est aussi un Product. Dans ce cas un Product a hasmany voiture et inversement voiture a belongTo Product (je me refere uniquement a ceci : php artisan datatable:make Product).

Maintenant si tu veux véritablement rester avec ton model de départ, je ne vois qu'une possiblité c'est une interface .

public method(Interface $monObjetImplemente)
{
    return $monObjetImplemente->MaMethode();
}
Posté il y a 1 mois
Avatar de Adyllium
Adyllium

Salut, et merci.

Non, il n'y a pas de table Products. Enfait j'utilise la classe product ( abstraite ) pour gérer les différent aspects de toutes les classes enfants sans devoir me les retaper.

Donc chaque table illustrant un objet enfant de product porte tous les champs. En revanche les classes sont bien heritées correctement.

Par exemple, voici un equipement :

<?php

namespace App\Models;

use App\Models\Product;
use App\Models\Consumable;
use App\Http\Traits\HasParent;
use Illuminate\Database\Eloquent\Factories\HasFactory;

class Equipment extends Product
{
    use HasFactory;
    use HasParent;
    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'end_waranty_date',
        'buy_date',
        'commissioning_date',
        'buy_price',
        'status_id',
        'owner_id',
    ];

    protected $casts = [
        'end_waranty_date' => 'date',
        'buy_date' => 'date',
        'commissioning_date' => 'date',
    ];

    /**
     * The table associated with the model.
     *
     * @var string
     */
    protected $table = 'equipments';

    public function consumables()
    {
        return $this->belongsToMany(Consumable::class);
    }
}

Voici Product

<?php

namespace App\Models;

use App\Models\Team;
use App\Models\Provider;
use App\Models\ProductType;
use App\Http\Traits\HasChildren;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Factories\HasFactory;

abstract class Product extends Model
{
    use SoftDeletes;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    public $pFillable = [
        'id',
        'designation',
        'product_type_id',
        'team_id',
        'serial',
        'brand',
        'model',
        'ref_lcgb',
        'ref_provider',
        'provider_id',
        'comment',
    ];

    public $pCasts = [
        'attrs' => 'array'
    ];

    public function product_type(){
        return $this->belongsTo(ProductType::class)->withDefault([
            'designation'=>''
        ]);
    }
    public function team(){
        return $this->belongsTo(Team::class)->withDefault([
            'name'=>''
        ]);
    }
    public function provider(){
        return $this->belongsTo(Provider::class)->withDefault([
            'designation'=>''
        ]);
    }

    public function getProductTypeNameAttribute(){
        return ($this->product_type)?$this->product_type->designation:null;
    }
    public function getTeamNameAttribute(){
        return $this->team->name;
    }
    public function getProviderNameAttribute(){
        return $this->provider->name;
    }
}

Et voici la migration de Equipment

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateEquipmentsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('equipments', function (Blueprint $table) {
            $table->id();
            $table->string('designation');
            $table->integer('product_type_id')->nullable();
            $table->integer('team_id')->nullable();
            $table->string('serial')->nullable();
            $table->string('brand')->nullable();
            $table->string('model')->nullable();
            $table->string('ref_lcgb')->nullable();
            $table->string('ref_provider')->nullable();
            $table->integer('provider_id')->nullable();
            $table->date('end_waranty_date')->nullable();
            $table->date('buy_date')->nullable();
            $table->date('commissioning_date')->nullable();
            $table->float('buy_price')->nullable();
            $table->integer('status_id')->default(1);
            $table->integer('owner_id')->nullable();
            $table->string('comment')->nullable();
            $table->softDeletes($column = 'deleted_at', $precision = 0);
            $table->timestamps();

            $table->foreign('product_type_id')->references('id')->on('product_types');
            $table->foreign('team_id')->references('id')->on('teams');
            $table->foreign('provider_id')->references('id')->on('providers');
            $table->foreign('status_id')->references('id')->on('status');
            $table->foreign('owner_id')->references('id')->on('contacts');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('equipments');
    }
}

Le MCD et en FN4 avec dénormalisations

Tout fonctionne parfaitement, sauf que je ne sais pas faire une injection qui puisse porter tout les types de objets instanciés des classes enfants.

Je peux tout à fait réécrire un service de Datatable pour chaques enfants ( c'est d'ailleurs ce que j'ai fais en attendant de trouver une solution ) mais j'aimerai mieux faire un seul service pour tous les objets Enfants de Product :/

Posté il y a 1 mois
Avatar de nash
nash

Je comprends ta problèmatique et ton injection de dependance tu pourras la faire avec une interface. Je t'invite à regarder les repository (comme exemple) qui te permettra de mettre en place ton injection de dependance avec cette meme interface.

Posté il y a 1 mois
Avatar de Adyllium
Adyllium

Je vais regarder ca aujourd'hui ou demain, je te tiens au jus. Merci :)

Posté il y a 1 mois
Avatar de Adyllium
Adyllium

Merci beaucoup, j'ai pris quelques minutes pour faire des tests et tout fonctionne nickel :) je vais préparer un petit commit pour cleaner le code.

Merci beaucoup :D

Posté il y a 1 mois

Vous ne pouvez pas répondre à ce sujet.