Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Daniel Ikeda's avatar

Help with structure of database and polimorphic call

#Hello everybody. This is my first time participating here on the forum due to the help I need and I'm sure you can help me get out of this mess.

I have a business rule that I need to treat each marketplace separately via polymorphism, but I don't know exactly how I implement this in practice. We have three marketplaces, 2 that operate in Brazil and 1 that most people here know well. The idea is to record whether a variant of my product is in one of these marketplaces or in more than one, and there may be more than one in each of them.

The idea itself is to take all the marketplaces the variant is on, and make adjustments such as updatePrice, updateStock... However, I don't know how to efficiently register each marketplace in the DB to access the appropriate polymorphic class later.

I have in mind that I must create a one-to-many table with the marketplace name, item id and variant id. How do I call a polymorphic class in this case? I kind of know the implementation of the interface, but I'm unsure about the call.

Structure

0 likes
5 replies
LaryAI's avatar
Level 58

To implement a polymorphic relationship for handling different marketplaces in your application, you can follow these steps. This approach will allow you to manage product variants across multiple marketplaces and perform operations like updating prices and stock.

Database Structure

  1. Products Table: This table will store your main product information.
  2. Variants Table: This table will store different variants of your products.
  3. Marketplaces Table: This table will store the different marketplaces.
  4. Marketplace_Variant Table: This is a pivot table that will store the relationship between variants and marketplaces.

Here's a basic structure for these tables:

CREATE TABLE products (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255) NOT NULL
);

CREATE TABLE variants (
    id INT AUTO_INCREMENT PRIMARY KEY,
    product_id INT,
    name VARCHAR(255) NOT NULL,
    FOREIGN KEY (product_id) REFERENCES products(id)
);

CREATE TABLE marketplaces (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255) NOT NULL
);

CREATE TABLE marketplace_variant (
    id INT AUTO_INCREMENT PRIMARY KEY,
    marketplace_id INT,
    variant_id INT,
    FOREIGN KEY (marketplace_id) REFERENCES marketplaces(id),
    FOREIGN KEY (variant_id) REFERENCES variants(id)
);

Polymorphic Relationship in Laravel

In Laravel, you can use polymorphic relationships to handle this scenario. Here's how you can set it up:

  1. Models: Create models for Product, Variant, and Marketplace.

  2. Polymorphic Relationship: Use polymorphic relationships to associate variants with marketplaces.

// Variant.php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Variant extends Model
{
    public function marketplaces()
    {
        return $this->morphToMany(Marketplace::class, 'marketplace_variant');
    }
}

// Marketplace.php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Marketplace extends Model
{
    public function variants()
    {
        return $this->morphedByMany(Variant::class, 'marketplace_variant');
    }
}

Implementing the Interface

To implement the interface for marketplace operations, you can define an interface and then create classes for each marketplace that implement this interface.

// MarketplaceInterface.php
namespace App\Contracts;

interface MarketplaceInterface
{
    public function updatePrice($variantId, $price);
    public function updateStock($variantId, $stock);
}

// AmazonMarketplace.php
namespace App\Services;

use App\Contracts\MarketplaceInterface;

class AmazonMarketplace implements MarketplaceInterface
{
    public function updatePrice($variantId, $price)
    {
        // Logic to update price on Amazon
    }

    public function updateStock($variantId, $stock)
    {
        // Logic to update stock on Amazon
    }
}

// Similar classes for other marketplaces...

Using the Polymorphic Relationship

To use the polymorphic relationship and call the appropriate marketplace class, you can do something like this:

use App\Models\Variant;
use App\Services\AmazonMarketplace;

$variant = Variant::find($variantId);
$marketplaces = $variant->marketplaces;

foreach ($marketplaces as $marketplace) {
    $marketplaceService = $this->getMarketplaceService($marketplace->name);
    $marketplaceService->updatePrice($variant->id, $newPrice);
    $marketplaceService->updateStock($variant->id, $newStock);
}

protected function getMarketplaceService($marketplaceName)
{
    switch ($marketplaceName) {
        case 'Amazon':
            return new AmazonMarketplace();
        // Add cases for other marketplaces
        default:
            throw new \Exception("Marketplace not supported");
    }
}

This setup allows you to dynamically call the appropriate marketplace service based on the marketplace name stored in your database. You can extend this by adding more marketplace classes and handling additional operations as needed.

1 like
martinbean's avatar

@daniel ikeda I don’t see why you need polymorphism here in the first place?

If you have multiple marketplaces, then just create a Marketplace model. You can then use a pivot table to assign product variants (I call these SKUs) to marketplaces. If SKUs should have different prices in different marketplaces, then put your price-related columns in the pivot table:

Schema::create('marketplaces', function (Blueprint $table) {
    $table->id();
    $table->string('name')->unique();
});
Schema::create('products', function (Blueprint $table) {
    $table->id();
    $table->string('name')->unique();
});
Schema::create('skus', function (Blueprint $table) {
    $table->id();
    $table->string('sku')->unique();
    $table->foreignId('product_id')->constrained()->cascadeOnDelete();
});
Schema::create('marketplace_sku', function (Blueprint $table) {
    $table->primary(['marketplace_id', 'sku_id']);
    $table->foreignId('marketplace_id')->constrained()->cascadeOnDelete();
    $table->foreignId('sku_id')->constrained()->cascadeOnDelete();
    $table->char('currency', 3)->comment('ISO 4217 currency code');
    $table->unsignedInteger('unit_amount');
});

I’ve including included the pertinent columns above to illustrate the relations between the models.

You can then display a list of products for a marketplace, by query your Product model and restricting it to records that have a SKU, that have pricing for the current marketplace:

class MarketplaceProductController extends Controller
{
    public function index(Marketplace $marketplace)
    {
        $products = Product::query()
            ->withWhereHas('skus', function ($query) use ($marketplace) {
                $query->withWhereHas('marketplaces', function ($query) use ($marketplace) {
                    $query->whereKey($marketplace->getKey());
                });
            })
            ->paginate();

        return view('marketplace.product.index')->with([
            'marketplace' => $marketplace,
            'products' => $products,
        ]);
    }
}

You might want to wrap that up into a local scope on your Product model, though:

$products = Product::query()->forMarketplace($marketplace)->paginate();
1 like
Daniel Ikeda's avatar

@martinbean Thanks for the great explanation. My problem also involves that a sku can appear more than once in the marketplace, and each marketplace contains specific business rules and my system also deals with the API of these marketplaces. The idea is when making a put in a marketplace (generally it returns the changed model) to update the database. To make matters worse, in a specific marketplace I have 2 prices in different "subcategories" with their peculiarities (in this case I thought about storing them in json or making a table for prices) That's why it includes polymorphism in the initial idea. I'm still a bit lost but any contribution is welcome.

martinbean's avatar

My problem also involves that a sku can appear more than once in the marketplace

@Daniel Ikeda Why? A SKU would identify one single product variant. For example, if a T-shirt comes in different sizes, then each size would have its own SKU identifying that particular variant. The reason being, if you run out of say, a particular T-shirt design in size L, you can re-order more of that specific variant by ordering more of that particular SKU from the supplier. So it doesn’t make sense to have a SKU appear multiple times in a single store.

Daniel Ikeda's avatar

@martinbean Yes, it doesn't make sense, but the marketplaces I work on allow me to create, for example, an individual product and a kit, for example, where the Sku appears inside the individual and the kit. There are other possibilities but this is the most obvious in my case.

Please or to participate in this conversation.