Benjamin Cremer
Core Developer shopware AG
@benjamincremer
BaseProduct < ListProduct < Product
BaseProduct: Product Identification
ListProduct: Basic Product Data (Catogory Listing, Related Products)
Product: Full Product data, contains ListProducts (Product Detail Page)
$criteria = new \Shopware\Bundle\SearchBundle\Criteria();
$criteria->addCondition(
new HasFreeShippingCondition()
);
$criteria->addCondition(
new SearchTermCondition('tee')
);
$criteria->addCondition(
new PriceRangeCondition(5, 50)
);
$criteria->addSorting(
new PriceSorting(SortingInterface::SORT_ASC)
);
$criteria->limit(5);
$criteria->offset(0);
namespace Shopware\Bundle\SearchBundle\Condition;
class PriceRangeCondition implements ConditionInterface
{
/**
* @param float $minPrice
* @param float $maxPrice
*/
public function __construct($minPrice, $maxPrice)
{
Assertion::float($minPrice); // see github.com/beberlei/assert
Assertion::float($maxPrice);
$this->minPrice = $minPrice;
$this->maxPrice = $maxPrice;
}
public function getName() {};
public function getMinPrice() {};
public function getMaxPrice() {};
}
/** @var ContextServiceInterface $contextService */
$contextService = $container->get('shopware_storefront.context_service_core');
$context = $contextService->getProductContext();
$context->getShop()->getId(); // 1
$context->getFallbackCustomerGroup()->getKey(); // EK
namespace Shopware\Bundle\SearchBundle;
interface ProductNumberSearchInterface
{
/**
* @param Criteria $criteria
* @param ShopContextInterface $context
* @return ProductNumberSearchResult
*/
public function search(Criteria $criteria, ShopContextInterface $context);
}
$criteria = Criteria();
$criteria->addCondition(new SearchTermCondition('tee'));
$criteria->limit(5);
[..]
$context = [..]
/** @var ProductNumberSearchInterface $search */
$search = $this->get('shopware_searchdbal.product_number_search');
/** @var ProductNumberSearchResult $result */
$result = $search->search($criteria, $context);
echo $result->getTotalCount();
/** @var BaseProduct $product */
foreach ($result->getProducts() as $product) {
echo $product->getNumber(); // $product->getId(), $product->getVariantId();
}
interface ListProductServiceInterface
{
/**
* @return Struct\ListProduct
*/
public function get($number, ProductContextInterface $context);
/**
* @return Struct\ListProduct[] Indexed by the products order number
*/
public function getList(array $numbers, ProductContextInterface $context);
}
interface ProductServiceInterface
{
/**
* @return Struct\Product
*/
public function get($number, ProductContextInterface $context);
/**
* @return Struct\Product[] Indexed by the products order number
*/
public function getList($numbers, ProductContextInterface $context);
}
/** @var ListProductService $productListService */
$productListService = $this->get('shopware_storefront.list_product_service');
/** @var ListProduct $product */
$product = $productListService->get('sw-555', $context);
/** @var ListProduct[] $products */
$products = $productListService->getList(['sw-555', 'sw-111'], $context);
/** @var ProductNumberSearchResult $searchResult */
$searchResult = $this->productNumberSearch->search($condition, $context);
/** @var ListProductService $productListService */
$productListService = $this->get('shopware_storefront.list_product_service');
$listProducts = [];
foreach ($result->getProducts() as $product) {
$listProducts = $productListService->get($product->getNumber(), $context);
}
// Better:
$listProducts = $productListService->get(
array_keys($result->getProducts()),
$context
);
// Produces one single IN query (default DBAL implementation)
namespace Shopware\Bundle\SearchBundle;
use Shopware\Bundle\StoreFrontBundle\Struct;
interface ProductSearchInterface
{
/**
* @return ProductSearchResult
*/
public function search(Criteria $criteria, ProductContextInterface $context);
}
class ProductSearch implements ProductSearchInterface
{
public function __construct(
ProductNumberSearchInterface $search // ElasticSearch
ListProductServiceInterface $productService, // Doctrine DBAL
);
/**
* @return ProductSearchResult
*/
public function search(Criteria $criteria, ProductContextInterface $context);
}
$condition = [..];
$context = [..];
/** @var ProductSearchInterface $search */
$search = $this->get('shopware_search.product_search');
$result = $search->search($criteria, $context);
echo "Totalcount: ". $result->getTotalCount(). "\n";
/** @var ListProduct $product */
foreach ($result->getProducts() as $product) {
echo $product->getName();
};
namespace ShopwarePlugins\AcmeExamplePlugin;
class CriteriaRequestHandler implements CriteriaRequestHandlerInterface
{
public function handleRequest(
Request $request,
Criteria $criteria,
ShopContextInterface $context
) {
if (!$request->hasParam('foos')) {
return;
}
$fooIds = explode(
'|',
$request->getParam('foos')
);
if (!empty($fooIds)) {
$criteria->addCondition(new FooCondition($fooIds));
}
}
}
interface ConditionHandlerInterface
{
/**
* @param ConditionInterface $condition
* @return bool
*/
public function supportsCondition(ConditionInterface $condition);
/**
* @param ConditionInterface $condition
* @param QueryBuilder $query
* @param ShopContextInterface $context
*/
public function generateCondition(
ConditionInterface $condition,
QueryBuilder $query,
ShopContextInterface $context
);
}
class ManufacturerConditionHandler implements ConditionHandlerInterface
{
public function supportsCondition(ConditionInterface $condition)
{
return ($condition instanceof ManufacturerCondition);
}
public function generateCondition(
ConditionInterface $condition,
QueryBuilder $query,
ShopContextInterface $context
) {
/* @var $condition ManufacturerCondition */
$query->innerJoin(
'product',
's_articles_manufacturer',
'manufacturer',
'manufacturer.id = product.manufacturerID
AND product.manufacturerID IN (:manufacturer)'
);
$query->setParameter(
':manufacturer',
$condition->getManufacturerIds(),
Connection::PARAM_INT_ARRAY
);
}
}
class ProductNameSortingHandler implements SortingHandlerInterface
{
public function supportsSorting(SortingInterface $sorting)
{
return ($sorting instanceof ProductNameSorting);
}
public function generateSorting(
SortingInterface $sorting,
QueryBuilder $query,
ShopContextInterface $context
) {
$query->addOrderBy('product.name', $sorting->getDirection())
->addOrderBy('product.id', $sorting->getDirection());
}
}
Just add own Conditions & Handlers
class CachedSearch implements SearchInterface
{
private $innerSearch;
private $cache;
public function __construct(SearchInterface $innerSearch, Cache $cache)
{
$this->innerSearch = $innerSearch;
$this->cache = $cache;
}
public function search(Criteria $criteria, Struct\ShopContextInterface $context)
{
$key = stringify($criteria, $context);
if ($result = $this->cache->get($key)) {
return $result;
}
$result = $this->innerSearch->search($criteria, $context);
$this->cache->put($key, $result);
return $result;
}
}