Files
kupshop/bundles/KupShop/OrderingBundle/Feed/OrderConfigurableFeed.php
2025-08-02 16:30:27 +02:00

214 lines
7.1 KiB
PHP

<?php
declare(strict_types=1);
namespace KupShop\OrderingBundle\Feed;
use KupShop\AdminBundle\Util\Filter\OrdersFilterSpecs;
use KupShop\FeedGeneratorBundle\Feed\ConfigurableFeedTrait;
use KupShop\FeedGeneratorBundle\Feed\IConfigurableFeed;
use KupShop\FeedsBundle\Feed\IFeed;
use KupShop\KupShopBundle\Context\ContextManager;
use KupShop\OrderingBundle\Feed\Wrapper\OrderWrapper;
use KupShop\OrderingBundle\OrderList\OrderCollection;
use Query\Operator;
use Query\QueryBuilder;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Contracts\Service\Attribute\Required;
class OrderConfigurableFeed implements IFeed, IConfigurableFeed
{
use \DatabaseCommunication;
use ConfigurableFeedTrait;
/** @var string */
public static $type = 'orderConfigurable';
/** @var string */
public static $alias = 'Objednávky';
/** @var string */
public static $objectType = 'order';
/** @var \Query\QueryBuilder */
protected $query;
/** @var OrdersFilterSpecs */
protected $ordersFilterSpecs;
protected $contextManager;
protected RequestStack $requestStack;
#[Required]
public function setRequestStack(RequestStack $requestStack): void
{
$this->requestStack = $requestStack;
}
public static function isAllowed(): bool
{
return (bool) findModule(\Modules::ORDERS);
}
public function __construct(OrderWrapper $orderWrapper, ContextManager $contextManager)
{
$this->objectWrapper = $orderWrapper;
$this->contextManager = $contextManager;
}
/**
* @required
*/
public function setOrdersFilterSpecs(OrdersFilterSpecs $ordersFilterSpecs)
{
$this->ordersFilterSpecs = $ordersFilterSpecs;
}
public function getQuery(array $feedRow): QueryBuilder
{
$qb = sqlQueryBuilder()->select('o.*')
->from('orders', 'o');
$settings = json_decode($feedRow['settings'] ?? '', true) ?? [];
$filter = $settings['filter'] ?? [];
$days = $filter['order_days'] ?? 1;
if (empty($days)) {
$days = 1;
}
if ($this->requestStack->getMainRequest()?->get('date_from')) {
// date is from GET parameter, its formated as Y-m-d
$date = $this->requestStack->getMainRequest()?->get('date_from');
if (!$date_from = \DateTime::createFromFormat('Y-m-d H:i:s', $date)) {
$date_from = $date.' 00:00:00';
} else {
$date_from = $date_from->format('Y-m-d H:i:s');
}
} else {
// date is from admin field, we need to format it
$date_from = $filter['date_created']['from'] ?? null;
$date_from = empty($date_from) ? null : $this->prepareDate($date_from).' 00:00:00';
}
if ($this->requestStack->getMainRequest()?->get('date_to')) {
$date = $this->requestStack->getMainRequest()?->get('date_to');
if (!$date_to = \DateTime::createFromFormat('Y-m-d H:i:s', $date)) {
$date_to = $date.' 23:59:59';
} else {
$date_to = $date_to->format('Y-m-d H:i:s');
}
} else {
$date_to = $filter['date_created']['to'] ?? null;
$date_to = empty($date_to) ? null : $this->prepareDate($date_to).' 23:59:59';
}
// we handle date_created and date_updated manually, so we unset them to skip them in OrdersfIlterSpecs
unset($filter['date_created']);
if ($date_to || $date_from) {
$qb->andWhere(Operator::orX(
Operator::between('o.date_created', new \Range($date_from, $date_to)),
));
}
if (empty($filter['date_handled']['from']) && empty($filter['date_handled']['to']) && empty($date_from) && empty($date_to)) {
// max days limit
if ($filter['use_date_updated'] ?? false) {
$qb->andWhere('COALESCE(date_updated, date_created) >= (DATE(NOW()) - INTERVAL :days DAY)')
->setParameter('days', $days);
} else {
$qb->andWhere('date_created >= (DATE(NOW()) - INTERVAL :days DAY)')
->setParameter('days', $days);
}
if ($filter['order_days_min'] ?? false) {
// min days limit
if ($filter['use_date_updated'] ?? false) {
$qb->andWhere('COALESCE(date_updated, date_created) < (DATE(NOW()) - INTERVAL :days_min DAY)')
->setParameter('days_min', $filter['order_days_min']);
} else {
$qb->andWhere('date_created < (DATE(NOW()) - INTERVAL :days_min DAY)')
->setParameter('days_min', $filter['order_days_min']);
}
}
}
// orders filter
$filterSpecs = null;
if ($filter) {
$filterSpecs = $this->ordersFilterSpecs->getSpecs($filter);
}
if ($filterSpecs) {
$qb->andWhere($filterSpecs);
}
// Hard limit
$qb->setMaxResults(100000);
foreach ($this->specs as $spec) {
$qb->andWhere($spec);
}
$this->query = $qb;
return $qb;
}
public function filterByObjectID($objectID): void
{
$this->specs[] = function (QueryBuilder $qb) use ($objectID) {
$qb->andWhere(Operator::equals(['o.id' => $objectID]));
};
}
public function getData(array $feedRow, ?int $limit = null): \Generator
{
$qb = $this->query ?? $this->getQuery($feedRow);
$countQuery = (clone $qb)
->select('count(o.id) AS c')
->resetQueryPart('groupBy');
$count = (int) $countQuery->execute()->fetch()['c'];
// use batching only if limit is NOT set
$iterationLimit = isset($limit) ? 1 : ($count / (float) static::$batchSize);
for ($i = 0; $i < $iterationLimit; $i++) {
$qb->setFirstResult($i * static::$batchSize);
$qb->setMaxResults($limit ?? static::$batchSize);
$orders = new OrderCollection();
foreach ($qb->execute() as $row) {
// TODO: predelat na OrdersList s multifetchama az jednou bude
$order = new \Order();
$order->createFromArray($row);
$orders->set((int) $row['id'], $order); // cast to (object) to force reference
}
$this->objectWrapper->setOrders($orders);
foreach ($orders as $order) {
yield $this->prepareSingleObject($order);
}
}
}
protected function initFeedGenerator(array $feedRow): void
{
if (isset($this->forcedFeedGenerator)) {
$this->feedGenerator = $this->forcedFeedGenerator;
} else {
$this->feedGenerator = $this->v8FeedGenerator;
}
if (method_exists($this->feedGenerator, 'setBuildItemCallback')) {
$this->feedGenerator->setBuildItemCallback(function (callable $callback, $v8Object) {
/** @var $itemWrapper OrderWrapper */
$itemWrapper = $v8Object->value;
$itemWrapper->activateOrderFor($callback);
});
}
}
}