src/Service/BaseEntityService.php line 205

Open in your IDE?
  1. <?php
  2. namespace App\Service;
  3. use App\Core\Utils\String\StringUtils;
  4. use App\Entity\CalendarEvent;
  5. use App\Entity\Client;
  6. use App\Entity\Company;
  7. use App\Entity\Form\AnySearch;
  8. use App\Entity\Machine;
  9. use App\Entity\Person;
  10. use App\Entity\Session;
  11. use App\Entity\Student;
  12. use App\Library\Route\RouteParamObjects;
  13. use App\Library\Utils\DateTimeProvider\DateTimeProviderInterface;
  14. use App\Library\Utils\DateTimeProvider\SystemDateTimeProvider;
  15. use App\Library\Utils\Dev\DoctrineUtils\DoctrineUtils;
  16. use App\Library\Utils\Dev\ReflectionUtils\ReflectionUtils;
  17. use App\Library\Utils\Other\Other;
  18. use App\Service\CarWash\CarWashService;
  19. use App\Service\Data\Paginator;
  20. use Doctrine\ORM\EntityManagerInterface;
  21. use Doctrine\ORM\EntityRepository;
  22. use Doctrine\ORM\Query\Expr\Join;
  23. use Doctrine\ORM\QueryBuilder;
  24. use Symfony\Component\Serializer\SerializerInterface;
  25. class BaseEntityService
  26. {
  27.     const MANDATORY_PARAMS = [
  28.     ];
  29.     const SEARCH_FIELDS = [
  30.         "name"
  31.     ];
  32.     const ORDER_ID_DESC = ["id""DESC"];
  33.     private static $serviceSecFields = [];
  34.     /** @var EntityManagerInterface */
  35.     protected $em;
  36.     /**
  37.      * @var DateTimeProviderInterface
  38.      */
  39.     protected $dateTimeProvider;
  40.     protected $entityClassName null;
  41.     protected $entityShortClassName null;
  42.     protected $entityAlias null;
  43.     protected $dateFieldName "createdAt";
  44.     protected $tableName null;
  45.     /**
  46.      * @deprecated Устарело. Не использовать.
  47.      */
  48.     protected $searchDql 'item.id = :text or item.name like :text_like';
  49.     /**
  50.      * @var BaseEntityServiceDefault
  51.      */
  52.     private $default;
  53.     private $sqlFields = [];
  54.     /**
  55.      * @var SerializerInterface
  56.      */
  57.     private $serializer;
  58.     /**
  59.      * @var ServiceRetriever|null
  60.      */
  61.     protected $serviceRetriever;
  62.     public function __construct(EntityManagerInterface $em,
  63.                                 SerializerInterface $serializer null,
  64.                                 ServiceRetriever $serviceRetriever null)
  65.     {
  66.         $this->em $em;
  67.         $this->default = new BaseEntityServiceDefault($this);
  68.         $this->serializer $serializer;
  69.         $this->serviceRetriever $serviceRetriever;
  70.     }
  71.     public function initialize(string $entityClassNamestring $dateFieldName "createdAt"string $searchDql null): void
  72.     {
  73.         $this->dateFieldName $dateFieldName;
  74.         $this->entityClassName $entityClassName;
  75.         $this->entityShortClassName self::getEntityShortName($entityClassName);
  76.         $this->entityAlias self::getEntityAlias($this->entityShortClassName);
  77.         $classMetadata $this->em->getClassMetadata($entityClassName);
  78.         $this->tableName $classMetadata->getTableName();
  79.         $this->searchDql $searchDql ?? $this->searchDql;
  80.     }
  81.     public function getRepository(): EntityRepository
  82.     {
  83.         return $this->em->getRepository($this->entityClassName);
  84.     }
  85.     /**
  86.      * @return BaseEntityServiceDefault
  87.      */
  88.     public function getBaseService(): BaseEntityServiceDefault
  89.     {
  90.         return $this->default;
  91.     }
  92.     public function getRandom(int $count 1bool $getCount false, array $excludeIds nullstring $where null)
  93.     {
  94.         $sql 'SELECT ' . ($getCount "count(*)" "*") . ' FROM ' $this->tableName ' item '
  95.             . ($excludeIds || $where "WHERE " "")
  96.             . ($excludeIds " item.id not in (0, " implode(","$excludeIds) . ")" "")
  97.             . ($where $where"")
  98.             . ' ORDER BY RAND() LIMIT ' $count;
  99.         $connection $this->em->getConnection();
  100.         $stmt $connection->prepare($sql);
  101.         $result $stmt->executeQuery();
  102.         return ($getCount ? (int)$result->fetchNumeric()[0] : $result->fetchAllAssociative());
  103.     }
  104.     public function hasItems(Company $company nullstring $whereSql null): bool
  105.     {
  106.         $sql 'SELECT count(*) as count FROM ' $this->tableName " item where"
  107.             . ($company " item.company_id = {$company->getId()}"")
  108.             . ($whereSql $whereSql"")
  109.             . " LIMIT 1";
  110.         $connection $this->em->getConnection();
  111.         $stmt $connection->prepare($sql);
  112.         $result $stmt->executeQuery();
  113.         return (int)$result->fetchNumeric()[0] != 0;
  114.     }
  115.     public function hasNotDeletedItems(Company $company): bool
  116.     {
  117.         $sql 'SELECT count(*) as count FROM ' $this->tableName " item where item.company_id = {$company->getId()} and item.status != 'deleted' LIMIT 1";
  118.         $connection $this->em->getConnection();
  119.         $stmt $connection->prepare($sql);
  120.         $result $stmt->executeQuery();
  121.         return (int)$result->fetchNumeric()[0] != 0;
  122.     }
  123.     protected static $sortedDefaultQueryParams = [
  124.         "company" => null,
  125.         "machine" => null,
  126.     ];
  127.     /**
  128.      * @param array{string, string}|null $orderBy
  129.      * @return array{list: array, page: int, perPage: int, totalItems: int, pagesCount: int}
  130.      * @throws \Exception
  131.      */
  132.     public function getItemsWithPaginationDefault(int   $page, array $params null,
  133.                                                   array $orderBy null$onBeforeQueryChange null, array $excludeMandatoryParams null,
  134.                                                         $isSql false, array $joinClasses nullint $perPage Paginator::PER_PAGE): array
  135.     {
  136.         $query $this->getQuery($params$orderBy$onBeforeQueryChange,
  137.             $excludeMandatoryParams$isSql$joinClasses);
  138.         $result Paginator::getResult($query$page$perPagefalse$this->em->getConnection());
  139.         if ($isSql && $joinClasses) {
  140.             foreach ($result['list'] as $index => $itemData) {
  141.                 $newData = [];
  142.                 $jointTableNames = [];
  143.                 foreach ($itemData as $key => $value) {
  144.                     $keyArr explode("__"$key2);
  145.                     $tableName $keyArr[0];
  146.                     $columnName $keyArr[1];
  147.                     if (!isset($newData[$tableName])) {
  148.                         $newData[$tableName] = [];
  149.                         if ($tableName != $this->tableName) {
  150.                             $jointTableNames[] = $tableName;
  151.                         }
  152.                     }
  153.                     if (in_array($columnName, ["created_at""last_online""last_time"])) {
  154.                         $value = new \DateTime($value);
  155.                     }
  156.                     $newData[$tableName][$columnName] = $value;
  157.                 }
  158.                 $result['list'][$index] = $newData[$this->tableName];
  159.                 foreach ($jointTableNames as $name) {
  160.                     if (isset($result['list'][$index][$name])) {
  161.                         throw new \Exception("'$name' field is already set");
  162.                     }
  163.                     $result['list'][$index][$name] = $newData[$name];
  164.                 }
  165.             }
  166.         }
  167.         return $result;
  168.     }
  169.     public function summaryDefault(array $params nullstring $field "amount"$onBeforeQueryChange null,
  170.                                    array $excludeMandatoryParams null, array $joinClasses null)
  171.     {
  172.         $query $this->summaryQueryDefault($params$onBeforeQueryChange$excludeMandatoryParams$joinClasses$field);
  173.         $result = (int)current($query->getQuery()->getResult()[0]);
  174.         return $result;
  175.     }
  176.     public function getDefault($params null$onBeforeQueryChange null, array $excludeMandatoryParams null,
  177.                                array $joinClasses nullint $limit null, array $orderBy null): array {
  178.         $query $this->getQuery($params$orderBy$onBeforeQueryChange,
  179.             $excludeMandatoryParamsfalse$joinClasses$limit);
  180.         $result $query->getQuery()->getResult();
  181.         return $result;
  182.     }
  183.     public function getFirst(array $params null$onBeforeQueryChange null, array $excludeMandatoryParams null,
  184.                              array $joinClasses null, array $orderBy null)
  185.     {
  186.         $result $this->getDefault($params$onBeforeQueryChange$excludeMandatoryParams$joinClasses1,
  187.             $orderBy);
  188.         if ($result) {
  189.             return $result[0];
  190.         } else {
  191.             return null;
  192.         }
  193.     }
  194.     public function summaryQueryDefault(array $params null$onBeforeQueryChange null, array $excludeMandatoryParams null,
  195.                                         array $joinClasses nullstring $field "amount")
  196.     {
  197.         $query $this->getQuery($paramsnull$onBeforeQueryChange$excludeMandatoryParamsfalse$joinClasses);
  198.         $query->select("sum(item.$field)");
  199.         return $query;
  200.     }
  201.     /**
  202.      * @param $paramName
  203.      * @param $paramValue
  204.      * @param \Doctrine\DBAL\Query\QueryBuilder|\Doctrine\ORM\QueryBuilder $query
  205.      * @param $sortedParams
  206.      * @return false
  207.      */
  208.     protected function handleNextQueryParam($paramName$paramValue$query$sortedParams$isSql) { //need override
  209.         return false;
  210.     }
  211.     /**
  212.      * @param array|null $params
  213.      * @param null|array{string, string} $orderBy
  214.      * @param $onBeforeQueryChange
  215.      * function(string $paramName, $paramValue, \Doctrine\DBAL\Query\QueryBuilder|\Doctrine\ORM\QueryBuilder $query): bool {}
  216.      * @param array|null $excludeMandatoryParams
  217.      * @param $isSql
  218.      * @param array|null $sortedDefaultQueryParams
  219.      * @return \Doctrine\DBAL\Query\QueryBuilder|QueryBuilder
  220.      * @throws \Exception
  221.      */
  222.     public function getQuery($params null,
  223.                              array $orderBy null$onBeforeQueryChange null, array $excludeMandatoryParams null$isSql false, array $joinClasses null,
  224.                              int $limit null)
  225.     {
  226.         if ($params !== null && !is_array($params)) {
  227.             $params = [$params];
  228.         }
  229.         if ($params) {
  230.             $params2 = [];
  231.             foreach ($params as $key => $value) {
  232.                 if (!is_string($key)) {
  233.                     $key lcfirst(ReflectionUtils::getClassShortName(get_class($value)));
  234.                 }
  235.                 $params2[$key] = $value;
  236.             }
  237.             $params $params2;
  238.         }
  239.         $sortedParams $this->getSortedParams($params$excludeMandatoryParams);
  240.         $jointAliases = [];
  241.         $query = ($isSql
  242.             $this->em->getConnection()->createQueryBuilder()
  243.             : $this->em->getRepository($this->entityClassName)->createQueryBuilder('item'));
  244.         $select null;
  245.         if ($joinClasses) {
  246.             if ($isSql) {
  247.                 $select .= implode(", "array_map(function ($current) {
  248.                     return "item.$current";
  249.                 }, DoctrineUtils::getAllEntityFields($this->em$this->getEntityClassName(), $this->tableName)));
  250.             }
  251.             $lastJoinAlias "item";
  252.             foreach ($joinClasses as $class) {
  253.                 $table StringUtils::toCamel(self::getEntityShortName($class));
  254.                 $alias self::getEntityAliasByTableName($tablefalse);
  255.                 $metadata $this->em->getClassMetadata($class);
  256.                 if ($isSql) {
  257.                     $select .= ", " implode(", "array_map(function ($current) use ($alias) {
  258.                             return "$alias.$current";
  259.                         }, DoctrineUtils::getAllEntityFields($this->em$class$table)));
  260.                 }
  261.                 $field null;
  262.                 switch ($class) {
  263.                     case Machine::class:
  264.                         $field "machine_id";
  265.                         break;
  266.                     case Company::class:
  267.                         $field $isSql "company_id" "company";
  268.                         break;
  269.                     case Client::class:
  270.                         $field $isSql "client_id" "client";
  271.                         break;
  272.                     case Person::class:
  273.                         $field $isSql "person_id" "person";
  274.                         break;
  275.                     case CalendarEvent::class:
  276.                         $field $isSql "calendar_event_id" "calendarEvent";
  277.                         break;
  278.                     case Student::class:
  279.                         $field $isSql "student_id" "student";
  280.                         break;
  281.                     default:
  282.                         $field $isSql self::getSqlField(lcfirst($alias)) . "_id" $alias;
  283. //                        throw new \Exception("Unknown: " . $class . ". Entity: " . $this->entityClassName);
  284.                 }
  285.                 if ($isSql) {
  286.                     $query->innerJoin($lastJoinAlias$table$alias"$lastJoinAlias.$field = $alias.id");
  287.                 } else {
  288.                     $query->innerJoin($class$aliasJoin::WITH"$lastJoinAlias.$field = $alias");
  289.                 }
  290.                 $lastJoinAlias $alias;
  291.                 $jointAliases[] = $alias;
  292.             }
  293.         } else {
  294.             if ($isSql) {
  295.                 $select "*";
  296.             }
  297.         }
  298.         if ($isSql) {
  299.             $query->select($select);
  300.             $query->from($this->tableName"item");
  301.         }
  302.         $isParamJointAlias = function ($param) use (&$jointAliases) {
  303.             return in_array($param$jointAliases);
  304.         };
  305.         $getSqlParam = function ($param) use ($isParamJointAlias) {
  306.             $paramBeforeDotArr explode("."$param);
  307.             $paramBeforeDot $paramBeforeDotArr $paramBeforeDotArr[0] : $param;
  308.             return $isParamJointAlias($paramBeforeDot) ? $param "item.$param";
  309.         };
  310.         foreach ($sortedParams as $paramName => $paramValue) {
  311.             if ($onBeforeQueryChange) {
  312.                 if ($onBeforeQueryChange($paramName$paramValue$query)) {
  313.                     continue;
  314.                 }
  315.             }
  316.             $paramNameNoDot str_replace(".""_"$paramName);
  317.             /** @var \Doctrine\DBAL\Query\QueryBuilder|\Doctrine\ORM\QueryBuilder $query */
  318.             if (!$this->handleNextQueryParam($paramName$paramValue$query$sortedParams$isSql)) {
  319.                 switch ($paramName) {
  320.                     case "id":
  321.                         if (is_array($paramValue)) {
  322.                             if ($isSql) {
  323.                                 $query->andWhere("item.id IN (" Other::objectToStringId($paramValue) . ")");
  324.                             } else {
  325.                                 $query->andWhere("item.id IN (:ids)")
  326.                                     ->setParameter('ids'$paramValue);
  327.                             }
  328.                         } else {
  329.                             if ($isSql) {
  330.                                 $query->andWhere("item.id = :id")
  331.                                     ->setParameter('id'$paramValue);
  332.                             } else {
  333.                                 $query->andWhere("item.id = :id")
  334.                                     ->setParameter('id'$paramValue);
  335.                             }
  336.                         }
  337.                         break;
  338.                     // case "type":
  339.                     // case "status":
  340.                     //     if ($isSql) {
  341.                     //         throw new \Exception("Not implemented");
  342.                     //     } else {
  343.                     //         $query->andWhere("item.$paramName = :$paramName")
  344.                     //             ->setParameter("$paramName", $paramValue);
  345.                     //     }
  346.                     //     break;
  347.                     case "company":
  348.                         if ($paramValue !== null) {
  349.                             if ($isSql) {
  350.                                 $query->andWhere("item.company_id = :companyId")
  351.                                     ->setParameter('companyId'$paramValue);
  352.                             } else {
  353.                                 $query->andWhere("item.company = :company")
  354.                                     ->setParameter("company"$paramValue);
  355.                             }
  356.                         }
  357.                         break;
  358.                     case "start":
  359.                         if ($paramValue !== null) {
  360.                             if ($isSql) {
  361.                                 $query->andWhere("item.{$this->getSqlField($this->dateFieldName)} >= :start and item.{$this->getSqlField($this->dateFieldName)} <= :end")
  362.                                     ->setParameter('start'$paramValue->format("Y-m-d H:i:s"))
  363.                                     ->setParameter('end'$sortedParams['end']->format("Y-m-d H:i:s"));
  364.                             } else {
  365.                                 $query->andWhere("item.{$this->dateFieldName} >= :start and item.{$this->dateFieldName} <= :end")
  366.                                     ->setParameter('start'$paramValue)
  367.                                     ->setParameter('end'$sortedParams['end']);
  368.                             }
  369.                         }
  370.                         break;
  371.                     case "end":
  372.                         //do nothing
  373.                         break;
  374.                     case "startTime":
  375.                         if ($paramValue !== null) {
  376.                             if ($isSql) {
  377.                                 $query->andWhere("time(item.{$this->getSqlField($this->dateFieldName)}) >= :startTime and time(item.{$this->getSqlField($this->dateFieldName)}) <= :endTime")
  378.                                     ->setParameter('startTime'$paramValue->format('H:i:s'))
  379.                                     ->setParameter('endTime'$sortedParams['endTime']->format('H:i:s'));
  380.                             } else {
  381.                                 throw new \Exception("Not available");
  382.                             }
  383.                         }
  384.                         break;
  385.                     case "endTime":
  386.                         //do nothing`
  387.                         break;
  388.                     case "machine":
  389.                         if ($paramValue !== null) {
  390.                             if (is_object($paramValue) && method_exists($paramValue"toArray") && get_class($paramValue) != Machine::class) {
  391.                                 $paramValue $paramValue->toArray();
  392.                             }
  393.                             if (!is_array($paramValue)) {
  394.                                 $paramValue = [$paramValue];
  395.                             }
  396.                             if ($isSql) {
  397.                                 $query->andWhere("item.machine_id in (" implode(", ",
  398.                                         array_map(function (Machine $machine) {return $machine->getId();}, $paramValue)) . ")");
  399.                             } else {
  400.                                 $query->andWhere("item.machine in (:machines)")
  401.                                     ->setParameter("machines"$paramValue);
  402.                             }
  403.                         }
  404.                         break;
  405.                     case "name":
  406.                         if ($paramValue !== null) {
  407.                             if ($isSql) {
  408.                                 throw new \Exception("Not implemented");
  409.                             } else {
  410.                                 $query->andWhere("item.name = :name")
  411.                                     ->setParameter("name"$paramValue);
  412.                             }
  413.                         }
  414.                         break;
  415.                     case "search":
  416.                         if ($paramValue !== null && $paramValue != "") {
  417.                             if ($isSql) {
  418.                                 throw new \Exception("Not implemented");
  419.                             } else {
  420.                                 $where "";
  421.                                 foreach ($this->getSearchFields() as $field) {
  422.                                     $where .= ($where " or " "") . "item.$field like :search";
  423.                                 }
  424.                                 $query->andWhere($where)
  425.                                     ->setParameter("search""%" $paramValue "%");
  426.                             }
  427.                         }
  428.                         break;
  429.                     default:
  430.                         if (is_bool($paramValue) && preg_match("/^is[A-Z0-9]/"$paramName)) {
  431.                             if ($paramValue === false) {
  432.                                 $query->andWhere("item.$paramName = 0 or item.$paramName is null");
  433.                             } else {
  434.                                 $query->andWhere("item.$paramName = 1");
  435.                             }
  436.                         } else if (is_array($paramValue) && (isset($paramValue["startDate"]) || isset($paramValue["endDate"]))) {
  437.                             if ($isSql) {
  438.                                 throw new \Exception("Not implemented");
  439.                             } else {
  440.                                 $tmpWhere "";
  441.                                 if (isset($paramValue["startDate"])) {
  442.                                     $tmpWhere .= "{$getSqlParam($paramName)} >= :{$paramNameNoDot}StartDate";
  443.                                     $query->setParameter("{$paramNameNoDot}StartDate"$paramValue['startDate']);
  444.                                 }
  445.                                 if (isset($paramValue["endDate"])) {
  446.                                     $tmpWhere .= ($tmpWhere " and " "") . "{$getSqlParam($paramName)} <= :{$paramNameNoDot}EndDate";
  447.                                     $query->setParameter("{$paramNameNoDot}EndDate"$paramValue['endDate']);
  448.                                 }
  449.                                 $query->andWhere($tmpWhere);
  450.                             }
  451.                         } else if (is_array($paramValue) && ReflectionUtils::isEntity(current($paramValue))) {
  452.                             $alias self::getEntityAlias($paramName);
  453. //                            $query
  454. //                                ->join("item.$paramName", $alias)
  455. //                                ->andWhere("$alias.id in (:{$paramName}Ids)")
  456. //                                ->setParameter(":{$paramName}Ids", Other::objectToStringId($paramValue));
  457.                             $query
  458.                                 ->join("item.$paramName"$alias)
  459.                                 ->andWhere("$alias in (:{$paramName})")
  460.                                 ->setParameter(":{$paramName}"$paramValue);
  461.                         } else if (is_array($paramValue) && is_string(current($paramValue))) {
  462.                             $query->andWhere("{$getSqlParam($paramName)} in (:{$paramNameNoDot}Values)")
  463.                                 ->setParameter(":{$paramNameNoDot}Values"$paramValue);
  464.                         } elseif  (is_array($paramValue) && is_int(current($paramValue))) {
  465.                             if ($isSql) {
  466.                                 $query->andWhere("item.$paramName in (" implode(", "$paramValue) . ")");
  467.                             } else {
  468.                                 $query->andWhere("item.$paramName in (:{$paramName}Ids)")
  469.                                     ->setParameter(":{$paramName}Ids"$paramValue);
  470.                             }
  471.                         } else {
  472.                             if ($isSql) {
  473.                                 throw new \Exception("Not implemented");
  474.                             } else {
  475.                                 if (strpos($paramName".") !== false) {
  476.                                     $query->andWhere("$paramName = :" str_replace(".""_"$paramName))
  477.                                         ->setParameter(str_replace(".""_"$paramName), $paramValue);
  478.                                 } else {
  479.                                     $query->andWhere("item.$paramName = :$paramName")
  480.                                         ->setParameter("$paramName"$paramValue);
  481.                                 }
  482.                             }
  483.                         }
  484.                 }
  485.             }
  486.         }
  487.         if ($orderBy) {
  488.             $query->orderBy("item.{$orderBy[0]}"$orderBy[1]);
  489.         }
  490.         if ($limit !== null) {
  491.             $query->setMaxResults($limit);
  492.         }
  493.         if (Other::canAddDebugLog()) {
  494.             Other::appendQueryLog(
  495.                 (get_class($query) == "Doctrine\ORM\QueryBuilder" "DQL: "  $query->getDQL() : "")
  496.                 . "\nSQL: " . (get_class($query) == "Doctrine\ORM\QueryBuilder" $query->getQuery()->getSQL() : $query->getSQL()));
  497.         }
  498.         return $query;
  499.     }
  500.     protected function getSqlField(string $field): string
  501.     {
  502.         if (isset($this->sqlFields[$field])) {
  503.             return $this->sqlFields[$field];
  504.         }
  505.         $this->sqlFields[$field] = StringUtils::toCamel($field);
  506.         return $this->sqlFields[$field];
  507.     }
  508.     public function getSortedParams(?array $params, ?array $excludeMandatoryParams): array
  509.     {
  510.         $sortedParams array_merge($this::$sortedDefaultQueryParams, ($params ?: []));
  511.         foreach ($this->getMandatoryParams() as $paramName) {
  512.             if ((!isset($sortedParams[$paramName]) || $sortedParams[$paramName] === null) && (!$excludeMandatoryParams || !in_array($paramName$excludeMandatoryParams))) {
  513.                 throw new \Exception("Обязательный параметр \"$paramName\" не задан. Добавьте параметр в \$params или добавьте в исключение \$excludeMandatoryParams"
  514.                     ". Сущность: " $this->entityClassName);
  515.             }
  516.         }
  517.         return $sortedParams;
  518.     }
  519.     public function getMandatoryParams(): array {
  520.         return self::MANDATORY_PARAMS;
  521.     }
  522.     protected function getSearchFields(): array {
  523.         return self::SEARCH_FIELDS;
  524.     }
  525.     /**
  526.      * @deprecated Устарело. Не использовать.
  527.      * Calls in getItemsBySearchWithPagination.
  528.      * Override if you need to modify query before search query execution.
  529.      * Example:
  530.      * For other entity joining.
  531.      * $query->innerJoin(Client::class, "client_", Join::WITH, "item.client = client_");
  532.      * @param QueryBuilder $query
  533.      * @return void
  534.      */
  535.     protected function setSearchQueryParams(QueryBuilder $query): void
  536.     {
  537.     }
  538.     public function setDateTimeProvider(DateTimeProviderInterface $dateTimeProvider)
  539.     {
  540.         $this->dateTimeProvider $dateTimeProvider;
  541.     }
  542.     public function setSystemTimeProvider()
  543.     {
  544.         $this->dateTimeProvider = new SystemDateTimeProvider();
  545.     }
  546.     public static function getEntityShortName(string $entityClassName): string
  547.     {
  548.         return (new \ReflectionClass($entityClassName))->getShortName();
  549.     }
  550.     public static function getEntityAlias(string $entityShortClassName): string
  551.     {
  552.         return lcfirst($entityShortClassName) . "_";
  553.     }
  554.     public static function getEntityAliasByTableName(string $tableNamebool $addUnderscore true): string
  555.     {
  556.         if (!str_contains($tableName"_")) {
  557.             return $tableName . ($addUnderscore "_" "");
  558.         }
  559.         $substrings explode("_"$tableName);
  560.         return $substrings[0] .
  561.             implode(""array_map(function ($current) {return ucfirst($current);}, array_splice($substrings1))) .
  562.             ($addUnderscore "_" "");
  563.     }
  564.     /**
  565.      * @deprecated Устарело. Не использовать.
  566.      */
  567.     public function setQueryParams(?QueryBuilder $query null, ?AnySearch $search null, ?Company $company,
  568.                                    ?\DateTime $start null, ?\DateTime $end null, ?array $orderBy null,
  569.                                    ?array $statuses null, ?Client $client null, array $carWashes null): QueryBuilder
  570.     {
  571.         return self::setQueryParamsByEm($this->em$this->entityClassName$this->dateFieldName,
  572.             $query$search$company$start$end$orderBy$statuses$client$this->searchDql$carWashes);
  573.     }
  574.     /**
  575.      * @deprecated Устарело. Не использовать.
  576.      */
  577.     public static function setQueryParamsByEm(EntityManagerInterface $emstring $entityClassNamestring $dateFieldName null,
  578.                                               ?QueryBuilder $query null, ?AnySearch $search null, ?Company $company,
  579.                                               ?\DateTime $start null, ?\DateTime $end null, ?array $orderBy null,
  580.                                               ?array $statuses null, ?Client $client nullstring $searchDql null,
  581.                                               array $carWashes null): QueryBuilder
  582.     {
  583.         $lostClients $search && $search->isLost() && $search->getLostDays();
  584.         if (!$query) {
  585.             $query $em->getRepository($entityClassName)->createQueryBuilder('item');
  586.         }
  587.         if ($company) {
  588.             $query->where('item.company = :company')
  589.                 ->setParameter("company"$company);
  590.         }
  591.         if ($carWashes && !$lostClients) {
  592.             $query->andWhere($query->expr()->in("carWash_"":carWashes"))->setParameter("carWashes"$carWashes);
  593.         }
  594.         if ($search && $search->getSearch() && $search->getSearch() != '') {
  595.             $query->andWhere($searchDql ?? 'item.id = :text or item.name like :text_like')
  596.                 ->setParameter('text'$search->getSearch())
  597.                 ->setParameter('text_like''%' $search->getSearch() . '%');
  598.         }
  599.         if ($start && $end && (!$search || !$search->isLost())) {
  600.             $query->andWhere("item.{$dateFieldName} >= :start and item.{$dateFieldName} <= :end")
  601.                 ->setParameter('start'$start)
  602.                 ->setParameter('end'$end);
  603.         }
  604.         if ($lostClients) {
  605.             $ids = [0];
  606.             $now = new \DateTime();
  607.             foreach ($em->getRepository(Client::class)->findBy(['company' => $company]) as $tmpClient) {
  608.                 /** @var Session $session */
  609.                 $session $em->getRepository(Session::class)->findOneBy(array_merge(['client' => $tmpClient],
  610.                     (!$carWashes ? [] : ['machine' => CarWashService::getCarWashesMachines($carWashesfalse)])), ['id' => 'DESC']);
  611.                 if ($session) {
  612.                     $dt = clone $session->getEndTime();
  613.                     $dt->modify('+'$search->getLostDays() .' days');
  614.                     if ($dt $now) {
  615.                         $ids[] = $tmpClient->getId();
  616.                         $search->clientLastSessionsDates[$tmpClient->getId()] = $session->getEndTime();
  617.                     }
  618.                 }
  619.             }
  620.             $query->andWhere('item.id in (:ids)')
  621.                 ->setParameter('ids'$ids);
  622.         }
  623.         if ($statuses) {
  624.             if (!is_array($statuses)) {
  625.                 $statuses = [$statuses];
  626.             }
  627.             $query->andWhere($query->expr()->in('item.status'':statuses'))
  628.                 ->setParameter('statuses'$statuses);
  629.         }
  630.         if ($client) {
  631.             $query->andWhere('item.client = :client')
  632.                 ->setParameter("client"$client);
  633.         }
  634.         if ($orderBy) {
  635.             $query->orderBy("item.{$orderBy[0]}"$orderBy[1]);
  636.         }
  637.         return $query;
  638.     }
  639.     /**
  640.      * @deprecated Устарело. Не использовать.
  641.      * @psalm-param array<string, string>|null $orderBy
  642.      * @return array
  643.      */
  644.     public function getItemsBySearchWithPagination(?AnySearch $search null, ?Company $company null,
  645.                                                    ?\DateTime $start null, ?\DateTime $end null, ?array $orderBy null,
  646.                                                    ?array     $statuses null$queryCallback null, array $carWashes null,
  647.                                                    Client $client null, array $options nullRouteParamObjects $routeObjects null): array
  648.     {
  649.         if ($routeObjects && $routeObjects->getCarWash()) {
  650.             $carWashes = [$routeObjects->getCarWash()];
  651.         }
  652.         $query $this->createQuery($search$company$start$end$orderBy$statuses$client$queryCallbacktrue,
  653.             $carWashes);
  654.         $result Paginator::getResult($query, ($search->getPage() && $search->getPage() > 0) ? $search->getPage() : 1,
  655.             Paginator::PER_PAGEfalse);
  656.         if (isset($options['sortByPostId']) && $options['sortByPostId']) {
  657.             $result["list"] = $this->sortMachinesByPostId($result["list"]);
  658.         }
  659.         return $result;
  660.     }
  661.     /**
  662.      * @deprecated Устарело. Не использовать.
  663.      * @psalm-param array<string, string>|null $orderBy
  664.      */
  665.     public function createQuery(?AnySearch $search null, ?Company $company null,
  666.                                 ?\DateTime $start null, ?\DateTime $end null, ?array $orderBy null,
  667.                                 ?array     $statuses null$client null$queryCallback nullbool $setCommonSearchQueryParams false,
  668.                                 array $carWashes null): QueryBuilder
  669.     {
  670.         $query $this->em->getRepository($this->entityClassName)->createQueryBuilder('item');
  671.         if ($setCommonSearchQueryParams) {
  672.             $this->setSearchQueryParams($query);
  673.         }
  674.         /** @var QueryBuilder $q */
  675.         $q $this->setQueryParams($query$search$company$start$end$orderBy$statuses$client$carWashes);
  676.         if ($queryCallback) {
  677.             $queryCallback($q);
  678.         }
  679.         return $query;
  680.     }
  681.     /**
  682.      * @deprecated Устарело. Не использовать.
  683.      * @psalm-param array<string, string>|null $orderBy
  684.      * @return array
  685.      */
  686.     public function getQueryBySearchWithPagination(?AnySearch $search null, ?Company $company null,
  687.                                                    ?\DateTime $start null, ?\DateTime $end null, ?array $orderBy null,
  688.                                                    ?array     $statuses null): QueryBuilder
  689.     {
  690.         $query $this->em->getRepository($this->entityClassName)->createQueryBuilder('item');
  691.         $this->setSearchQueryParams($query);
  692.         $q $this->setQueryParams($query$search$company$start$end$orderBy$statuses);
  693.         return $q;
  694.     }
  695.     /**
  696.      * @deprecated Устарело. Не использовать.
  697.      * @param $fieldName
  698.      * @param AnySearch $search
  699.      * @param Company|null $company
  700.      * @param \DateTime|null $start
  701.      * @param \DateTime|null $end
  702.      * @return float|int|mixed|string
  703.      * @throws \Doctrine\ORM\NoResultException
  704.      * @throws \Doctrine\ORM\NonUniqueResultException
  705.      */
  706.     public function getSummaryByField($fieldName "amount", ?AnySearch $search null, ?Company $company null,
  707.                                       ?\DateTime $start null, ?\DateTime $end null, ?Client $client null,
  708.                                       ?array $statuses null$queryCallback nullbool $setCommonSearchParams false)
  709.     {
  710.         $q $this->createQuery($search$company$start$endnull$statuses$client$queryCallback$setCommonSearchParams);
  711.         $q->select("sum(item.$fieldName)");
  712.         $result $q->getQuery()->getSingleScalarResult();
  713.         if ($result === null) {
  714.             $result 0;
  715.         }
  716.         return $result;
  717.     }
  718.     /**
  719.      * @param string|array $whereConditions
  720.      * @param array|null $joinConditions
  721.      * @param string|null $select
  722.      * @param string|null $groupBy
  723.      * @return array
  724.      */
  725.     public function getByExpression($whereConditions = [], array $joinConditions nullstring $select null,
  726.                                     string $groupBy null): array
  727.     {
  728.         return self::getByExpressionWithEm($this->em$this->entityClassName$this->entityAlias$whereConditions,
  729.             $joinConditions$select$groupBy);
  730.     }
  731.     /**
  732.      * @param array $whereConditions
  733.      * @param array|null $joinConditions
  734.      * @param string|null $select
  735.      * @param string|null $groupBy
  736.      * @return mixed
  737.      */
  738.     public function getOnyByExpression(array $whereConditions = [], array $joinConditions nullstring $select null,
  739.                                        string $groupBy null)
  740.     {
  741.         $result self::getByExpressionWithEm($this->em$this->entityClassName$this->entityAlias$whereConditions,
  742.             $joinConditions$select$groupBy);
  743.         if ($result == []) {
  744.             return null;
  745.         }  else {
  746.             if (count($result) > 1) {
  747.                 throw new \Exception('Found more than one');
  748.             }
  749.             return $result[0];
  750.         }
  751.     }
  752.     /**
  753.      * @param array $whereConditions
  754.      * @param array|null $joinConditions
  755.      * @param string|null $select
  756.      * @param string|null $groupBy
  757.      * @return QueryBuilder
  758.      */
  759.     public function getQueryByExpression(array $whereConditions = [], array $joinConditions nullstring $select null,
  760.                                          string $groupBy null)
  761.     {
  762.         return self::getQueryByExpressionWithEm($this->em$this->entityClassName$this->entityAlias$whereConditions,
  763.             $joinConditions$select$groupBy);
  764.     }
  765.     /**
  766.      * @deprecated Устарело. Не использовать.
  767.      * @param EntityManagerInterface $em
  768.      * @param string $entityClassName
  769.      * @param string|null $entityAlias
  770.      * @param string|array $whereConditions
  771.      * @param array|null $joinExpressions
  772.      * @param string|null $select
  773.      * @param string|null $groupBy
  774.      * @return array
  775.      */
  776.     public static function getByExpressionWithEm(EntityManagerInterface $emstring $entityClassNamestring $entityAlias null,
  777.                                                                         $whereConditions = [], $joinExpressions nullstring $select null,
  778.                                                  string $groupBy nullint $limit 0): array
  779.     {
  780.         $q self::getQueryByExpressionWithEm($em$entityClassName$entityAlias$whereConditions$joinExpressions$select$groupBy$limit);
  781.         $result $q->getQuery()->getResult();
  782.         return $result;
  783.     }
  784.     /**
  785.      * @deprecated Устарело. Не использовать.
  786.      * @param string|array $whereConditions
  787.      * [Key = 'left expression part', value = 'expression value'].
  788.      * Example: [
  789.      *             "bonusPercentUpdatedAt !=" => "null",
  790.      *             "status" => [Status::STATUS1, Status::STATUS2]
  791.      *          ]
  792.      *
  793.      * @param array|null $joinExpressions
  794.      * ['joinEntityName', 'joinEntityCondition', 'joinEntityWhereExpression', 'joinEntityWhereValue']
  795.      * Example: ['cashbackRule', "id = client_.cashbackRule", 'status =', Status::STATUS_ACTIVE]
  796.      *
  797.      * @return QueryBuilder
  798.      */
  799.     public static function getQueryByExpressionWithEm(EntityManagerInterface $emstring $entityClassNamestring $entityAlias null,
  800.                                                                              $whereConditions = [], array $joinExpressions nullstring $select null,
  801.                                                       string $groupBy nullint $limit 0)
  802.     {
  803.         if (!$entityAlias) {
  804.             $entityAlias self::getEntityAlias(self::getEntityShortName($entityClassName));
  805.         }
  806.         $q $em->getRepository($entityClassName)->createQueryBuilder($entityAlias);
  807.         if ($select) {
  808.             $q->select($select);
  809.         }
  810.         if ($joinExpressions) {
  811.             if (!is_array($joinExpressions[0])) {
  812.                 $joinExpressions = [$joinExpressions];
  813.             }
  814.             $joinParamIndex 0;
  815.             foreach ($joinExpressions as $joinParams) {
  816.                 $joinEntity $joinParams[0];
  817.                 $joinEntityAlias "{$joinEntity}_";
  818.                 $joinCondition $joinParams[1];
  819.                 $joinWhereExpression $joinParams[2] ?? null;
  820.                 $joinWhereValue $joinParams[3] ?? null;
  821.                 $q $q->innerJoin("$entityAlias.$joinEntity"$joinEntityAlias"WITH""$joinEntityAlias.$joinCondition");
  822.                 $joinParamIndex++;
  823.                 $joinParamName "joinParam$joinParamIndex";
  824.                 if ($joinWhereExpression) {
  825.                     $q->andWhere("$joinEntityAlias.$joinWhereExpression :$joinParamName")
  826.                         ->setParameter($joinParamName$joinWhereValue);
  827.                 }
  828.             }
  829.         }
  830.         if (is_string($whereConditions)) {
  831.             $q->where($whereConditions);
  832.         } else {
  833.             $paramIndex 0;
  834.             foreach ($whereConditions as $leftExpressionPart => $value) {
  835.                 $or false;
  836.                 if (str_starts_with(strtolower($leftExpressionPart), "or ")) {
  837.                     $or true;
  838.                     $leftExpressionPart substr($leftExpressionPart3);
  839.                 }
  840.                 $paramIndex++;
  841.                 $paramName "param$paramIndex";
  842.                 if (is_object($value) && strpos(get_class($value), "App\Entity") !== && method_exists($value"toArray")) {
  843.                     $value $value->toArray();
  844.                 }
  845.                 if ($or) {
  846.                     if (is_array($value)) {
  847.                         $q
  848.                             ->orWhere($q->expr()->in("$entityAlias.$leftExpressionPart"":$paramName"))
  849.                             ->setParameter($paramName$value);
  850.                     } else {
  851.                         if ($value === null) {
  852.                             $q
  853.                                 ->orWhere("$entityAlias.$leftExpressionPart null");
  854.                         } else {
  855.                             $q
  856.                                 ->orWhere("$entityAlias.$leftExpressionPart :$paramName")
  857.                                 ->setParameter($paramName$value);
  858.                         }
  859.                     }
  860.                 } else {
  861.                     if (is_array($value)) {
  862.                         $q
  863.                             ->andWhere($q->expr()->in("$entityAlias.$leftExpressionPart"":$paramName"))
  864.                             ->setParameter($paramName$value);
  865.                     } else {
  866.                         if ($value === null) {
  867.                             $q
  868.                                 ->andWhere("$entityAlias.$leftExpressionPart null");
  869.                         } else {
  870.                             $q
  871.                                 ->andWhere("$entityAlias.$leftExpressionPart :$paramName")
  872.                                 ->setParameter($paramName$value);
  873.                         }
  874.                     }
  875.                 }
  876.             }
  877.         }
  878.         if ($groupBy) {
  879.             $q->groupBy($groupBy);
  880.         }
  881.         if ($limit) {
  882.             $q->setMaxResults($limit);
  883.         }
  884.         return $q;
  885.     }
  886.     /**
  887.      * @param array $whereConditions
  888.      * @param array|null $joinConditions
  889.      * @param string|null $select
  890.      * @param string|null $groupBy
  891.      * @return array
  892.      */
  893.     public function getBySqlExpression(array $whereConditions = [], array $joinConditions nullstring $select null,
  894.                                        string $groupBy nullstring $tableName nullint $limit null): array
  895.     {
  896.         return self::getBySqlExpressionWithEm($this->em$this->entityClassName,
  897.             (!$tableName $this->entityAlias self::getEntityAliasByTableName($tableName)),
  898.             $whereConditions$joinConditions$select$groupBy, ($tableName ?? $this->tableName), $limit);
  899.     }
  900.     /**
  901.      * @deprecated Устарело. Не использовать.
  902.      * @param array $whereConditions
  903.      * @param array|null $joinConditions
  904.      * @param string|null $select
  905.      * @param string|null $groupBy
  906.      * @return \Doctrine\DBAL\Query\QueryBuilder
  907.      */
  908.     public function getQueryBySqlExpression(array $whereConditions = [], array $joinConditions nullstring $select null,
  909.                                             string $groupBy nullstring $tableName nullint $limit null)
  910.     {
  911.         return self::getQueryBySqlExpressionWithEm($this->em$this->entityClassName,
  912.             (!$tableName $this->entityAlias self::getEntityAliasByTableName($tableName)), $whereConditions,
  913.             $joinConditions$select$groupBy, ($tableName ?? $this->tableName), $limit);
  914.     }
  915.     /**
  916.      * @deprecated Устарело. Не использовать.
  917.      * @param EntityManagerInterface $em
  918.      * @param string $entityClassName
  919.      * @param string|null $entityAlias
  920.      * @param array $whereConditions
  921.      * @param array|null $joinExpressions
  922.      * @param string|null $select
  923.      * @param string|null $groupBy
  924.      */
  925.     public static function getBySqlExpressionWithEm(EntityManagerInterface $emstring $entityClassNamestring $entityAlias null,
  926.                                                     array $whereConditions = [], array $joinExpressions nullstring $select null,
  927.                                                     string $groupBy nullstring $tableName nullint $limit null): array
  928.     {
  929.         $q self::getQueryBySqlExpressionWithEm($em$entityClassName$entityAlias$whereConditions$joinExpressions$select$groupBy$tableName$limit);
  930.         $stmt $q->execute();
  931.         $result is_bool($stmt) ? $q->fetchAll() : $stmt->fetchAll();
  932.         return $result;
  933.     }
  934.     /**
  935.      * @deprecated Устарело. Не использовать.
  936.      * @param array $whereConditions
  937.      * [Key = 'left expression part', value = 'expression value'].
  938.      * Example: [
  939.      *             "bonusPercentUpdatedAt !=" => "null",
  940.      *             "status" => [Status::STATUS1, Status::STATUS2]
  941.      *          ]
  942.      *
  943.      * @param array|null $joinExpressions
  944.      * ['joinTableName', 'joinColumnCondition', 'joinColumnWhereExpression', 'joinColumnWhereValue', 'joinType']
  945.      * Example: ['client', "id = bonus.client_id", 'company_id =', 116, "left"]
  946.      *
  947.      * @return \Doctrine\DBAL\Query\QueryBuilder
  948.      */
  949.     public static function getQueryBySqlExpressionWithEm(EntityManagerInterface $emstring $entityClassNamestring $entityAlias null,
  950.                                                          array $whereConditions = [], array $joinExpressions nullstring $select null,
  951.                                                          string $groupBy nullstring $tableName nullint $limit null)
  952.     {
  953.         if (!$entityAlias) {
  954.             $entityAlias self::getEntityAlias(self::getEntityShortName($entityClassName));
  955.         }
  956.         if (!$tableName) {
  957.             throw new \Exception("\$tableName is not set");
  958.         }
  959.         $connection $em->getConnection();
  960.         $q $connection->createQueryBuilder()
  961.             ->select($select ?? "$entityAlias.id")
  962.             ->from($tableName$entityAlias);
  963.         if ($joinExpressions) {
  964.             if (!is_array($joinExpressions[0])) {
  965.                 $joinExpressions = [$joinExpressions];
  966.             }
  967.             foreach ($joinExpressions as $joinParams) {
  968.                 $joinTableName $joinParams[0];
  969.                 $joinEntityAlias self::getEntityAliasByTableName($joinTableName);
  970.                 $joinCondition $joinParams[1];
  971.                 $joinWhereExpression $joinParams[2] ?? null;
  972.                 $joinWhereValue $joinParams[3] ?? null;
  973.                 $preparedValue self::prepareSqlValue($joinWhereValue);
  974.                 $joinType $joinParams[4] ?? null;
  975.                 switch ($joinType) {
  976.                     case null:
  977.                     case "inner":
  978.                         $q $q->innerJoin($entityAlias$joinTableName$joinEntityAlias"$joinEntityAlias.$joinCondition");
  979.                         break;
  980.                     case "left":
  981.                         $q $q->leftJoin($entityAlias$joinTableName$joinEntityAlias"$joinEntityAlias.$joinCondition");
  982.                         break;
  983.                     default:
  984.                         throw new \Exception("Unknown: $joinType". Entity: " $entityClassName);
  985.                 }
  986.                 if ($joinWhereExpression) {
  987.                     if (is_array($joinWhereValue)) {
  988.                         $q->andWhere("$joinEntityAlias.$joinWhereExpression in ($preparedValue)");
  989.                     } else {
  990.                         $q->andWhere("$joinEntityAlias.$joinWhereExpression $preparedValue");
  991.                     }
  992.                 }
  993.             }
  994.         }
  995.         foreach ($whereConditions as $leftExpressionPart => $value) {
  996.             $or false;
  997.             if (str_starts_with(strtolower($leftExpressionPart), "or ")) {
  998.                 $or true;
  999.                 $leftExpressionPart substr($leftExpressionPart3);
  1000.             }
  1001.             $isFullExpression is_numeric($leftExpressionPart);
  1002.             $preparedValue self::prepareSqlValue($value);
  1003.             if ($isFullExpression) {
  1004.                 $q->andWhere($value);
  1005.             } else {
  1006.                 if ($or) {
  1007.                     if (is_array($value)) {
  1008.                         $q->orWhere("$entityAlias.$leftExpressionPart in ($preparedValue)");
  1009.                     } else {
  1010.                         $q->orWhere("$entityAlias.$leftExpressionPart $preparedValue");
  1011.                     }
  1012.                 } else {
  1013.                     if (is_array($value)) {
  1014.                         $q->andWhere("$entityAlias.$leftExpressionPart in ($preparedValue)");
  1015.                     } else {
  1016.                         $q->andWhere("$entityAlias.$leftExpressionPart $preparedValue");
  1017.                     }
  1018.                 }
  1019.             }
  1020.         }
  1021.         if ($groupBy) {
  1022.             $q->groupBy($groupBy);
  1023.         }
  1024.         if ($limit) {
  1025.             $q->setMaxResults($limit);
  1026.         }
  1027.         return $q;
  1028.     }
  1029.     /**
  1030.      * @param $value
  1031.      * @return mixed|string|int
  1032.      */
  1033.     private static function prepareSqlValue($value)
  1034.     {
  1035.         if ($value === null) {
  1036.             $value "null";
  1037.         } else if (is_string($value) && !str_starts_with($value"'") && !str_starts_with($value"\"")) {
  1038.             $value "'" $value "'";
  1039.         } else if (is_array($value)) {
  1040.             $value implode(", "$value);
  1041.         }
  1042.         return $value;
  1043.     }
  1044.     /**
  1045.      * @deprecated Устарело. Не использовать.
  1046.      */
  1047.     public function getBy(array $criteria, ?Company $company null): array
  1048.     {
  1049.         if ($company) {
  1050.             $criteria['company'] = $company;
  1051.         }
  1052.         return $this->em->getRepository($this->entityClassName)->findBy($criteria);
  1053.     }
  1054.     /**
  1055.      * @deprecated Устарело. Не использовать.
  1056.      */
  1057.     public function getOneBy(array $criteria, ?Company $company null)
  1058.     {
  1059.         if ($company) {
  1060.             $criteria['company'] = $company;
  1061.         }
  1062.         return $this->em->getRepository($this->entityClassName)->findOneBy($criteria);
  1063.     }
  1064.     public function getMachineIds(array $machines$addZeroId false): array
  1065.     {
  1066.         $result array_map(function ($machine) {return $machine->getId();}, $machines);
  1067.         if ($addZeroId) {
  1068.             array_unshift($result0);
  1069.         }
  1070.         return $result;
  1071.     }
  1072.     public function getMultiDimensionalSqlResultsByMachineIdAndDate(array $sqlResults, array $additionalFieldsBefore null,
  1073.                                                                     array $additionalFieldsAfter null): array
  1074.     {
  1075.         return DoctrineUtils::getMultiDimensionalSqlResults($sqlResults,
  1076.             array_merge(($additionalFieldsBefore ?? []), ["machine_id""date"], ($additionalFieldsAfter ?? [])));
  1077.     }
  1078.     public function getSessionsServiceSecSumSelectSql(string $tableAlias): string
  1079.     {
  1080.         $select '';
  1081.         for ($num 1$num <= Machine::maxServiceNum$num++) {
  1082.             $select .= ($select ",\n" '') . "SUM($tableAlias.service{$num}sec) as service{$num}sec";
  1083.         }
  1084.         return $select;
  1085.     }
  1086.     public function getSessionServiceSecSumSelectSql(string $tableAliasbool $paidPauseSec false): string
  1087.     {
  1088.         $select '';
  1089.         for ($num 1$num <= Machine::maxServiceNum$num++) {
  1090.             $select .= ($select " + " '') . "$tableAlias.service{$num}sec";
  1091.         }
  1092.         if ($paidPauseSec) {
  1093.             $select .= " + $tableAlias.paid_pause_sec";
  1094.         }
  1095.         return $select;
  1096.     }
  1097.     public function getSessionAmountsSumSelectSql(string $tableAlias): string
  1098.     {
  1099.         $arrayFields = ['coin_amount''note_amount''no_cash_amount''cash_sess''card_sess''bonus_for_session'];
  1100.         $select "";
  1101.         foreach ($arrayFields as $field) {
  1102.             $select .= ($select ",\n " "") . "IFNULL(SUM($tableAlias.$field), 0) as $field";
  1103.         }
  1104.         return $select;
  1105.     }
  1106.     public function getMachinePaymentsSummary(array $data): float
  1107.     {
  1108.         return $data["payments_qr_amount"] + $data["payments_yandex_amount"];
  1109.     }
  1110.     public function getMachinesMethodParameter($machine)
  1111.     {
  1112.         $machines $machine;
  1113.         if (!is_array($machines)) {
  1114.             $machines = [$machine];
  1115.         }
  1116.         return $machines;
  1117.     }
  1118.     /**
  1119.      * @return null
  1120.      */
  1121.     public function getEntityClassName()
  1122.     {
  1123.         return $this->entityClassName;
  1124.     }
  1125.     public function getIncomeMoneyFields(bool $refusual false): array
  1126.     {
  1127.         $result = ["coin_amount""note_amount""no_cash_amount""ping_amount""qr_amount"];
  1128.         if ($refusual) {
  1129.             $result[] = "refusual";
  1130.         }
  1131.         return $result;
  1132.     }
  1133.     public function getAllMoneyFields(): array
  1134.     {
  1135.         return ["note_amount""no_cash_amount""payments_qr_amount""payments_yandex_amount""refusual",
  1136.             "gross_profit""server_bonus""bonus_for_session""card_sess"];
  1137.     }
  1138.     public function getServiceSecFields(): array
  1139.     {
  1140.         if (self::$serviceSecFields) {
  1141.             return self::$serviceSecFields;
  1142.         }
  1143.         $result = [];
  1144.         for ($i 1$i <= Machine::maxServiceNum$i++) {
  1145.             $result[] = "service{$i}sec";
  1146.         }
  1147.         $result[] = "paid_pause_sec";
  1148.         self::$serviceSecFields $result;
  1149.         return $result;
  1150.     }
  1151.     public function createOrGetDefault(array $params)
  1152.     {
  1153.         $item $this->getFirst($params);
  1154.         if (!$item) {
  1155.             $item = (new $this->entityClassName());
  1156.             foreach ($params as $key => $value) {
  1157.                 $setter 'set' ucfirst($key);
  1158.                 $item->$setter($value);
  1159.             }
  1160.             $this->saveDefault($item);
  1161.         }
  1162.         return $item;
  1163.     }
  1164.     public function saveDefault($item)
  1165.     {
  1166.         $this->em->persist($item);
  1167.         $this->em->flush();
  1168.     }
  1169.     public function removeDefault($item$flush true)
  1170.     {
  1171.         $this->em->remove($item);
  1172.         if ($flush) {
  1173.             $this->em->flush();
  1174.         }
  1175.     }
  1176.     public function serializeDefault($item, array $includeFields null, array $excludeFields null): string
  1177.     {
  1178.         return $this->serializer->serialize($item'json', [
  1179.             'attributes' => $includeFields,
  1180.             'ignored_attributes' => $excludeFields
  1181.         ]);
  1182.     }
  1183.     public function getSameItemCheckFields(): array
  1184.     {
  1185.         throw new \Exception("Not implemented");
  1186.     }
  1187.     public function hasSameDefault($item): bool
  1188.     {
  1189.         $fields $this->getSameItemCheckFields();
  1190.         $criteria = [];
  1191.         foreach ($fields as $field) {
  1192.             $getter 'get' ucfirst($field);
  1193.             if ($item->$getter() !== null) {
  1194.                 $criteria[$field] = $item->$getter();
  1195.             }
  1196.         }
  1197.         $same $this->getDefault($criteria);
  1198.         foreach ($same as $sameItem) {
  1199.             $itemHasDeletedStatus $this->hasDeletedStatus($item);
  1200.             $sameHasDeletedStatus $this->hasDeletedStatus($sameItem);
  1201.             $oneHasDeletedStatus $sameHasDeletedStatus && !$itemHasDeletedStatus
  1202.                 || !$sameHasDeletedStatus && $itemHasDeletedStatus;
  1203.             if ($sameItem->getId() != $item->getId() && !$oneHasDeletedStatus) {
  1204.                 return true;
  1205.             }
  1206.         }
  1207.         return false;
  1208.     }
  1209.     public function getStatusIfExists($entity): ?string
  1210.     {
  1211.         if (method_exists($entity"getStatus")) {
  1212.             return $entity->getStatus();
  1213.         }
  1214.         return null;
  1215.     }
  1216.     public function hasDeletedStatus($entity): bool
  1217.     {
  1218.         return $this->getStatusIfExists($entity) == "deleted";
  1219.     }
  1220.     public function removeForeignKeyConstraintEntities($entity$foreignEntitystring $foreignEntityField)
  1221.     {
  1222.         if ($foreignEntity) {
  1223.             $this->em->remove($foreignEntity);
  1224.         }
  1225.         if ($entity) {
  1226.             $setter 'set' ucfirst($foreignEntityField);
  1227.             $entity->$setter(null);
  1228.             $this->em->flush();
  1229.         } else {
  1230.             $this->em->flush();
  1231.         }
  1232.         $this->removeDefault($entity);
  1233.     }
  1234. }