Installation
composer require awstudio/product-bundle
Ensure your composer.json includes the required dependencies (sylius/attribute-bundle, sylius/product, etc.).
Bundle Configuration
Add to config/bundles.php:
return [
// ...
Awstudio\ProductBundle\AwstudioProductBundle::class => ['all' => true],
];
Database Migrations Run migrations to create product-related tables:
php bin/console doctrine:migrations:diff
php bin/console doctrine:migrations:migrate
First Use Case: Basic Product CRUD
use Awstudio\ProductBundle\Entity\Product;
$product = new Product();
$product->setName('Sample Product');
$product->setSlug('sample-product');
$product->setPrice(19.99);
$manager->persist($product);
$manager->flush();
$products = $this->getDoctrine()->getRepository(Product::class)->findAll();
Product Management
ProductVariant entity (e.g., size/color combinations).
$variant = new ProductVariant();
$variant->setProduct($product);
$variant->setSku('PROD-001-BLUE-L');
$variant->setPrice(24.99);
ProductOption and ProductOptionValue.
$option = new ProductOption();
$option->setCode('color');
$option->setName('Color');
$product->addOption($option);
Attributes & Properties
sylius/attribute-bundle for customizable properties (e.g., weight, dimensions):
$attribute = $attributeRepository->findOneBy(['code' => 'weight']);
$product->addAttribute($attribute, '1.5 kg');
API Integration
# config/packages/serializer.yaml
framework:
serializer:
mapping:
paths: ['%kernel.project_dir%/config/serializer']
Create Product.yaml in config/serializer:
Awstudio\ProductBundle\Entity\Product:
attributes:
id: ~
name: ~
slug: ~
price: ~
Event-Driven Logic
ProductCreateEvent):
use Awstudio\ProductBundle\Event\ProductEvents;
$dispatcher->addListener(ProductEvents::PRODUCT_CREATE, function ($event) {
// Log or process new products
});
Deprecation Warnings
setPrice() → setBasePrice()).sylius/product directly if needed (this bundle is a wrapper).Doctrine Extensions
stof/doctrine-extensions-bundle for soft deletes/timestamps. If missing:
composer require stof/doctrine-extensions-bundle
Configure in config/packages/doctrine.yaml:
orm:
dql:
string_functions:
CONCAT: DoctrineExtensions\Query\Mysql\Concat
Translation Handling
sylius/locale-bundle. For multi-language support:
# config/packages/sylius_locale.yaml
sylius_locale:
default_locale: en_US
available_locales: [en_US, fr_FR]
Translate product fields via ProductTranslation:
$translation = new ProductTranslation();
$translation->setLocale('fr_FR');
$translation->setName('Produit Exemple');
$product->addTranslation($translation);
Performance with Large Catalogs
DISTINCT for variant-heavy products:
$query = $repository->createQueryBuilder('p')
->select('DISTINCT p.id')
->addSelect('v')
->leftJoin('p.variants', 'v')
->getQuery();
$errors = $validator->validate($product);
if (count($errors) > 0) {
foreach ($errors as $error) {
echo $error->getPropertyPath() . ': ' . $error->getMessage() . "\n";
}
}
$dispatcher->addListener(ProductEvents::PRODUCT_UPDATE, function ($event) {
\Log::debug('Product updated:', ['product' => $event->getProduct()->getId()]);
});
Custom Product Types
Product via inheritance or traits:
class DigitalProduct extends Product
{
private $downloadLink;
public function setDownloadLink(string $link): self
{
$this->downloadLink = $link;
return $this;
}
}
ProductTypeRegistry (override service).API Filters
use Awstudio\ProductBundle\Repository\ProductRepository;
class CustomProductRepository extends ProductRepository
{
public function findByCustomFilter(array $criteria)
{
return $this->createQueryBuilder('p')
->where('p.price > :minPrice')
->setParameter('minPrice', $criteria['min_price'])
->getQuery()
->getResult();
}
}
services.yaml to replace the default repository.Admin Panel Integration
# config/packages/sylius_grid.yaml
sylius_grid:
grids:
sylius_admin_product:
driver:
options:
fields:
name: ~
price: =price.getBasePrice()
variants_count: =variantCount()
How can I help you explore Laravel packages today?