romulo27's avatar

Laravel with Crud Traits

Guys, I need some help. I have a Product and a template for it, the template of these products may just have a price attached to it. When I create a price for the model I need to check if it already has the price, if it has I redirect it to update. How to make?

0 likes
9 replies
rodrigo.pedra's avatar

Do you have separated models: Product and Price, or is the price a nullable attribute of the Product model?

romulo27's avatar

class VariationsPriceController extends Controller {

    use Read, Retrieve, Create, Update, Delete;

    /**
     * VariationsPriceController constructor.
     * @param ModelRepository $repository
     */
    public function __construct(ModelRepository $repository) {
        $this->repository = $repository;
        $this->context = ContextManagerGroupDictionary::BRAND_MOTORCYCLE_VARIATION;
        $this->resource = 'prices';
        $this->modelNameAttribute = 'name';
        $this->titles = [
            'index' => 'Preços de Variação da Motocicleta',
            'create' => 'Cadastrando Preços',
            'edit' => 'Editando Preços',
        ];
    }

    /**
     * Exibe a tela de registros da Model conforme DataTable da Model
     *
     * @param Request $request
     * @param ModelDataTable $dataTable
     * @return \Illuminate\View\View
     */
    public function index(Request $request, ModelDataTable $dataTable) {

        /* @var $motorcycle Motorcycle */
        $motorcycle = $request->route('motorcycle');
        $brand = $request->route('brand');
        $variation = $request->route('variations');

        $dataTable->addScope(new MotorcycleVariationPriceContextScope(['variations' => $variation]));

        $options = [[
            'button' => 'Novo Preço',
            'url' => route('brand.motorcycle.prices.create', [$brand, $motorcycle, $variation->getRouteKey()])
        ]];

        $this->data['options'] = $options;

        return $this->makeIndex($dataTable);
    }

    /**
     * {@inheritdoc}
     *
     * @throws \Prettus\Repository\Exceptions\RepositoryException
     * @throws \Prettus\Validator\Exceptions\ValidatorException
     *
     */
//    public function create() {
//
//        $this->makeCreate();
//        $this->makeUpdate();
//    }

    /**
     * Operações para serem realizada antes do create da Model.
     *
     * @param Request $request
     * @param $data
     * @return array
     */
    public function beforeStore(Request $request, $data) {

        $data['id'] = $request->route('variation')->getKey();

        return $data;
    }

    /**
     * Retorna a rota para a store.
     *
     * @param Request $request
     * @return array|string
     */
    protected function makeStoreRedirectRoute(Request $request) {

        /* @var $motorcycle Motorcycle */
        $motorcycle = $request->route('motorcycle');
        $brand = $request->route('brand');

        $context = $this->context;

        $route = [ 'brand.motorcycle.variations.index', $brand, $motorcycle];

        return $route;
    }

    /**
     * Retorna a rota para store
     *
     * @param Request $request
     *
     * @return array
     */
    protected function makeCreateFormRoute(Request $request) {

        /* @var $motorcycle Motorcycle */
        $motorcycle = $request->route('motorcycle');
        $brand = $request->route('brand');
        $variation = $request->route('variation');

        $context = $this->context;
        $resource = $this->resource;

        return [$context . '.' . $resource . '.store', $brand, $motorcycle, $variation];
    }

   /**
     * Retorna os campos responsáveis pelo cadastramento/edição do Model neste Controller.
     *
     * @param EloquentModel $model
     * @return array
     */
    protected function formFields(EloquentModel $model): array {
        $inputs = [];

        $inputs[] = [
            'name' => 'price',
            'label' => 'Preço da Variação',
        ];

        $inputs[] = [
            'name' => 'infos_home',
            'label' => 'Informações Adicionais',
            'type' => 'checkbox',
            'values' => [
                'freight_included' => VariationInfoDictionary::FREIGHT_INCLUDED,
                'freight_not_included' => VariationInfoDictionary::FREIGHT_NOT_INCLUDED,
                'freight_country' => VariationInfoDictionary::FREIGHT_COUNTRY,
                'freight_conditional' => VariationInfoDictionary::FREIGHT_CONDITIONAL,
                'exchangeable' => VariationInfoDictionary::EXCHANGEABLE,
                'ships_home' => VariationInfoDictionary::SHIPS_HOME,
            ]
        ];

       return $inputs;
    }
}


Look the method create( );
rodrigo.pedra's avatar

Ok, so you probably have a relationship between then.

Lets assume it is a HasMany such as:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Product extends Model
{
    public function prices()
    {
        return $this->hasMany( Price::class );
    }
}

Assuming you have the following routes:

/products/{product}/prices/create to add a price to a product

/products/{product}/prices/{price}/edit to update the latest price of a product

So in the controller where you would add the price you could add a guard clause:

    // GET /products/{product}/prices/create
    public function store( Product $product )
    {
        $price = $product->prices()->latest()->first();

        if (!is_null( $price )) {
            return redirect()->to( "/products/{$product->id}/prices/{$price->id}/edit" );
        }

        return view( 'prices.create', compact( 'product' ) );
    }

You could use named routes and add a middleware to make this code look nicer. But I already made a lot of assumptions.

If the relation is a hasOne the code is similar you only have to change the first line in the method to:

$price = $product->price;
rodrigo.pedra's avatar

I didn't see you update while I was writing my response. Let me take a look

rodrigo.pedra's avatar

You use a very custom structure in your code. It is hard to guess how the underlying code is structured, but the idea would be the same.

Assuming the variation is the product model and that it has a related price model:

    public function create(Request $request) {
        // If Route Model Binding is enables - it is the Laravel's default to be
        // this would return the model
        $product = $request->route('variation');
        
        // try to retrieve the price from the model relation
        // maybe you will need to use the repository, but I am
        // not familiar with this package
        $price = $product->prices()->latest()->first();

        if (is_null( $price )) {
            $this->makeCreate();
        } else {
            $this->makeUpdate();
        }
    }

Hoe it helps

1 like
romulo27's avatar

@RODRIGO.PEDRA - I do not think it was that simple, but I have the relationship between price and variation, but not between variation and price

 Schema::create('motorcycle_variations_price', function (Blueprint $table) {
            $table->unsignedInteger('id');
            $table->decimal('price', 10, 2);
            $table->json('infos_home');
            $table->timestamps();

            $table->foreign('id')->references('id')->on('motorcycle_variations');
            $table->primary('id');

        });




class MotorcycleVariationsPrice extends Model {


    protected $table = 'motorcycle_variations_price';

    protected $fillable = [
        'id',
        'price',
        'infos_home',
    ];

    protected $dates = [
        'created_at',
        'updated_at'
    ];

    protected $casts = [
        'infos_home' => 'array',
    ];

    /**
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function variation() {
        return $this->belongsTo(MotorcycleVariations::class);
    }
}
rodrigo.pedra's avatar
Level 56

From the database model it is a HasOne relationship.

So to fetch the price directly from the Variation you can add the relationship method on the MotorcycleVariations model as you told the relationship is missing there:

class MotorcycleVariations {

    // ...

    /**
     * @return \Illuminate\Database\Eloquent\Relations\HasOne
     */
    public function price() {
        // If we do not pass the 'id' as the second parameter Laravel will try
        // to guess the foreign key in the motorcycle_variations_price
        // as motorcycle_variations_id
        return $this->hasOne(MotorcycleVariationsPrice::class, 'id');
    }
}

So your controller eneds as this:

public function create(Request $request) {
        $product = $request->route('variation');
        
        // As it is a hasOne relation, you can fetch it directly
        $price = $product->price;

        if (is_null( $price )) {
            $this->makeCreate();
        } else {
            $this->makeUpdate();
        }
    }
1 like

Please or to participate in this conversation.