hakhsin's avatar

Which pattern do I have to use in this case?

Hi, in my app there are multi type of products. I implement that like this: Here is product migration:

Schema::create('products', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->unsignedBigInteger('user_id');
            $table->unsignedBigInteger('category_id');
            $table->unsignedBigInteger('city_id');
            $table->nullableMorphs('details');
            $table->string('title', 100);
            $table->text('description');
            $table->timestamps();

            $table->foreign('user_id')
                ->references('id')->on('users')
                ->onDelete('CASCADE');
            $table->foreign('category_id')
                ->references('id')->on('categories')
                ->onDelete('CASCADE');
            $table->foreign('city_id')
                ->references('id')->on('cities')
                ->onDelete('CASCADE');
        });

Here is product model:

   /**
     * Get the details owned the product.
     *
     * @return \Illuminate\Database\Eloquent\Relations\MorphTo
     */
    public function details()
    {
        return $this->morphTo('details');
    }

Here is Animal Product (Details of every sub-products) migration:

   Schema::create('animal_products', function (Blueprint $table) {
            $table->bigIncrements('id');
        .... \ Details of product
            $table->timestamps();
        });

And here is sub-products model:

   /**
     * Get the product owned the detail.
     *
     * @return \Illuminate\Database\Eloquent\Relations\MorphOne
     */
    public function product()
    {
        return $this->morphOne(Product::class, 'details');
    }

In this case I am using repository pattern to create and update the product, like this:

// Product controller
/**
     * Store a newly created resource in storage.
     *
     * @param  \App\Http\Requests\StoreProductRequest $request
     * @return \Illuminate\Http\Response
     */
    public function store(StoreProductRequest $request)
    {
        return response(
            $this->repository->create($request->validated() + ['user_id' => auth()->user()->id]),
            Response::HTTP_CREATED
        );
    }
/**
     * Update the specified resource in storage.
     *
     * @param  \App\Http\Requests\UpdateProductRequest  $request
     * @return \Illuminate\Http\Response
     */
    public function update(UpdateProductRequest $request)
    {
        $this->repository->update($request->validated());
        return response([], Response::HTTP_NO_CONTENT);
    }

Now, I read this article. In this article wrote:

your repositories should not have a Save() or Update() method.

But in this article wrote another thing.

...
**
     * Updates a post.
     *
     * @param int
     * @param array
     */
    public function update($post_id, array $post_data);

Now, in this case what pattern do I use?

Here is my product repository:

class ProductRepository extends Repository
{
    /** @inheritDoc */
    public function create($data)
    {
        if (!isCategoryValid($category = Category::find($data['category_id']), Product::class)) {
            throw new UnexpectedValueException('The given category is not for Product model or its class not exists.');
        }

        $dataCollection = collect($data);

        $product = (new Product)->forceFill($dataCollection->only(['user_id', 'category_id', 'city_id', 'title', 'description'])->toArray());
        $details = $category->class::create($dataCollection->only((new $category->class)->getFillable())->toArray());
        $details->product()->save($product);

        return $product;
    }

    /** @inheritDoc */
    public function update($data)
    {
        $dataCollection = collect($data);
        $product = Product::find($data['id']);
        $result1 = $product->update($dataCollection->only($product->getFillable())->toArray());
        $result2 = $product->details()->update($dataCollection->only($product->details->getFillable())->toArray());
        return $result1 || $result2;
    }

    /**
     * Get the product category.
     *
     * @return \Illuminate\Database\Eloquent\Collection|null
     */
    public function getCategory()
    {
        return Product::getTheModelCategory();
    }

    /** @inheritDoc */
    protected function getResourceClass()
    {
        return Product::class;
    }
}
0 likes
1 reply
hakhsin's avatar

Hi, is it bad practice to add update method into a repository class?

Please or to participate in this conversation.