Skip to main content
Version: 4.1

Create a new Product Type

CoreShop allows you to create a new custom Product Type. The most single interface implementation that can be added to the cart is the CoreShop\Component\Order\Model\PurchasableInterface. You therefore have to at least implement this interface if you want to add a new Product Type and allow it to be added to the cart.

If you need Product Price Rules, Product Specific Price Rules and Quantity Price Rules, you have to go for the CoreShop\Component\Core\Model\ProductInterface. In that case, it is easier to just copy the CoreShopProduct Class Definition and add it as a new Class.

Registering your Product Type

In Order for CoreShop to know that there is a new Purchasable, you have to register your class. The easiest way to do this is, to add this config:

core_shop_resource:
pimcore:
app.my_product:
classes:
model: Pimcore\Model\DataObject\MyProduct
interface: CoreShop\Component\Core\Model\ProductInterface

Or if it's just a Purchasable:

core_shop_resource:
pimcore:
app.my_product:
classes:
model: Pimcore\Model\DataObject\MyProduct
interface: CoreShop\Component\Order\Model\PurchasableInterface

CoreShop will then create separate Services for you, the mains one are the Factory and the Repository (app.repository.my_product, app.factory.my_product). You don't need to use them in your Project, but they are quite important internally for CoreShop.

Alternative using Attributes

Since CoreShop 4.1.0, it is also possible to use PHP Attributes to register new Product Types. You can do this by adding the following Attribute to your Product Class:

<?php

declare(strict_types=1);

namespace App\Model;

use CoreShop\Bundle\ResourceBundle\Attribute\AsPimcoreModel;
use CoreShop\Component\Order\Model\PurchasableInterface;
use CoreShop\Component\Resource\Pimcore\Model\AbstractPimcoreModel;

#[AsPimcoreModel(
pimcoreModel: 'Pimcore\Model\DataObject\MyProduct',
type: 'object',
interface: PurchasableInterface::class
)]
class MyProduct extends AbstractPimcoreModel implements PurchasableInterface
{

}

For this to work, you have to make sure that your core_shop_resource Mapping Path is set. Per default, it points to %kernel.project_dir%/src/Model.

You can change this configuration by adding the following to your Symfony Config:

core_shop_resource:
mapping:
path: '%kernel.project_dir%/src/Model'

Price Calculators

Since you added a new Product Class, you also need Price Calculators for it. CoreShop has a few Price Calculators already, but you can add your own.

If you just added a Purchasable, you have to create a new Price Calculator.

To create a new Price Calculator, you need to implement the interfaces CoreShop\Component\Order\Calculator\PurchasablePriceCalculatorInterface and CoreShop\Component\Order\Calculator\PurchasableRetailPriceCalculatorInterface.

For how Pricing works in detail, see this: Pricing

<?php

declare(strict_types=1);

namespace App\CoreShop;

use CoreShop\Component\Order\Calculator\PurchasablePriceCalculatorInterface;
use CoreShop\Component\Order\Calculator\PurchasableRetailPriceCalculatorInterface;
use CoreShop\Component\Order\Exception\NoPurchasablePriceFoundException;
use CoreShop\Component\Order\Exception\NoPurchasableRetailPriceFoundException;
use CoreShop\Component\Order\Model\PurchasableInterface;

class MyProductPriceCalculator implements PurchasablePriceCalculatorInterface, PurchasableRetailPriceCalculatorInterface
{
public function getPrice(PurchasableInterface $purchasable, array $context, bool $includingDiscounts = false): int
{
return $this->getRetailPrice($purchasable, $context);
}

public function getRetailPrice(PurchasableInterface $purchasable, array $context): int
{
if (!$purchasable instanceof \Pimcore\Model\DataObject\MyProduct) {
throw new NoPurchasableRetailPriceFoundException(__CLASS__);
}

return 100;
}
}

You then also need to register your new Calculator as a Service:

    App\CoreShop\MyProductPriceCalculator:
tags:
- { name: coreshop.order.purchasable.price_calculator, type: my_product }
- { name: coreshop.order.purchasable.retail_price_calculator, type: my_product }