vendor/welshdev/doctrine-base-repository/src/BaseRepository.php line 196

Open in your IDE?
  1. <?php
  2. namespace WelshDev\DoctrineBaseRepository;
  3. use Doctrine\ORM\EntityRepository;
  4. use Doctrine\ORM\QueryBuilder;
  5. use Doctrine\ORM\Query\Expr\Composite;
  6. class BaseRepository extends EntityRepository
  7. {
  8.     protected $namedParamCounter 0;
  9.     protected $joins = array();
  10.     protected $disableJoins false;
  11.     protected $setupFunction null;
  12.     public function disableJoins(bool $disableJoins)
  13.     {
  14.         $this->disableJoins $disableJoins;
  15.         return $this;
  16.     }
  17.     public function countRows(string $column, array $filters = array())
  18.     {
  19.         // Get query builder
  20.         $queryBuilder $this->buildQuery($filters);
  21.         // Select the count
  22.         $queryBuilder->select('count(' $column ')');
  23.         // Get the query
  24.         $query $queryBuilder->getQuery();
  25.         return $query->getSingleScalarResult();
  26.     }
  27.     public function setup(callable $callback)
  28.     {
  29.         $this->setupFunction $callback;
  30.         return $this;
  31.     }
  32.     public function findFiltered(array $filters = array(), $order = array(), $limit null$offset 0)
  33.     {
  34.         // Get query builder
  35.         $queryBuilder $this->buildQuery($filters$order$limit$offset);
  36.         // Get the query
  37.         $query $queryBuilder->getQuery();
  38.         // Execute and return
  39.         return $query->getResult();
  40.     }
  41.     public function findOneFiltered(array $filters = array(), $order = array(), $offset 0)
  42.     {
  43.         // Get query builder
  44.         $queryBuilder $this->buildQuery($filters$order1$offset);
  45.         // Get the query
  46.         $query $queryBuilder->getQuery();
  47.         // Execute and return
  48.         return $query->getOneOrNullResult();
  49.     }
  50.     public function buildQuery(array $filters = array(), $order = array(), $limit null$offset 0, array $opt = [])
  51.     {
  52.         // Create the query builder
  53.         $queryBuilder $this->createQueryBuilder($this->alias)
  54.             ->select(array(
  55.                 $this->alias
  56.             ));
  57.         // Got a setup function?
  58.         if(is_callable($this->setupFunction))
  59.             $queryBuilder call_user_func($this->setupFunction$this->alias$queryBuilder);
  60.         // Defaults options
  61.         $opt array_merge(array(
  62.             'disable_joins' => false
  63.         ), $opt);
  64.         // Any joins?
  65.         if(count($this->joins) && !$opt['disable_joins'] && !$this->disableJoins)
  66.         {
  67.             // Loop joins
  68.             foreach($this->joins AS $someJoin)
  69.             {
  70.                 list($joinType$joinColumn$joinTable) = $someJoin;
  71.                 // Not got a dot, prefix table alias
  72.                 if(stripos($joinColumn".") === false)
  73.                     $joinColumn $this->alias "." $joinColumn;
  74.                 // Join
  75.                 $queryBuilder->{$joinType}($joinColumn$joinTable);
  76.             }
  77.         }
  78.         // Order
  79.         if(count($order))
  80.         {
  81.             // Loop columns to order
  82.             foreach($order AS $key => $val)
  83.             {
  84.                 // Not got a dot, prefix table alias
  85.                 if(stripos($key".") === false)
  86.                     $key $this->alias "." $key;
  87.                 $queryBuilder->addOrderBy($key$val);
  88.             }
  89.         }
  90.         // Limit
  91.         if($limit)
  92.             $queryBuilder->setMaxResults($limit);
  93.         // Offset
  94.         if($offset)
  95.             $queryBuilder->setFirstResult($offset);
  96.         // Got any filters?
  97.         if(count($filters))
  98.         {
  99.             // Add the where
  100.             $queryBuilder->where($this->addCriteria($queryBuilder$queryBuilder->expr()->andX(), $filters));
  101.         }
  102.         return $queryBuilder;
  103.     }
  104.     public function addCriteria(QueryBuilder $queryBuilderComposite $expr, array $criteria)
  105.     {
  106.         $em $this->getEntityManager();
  107.         if(count($criteria))
  108.         {
  109.             foreach($criteria AS $k => $v)
  110.             {
  111.                 // Numeric (i.e. it's being passed in as an operator e.g. ["id", "eq", 999])
  112.                 if(is_numeric($k))
  113.                 {
  114.                     // Not an array
  115.                     if(!is_array($v))
  116.                         throw new \Exception("Non-indexed criteria must be in array form e.g. ['id', 'eq', 1234]");
  117.                     // Extract
  118.                     if(count($v) == 3)
  119.                         list($field$operator$value) = $v;
  120.                     else
  121.                     {
  122.                         list($field$operator) = $v;
  123.                         // Default value of true
  124.                         $value true;
  125.                     }
  126.                     // Is this a special case i.e. or/and
  127.                     if(in_array($field, array("or""and")))
  128.                     {
  129.                         // Move things around
  130.                         $value $operator;
  131.                         $operator $field;
  132.                         // Field is no longer used
  133.                         $field null;
  134.                     }
  135.                 }
  136.                 // Indexed (e.g. ["id" => 1234])
  137.                 else
  138.                 {
  139.                     // Is the value an array?
  140.                     if(is_array($v))
  141.                         throw new \Exception("Indexed criteria does not support array values");
  142.                     // Is the value null?
  143.                     if(is_null($v))
  144.                     {
  145.                         // Use "is_null" operator
  146.                         $field $k;
  147.                         $operator "is_null";
  148.                         $value true;
  149.                     }
  150.                     else
  151.                     {
  152.                         // Default to "eq" operator
  153.                         $field $k;
  154.                         $operator "eq";
  155.                         $value $v;
  156.                     }
  157.                 }
  158.                 // Not got a dot, prefix table alias
  159.                 if(stripos($field".") === false)
  160.                     $field $this->alias "." $field;
  161.                 // Or
  162.                 if($operator === 'or')
  163.                     $expr->add($this->addCriteria($queryBuilder$queryBuilder->expr()->orX(), $value));
  164.                 // And
  165.                 elseif($operator === 'and')
  166.                     $expr->add($this->addCriteria($queryBuilder$queryBuilder->expr()->andX(), $value));
  167.                 // Basic operators
  168.                 elseif(in_array($operator, array("eq""neq""gt""gte""lt""lte""like")))
  169.                 {
  170.                     // Arrays not supported for this operator
  171.                     if(is_array($value))
  172.                         throw new \Exception("Array lookups are not supported for the '" $operator "' operator");
  173.                     // DateTime
  174.                     if(is_object($value) && $value instanceof \DateTime)
  175.                     {
  176.                         $expr->add($queryBuilder->expr()->{$operator}($field$this->createNamedParameter($queryBuilder$this->prepareValue($value))));
  177.                     }
  178.                     // Other object (likely an association)
  179.                     elseif(is_object($value))
  180.                     {
  181.                         $expr->add($queryBuilder->expr()->{$operator}($field$this->createNamedParameter($queryBuilder$this->prepareValue($value))));
  182.                     }
  183.                     // Is it null?
  184.                     elseif(is_null($value))
  185.                     {
  186.                         $expr->add($queryBuilder->expr()->isNull($field));
  187.                     }
  188.                     else
  189.                     {
  190.                         // Literal
  191.                         $expr->add($queryBuilder->expr()->{$operator}($field$this->createNamedParameter($queryBuilder$this->prepareValue($value))));
  192.                     }
  193.                 }
  194.                 // Null operator
  195.                 elseif(in_array($operator, array("is_null""not_null")))
  196.                 {
  197.                     // Is null
  198.                     if($operator == "is_null")
  199.                     {
  200.                         // True or false value?
  201.                         if($value)
  202.                             $expr->add($queryBuilder->expr()->isNull($field));
  203.                         else
  204.                             $expr->add($queryBuilder->expr()->isNotNull($field));
  205.                     }
  206.                     // Not null
  207.                     elseif($operator == "not_null")
  208.                     {
  209.                         // True or false value?
  210.                         if($value)
  211.                             $expr->add($queryBuilder->expr()->isNotNull($field));
  212.                         else
  213.                             $expr->add($queryBuilder->expr()->isNull($field));
  214.                     }
  215.                 }
  216.                 // In/NotIn operators
  217.                 elseif(in_array($operator, array("in""not_in")))
  218.                 {
  219.                     // Make sure it's an array
  220.                     if(!is_array($value))
  221.                         throw new \Exception("Invalid value for operator: " $operator);
  222.                     // In
  223.                     if($operator == "in")
  224.                         $expr->add($queryBuilder->expr()->in($field$this->createNamedParameter($queryBuilder$this->prepareValue($value))));
  225.                     // Not in
  226.                     elseif($operator == "not_in")
  227.                     {
  228.                         // Need to use multiple != operations because "NOT IN" is not null-safe
  229.                         // We therefore loop the values and build the SQL string
  230.                         // Hold the array
  231.                         $builtArraySQL = array();
  232.                         // Loop the values
  233.                         foreach($this->prepareValue($value) AS $someValue)
  234.                         {
  235.                             // Is it null?
  236.                             if(is_null($someValue))
  237.                             {
  238.                                 // Make sure we don't return if null
  239.                                 $builtArraySQL[] = '(' $field ' IS NOT NULL)';
  240.                             }
  241.                             else
  242.                             {
  243.                                 // Where (field = value OR field IS NULL)
  244.                                 // This is done because != is not null safe and would therefore not return anything with null values
  245.                                 $builtArraySQL[] = '(' $field ' != ' $this->createNamedParameter($queryBuilder$someValue) . ' OR ' $field ' IS NULL)';
  246.                             }
  247.                         }
  248.                         // Got anything?
  249.                         if(count($builtArraySQL))
  250.                         {
  251.                             // Implode into full array
  252.                             $fullSQL "(" implode($builtArraySQL' AND ') . ")";
  253.                             // Add it
  254.                             $expr->add($fullSQL);
  255.                         }
  256.                     }
  257.                 }
  258.                 // Unsupported operator
  259.                 else
  260.                     throw new \Exception("Unsupported operator: " $operator);
  261.             }
  262.         }
  263.         else
  264.             throw new \Exception("Empty criteria");
  265.         return $expr;
  266.     }
  267.     public function createNamedParameter(QueryBuilder $queryBuilder$value)
  268.     {
  269.         // Increase count
  270.         $this->namedParamCounter++;
  271.         // Create the new placeholder
  272.         $placeHolder ':paramValue' $this->namedParamCounter;
  273.         // Set the parameter
  274.         $queryBuilder->setParameter(substr($placeHolder1), $value);
  275.         return $placeHolder;
  276.     }
  277.     public function prepareValue($value)
  278.     {
  279.         // DateTime
  280.         if(is_object($value) && $value instanceof \DateTime)
  281.         {
  282.             return $value->format('Y-m-d H:i:s');
  283.         }
  284.         // Object
  285.         elseif(is_object($value))
  286.         {
  287.             return $value;
  288.         }
  289.         // Array
  290.         elseif(is_array($value))
  291.         {
  292.             // Loop
  293.             foreach($value AS $k => $v)
  294.             {
  295.                 // Prepare it
  296.                 $value[$k] = $this->prepareValue($v);
  297.             }
  298.             return $value;
  299.         }
  300.         // Anything else
  301.         else
  302.             return $value;
  303.     }
  304.     public function buildSearchCriteria(string $keywords, array $searchableColumns = array())
  305.     {
  306.         // Not no searchable columns
  307.         if(!count($searchableColumns))
  308.             throw new \Exception("No searchable columns specified");
  309.         // Explode individual keywords
  310.         $keywords array_filter(explode(" "trim($keywords)));
  311.         // Hold the keyword criteria
  312.         $keywordCriteria = array();
  313.         // Loop keywords
  314.         foreach($keywords AS $someKeyword)
  315.         {
  316.             // Grab this group
  317.             $keywordGroup = array();
  318.             // Loop search columns
  319.             foreach($searchableColumns AS $searchColumn)
  320.             {
  321.                 // Grab it
  322.                 $keywordGroup[] = array($searchColumn"like""%" $someKeyword "%");
  323.             }
  324.             // Add this group the main array
  325.             $keywordCriteria[] = array("or"$keywordGroup);
  326.         }
  327.         // Return the 'and' array
  328.         return array("and"$keywordCriteria);
  329.     }
  330. }