Lançado Adianti Framework 7.6!
Clique aqui para saber mais
menu

Adianti Solutions

API

Adianti, Framework, PHP, MVC, Active record, Front controller, IDE, RAD, Web, multiplataforma, geração de código, desenvolvimento rápido, relatórios, formulários, listagens, datagrids, gráficos, banco de dados, padrões de projeto, design patterns API do Adianti Framework.
API Docs
code
Selecione a classe

Source for file TRepository.php

Documentation is available at TRepository.php

  1. <?php
  2. namespace Adianti\Database;
  3.  
  4. use Adianti\Core\AdiantiCoreTranslator;
  5. use Adianti\Database\TRecord;
  6. use Adianti\Database\TCriteria;
  7. use Adianti\Database\TFilter;
  8. use Adianti\Database\TSqlSelect;
  9.  
  10. use PDO;
  11. use Exception;
  12. use ReflectionMethod;
  13. use ReflectionClass;
  14.  
  15. /**
  16.  * Implements the Repository Pattern to deal with collections of Active Records
  17.  *
  18.  * @version    7.4
  19.  * @package    database
  20.  * @author     Pablo Dall'Oglio
  21.  * @copyright  Copyright (c) 2006 Adianti Solutions Ltd. (http://www.adianti.com.br)
  22.  * @license    http://www.adianti.com.br/framework-license
  23.  */
  24. {
  25.     protected $class// Active Record class to be manipulated
  26.     protected $trashed;
  27.     protected $criteria// buffered criteria to use with fluent interfaces
  28.     protected $setValues;
  29.     protected $columns;
  30.     protected $aggregates;
  31.     
  32.     /**
  33.      * Class Constructor
  34.      * @param $class = Active Record class name
  35.      */
  36.     public function __construct($class$withTrashed FALSE)
  37.     {
  38.         if (class_exists($class))
  39.         {
  40.             if (is_subclass_of($class'TRecord'))
  41.             {
  42.                 $this->class = $class;
  43.                 $this->trashed = $withTrashed;
  44.                 $this->criteria = new TCriteria;
  45.             }
  46.             else
  47.             {
  48.                 throw new Exception(AdiantiCoreTranslator::translate('The class ^1 was not accepted as argument. The class informed as parameter must be subclass of ^2.'$class'TRecord'));
  49.             }
  50.         }
  51.         else
  52.         {
  53.             throw new Exception(AdiantiCoreTranslator::translate('The class ^1 was not found. Check the class name or the file name. They must match''"' $class '"'));
  54.         }
  55.         
  56.         $this->aggregates = [];
  57.     }
  58.     
  59.     /**
  60.      * Set criteria
  61.      */
  62.     public function setCriteria(TCriteria $criteria)
  63.     {
  64.         $this->criteria = $criteria;
  65.     }
  66.  
  67.     /**
  68.      * Set withTrashed using fluent interfaces
  69.      */
  70.     public function withTrashed()
  71.     {
  72.         $this->trashed = true;
  73.         return $this;
  74.     }
  75.  
  76.     /**
  77.      * Returns the name of database entity
  78.      * @return String containing the name of the entity
  79.      */
  80.     protected function getEntity()
  81.     {
  82.         return constant($this->class.'::TABLENAME');
  83.     }
  84.     
  85.     /**
  86.      * Get attribute list from entity
  87.      */
  88.     protected function getAttributeList()
  89.     {
  90.         if (!empty($this->columns))
  91.         {
  92.             return implode(', '$this->columns);
  93.         }
  94.         else
  95.         {
  96.             $object new $this->class;
  97.             return $object->getAttributeList();
  98.         }
  99.     }
  100.     
  101.     /**
  102.      * Define columns list
  103.      */
  104.     public function select($columns)
  105.     {
  106.         $this->columns = $columns;
  107.         return $this;
  108.     }
  109.     
  110.     /**
  111.      * Add a run time criteria using fluent interfaces
  112.      * 
  113.      * @param  $variable = variable
  114.      * @param  $operator = comparison operator (>,<,=)
  115.      * @param  $value    = value to be compared
  116.      * @param  $logicOperator = logical operator (TExpression::AND_OPERATOR, TExpression::OR_OPERATOR)
  117.      * @return TRepository object
  118.      */
  119.     public function where($variable$operator$value$logicOperator TExpression::AND_OPERATOR)
  120.     {
  121.         $this->criteria->add(new TFilter($variable$operator$value)$logicOperator);
  122.         
  123.         return $this;
  124.     }
  125.     
  126.     /**
  127.      * Assign values to the database columns
  128.      * 
  129.      * @param  $column = column name
  130.      * @param  $value  = column value
  131.      * @return TRepository object
  132.      */
  133.     public function set($column$value)
  134.     {
  135.         if (is_scalar($valueOR is_null($value))
  136.         {
  137.             $this->setValues[$column$value;
  138.         }
  139.         
  140.         return $this;
  141.     }
  142.     
  143.     /**
  144.      * Add a run time OR criteria using fluent interfaces
  145.      * 
  146.      * @param  $variable = variable
  147.      * @param  $operator = comparison operator (>,<,=)
  148.      * @param  $value    = value to be compared
  149.      * @return TRepository object
  150.      */
  151.     public function orWhere($variable$operator$value)
  152.     {
  153.         $this->criteria->add(new TFilter($variable$operator$value)TExpression::OR_OPERATOR);
  154.         
  155.         return $this;
  156.     }
  157.     
  158.     /**
  159.      * Define the ordering for criteria using fluent interfaces
  160.      * 
  161.      * @param  $order = Order column
  162.      * @param  $direction = Order direction (asc, desc)
  163.      * @return TRepository object
  164.      */
  165.     public function orderBy($order$direction 'asc')
  166.     {
  167.         $this->criteria->setProperty('order'$order);
  168.         $this->criteria->setProperty('direction'$direction);
  169.         
  170.         return $this;
  171.     }
  172.     
  173.     /**
  174.      * Define the group for criteria using fluent interfaces
  175.      * 
  176.      * @param  $group Group column
  177.      * @return TRepository object
  178.      */
  179.     public function groupBy($group)
  180.     {
  181.         $this->criteria->setProperty('group'$group);
  182.         
  183.         return $this;
  184.     }
  185.     
  186.     /**
  187.      * Define the LIMIT criteria using fluent interfaces
  188.      * 
  189.      * @param  $limit = Limit
  190.      * @return TRepository object
  191.      */
  192.     public function take($limit)
  193.     {
  194.         $this->criteria->setProperty('limit'$limit);
  195.         
  196.         return $this;
  197.     }
  198.     
  199.     /**
  200.      * Define the OFFSET criteria using fluent interfaces
  201.      * 
  202.      * @param  $offset = Offset
  203.      * @return TRepository object
  204.      */
  205.     public function skip($offset)
  206.     {
  207.         $this->criteria->setProperty('offset'$offset);
  208.         
  209.         return $this;
  210.     }
  211.     
  212.     /**
  213.      * Load a collection       of objects from database using a criteria
  214.      * @param $criteria        An TCriteria object, specifiyng the filters
  215.      * @param $callObjectLoad  If load() method from Active Records must be called to load object parts
  216.      * @return                 An array containing the Active Records
  217.      */
  218.     public function load(TCriteria $criteria NULL$callObjectLoad TRUE)
  219.     {
  220.         if (!$criteria)
  221.         {
  222.             $criteria = isset($this->criteria$this->criteria : new TCriteria;
  223.         }
  224.  
  225.         $deletedat $this->class::getDeletedAtColumn();
  226.         
  227.         if (!$this->trashed && $deletedat)
  228.         {
  229.             $criteria->add(new TFilter($deletedat'IS'NULL));
  230.         }
  231.  
  232.         // creates a SELECT statement
  233.         $sql new TSqlSelect;
  234.         $sql->addColumn($this->getAttributeList());
  235.         $sql->setEntity($this->getEntity());
  236.         // assign the criteria to the SELECT statement
  237.         $sql->setCriteria($criteria);
  238.         
  239.         // get the connection of the active transaction
  240.         if ($conn TTransaction::get())
  241.         {
  242.             // register the operation in the LOG file
  243.             TTransaction::log($sql->getInstruction());
  244.             $dbinfo TTransaction::getDatabaseInfo()// get dbinfo
  245.             if (isset($dbinfo['prep']AND $dbinfo['prep'== '1'// prepared ON
  246.             {
  247.                 $result $conn-> prepare $sql->getInstructionTRUE array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
  248.                 $result-> execute $criteria->getPreparedVars() );
  249.             }
  250.             else
  251.             {
  252.                 // execute the query
  253.                 $result$conn-> query($sql->getInstruction());
  254.             }
  255.             $results array();
  256.             
  257.             $class $this->class;
  258.             $callback array($class'load')// bypass compiler
  259.             
  260.             // Discover if load() is overloaded
  261.             $rm new ReflectionMethod($class$callback[1]);
  262.             
  263.             if ($result)
  264.             {
  265.                 // iterate the results as objects
  266.                 while ($raw $result-> fetchObject())
  267.                 {
  268.                     $object new $this->class;
  269.                     if (method_exists($object'onAfterLoadCollection'))
  270.                     {
  271.                         $object->onAfterLoadCollection($raw);
  272.                     }
  273.                     $object->fromArray(array) $raw);
  274.                     
  275.                     if ($callObjectLoad)
  276.                     {
  277.                         // reload the object because its load() method may be overloaded
  278.                         if ($rm->getDeclaringClass()-> getName (!== 'Adianti\Database\TRecord')
  279.                         {
  280.                             $object->reload();
  281.                         }
  282.                     }
  283.                     
  284.                     if ( ($cache $object->getCacheControl()) && empty($this->columns))
  285.                     {
  286.                         $pk $object->getPrimaryKey();
  287.                         $record_key $class '['$object->$pk ']';
  288.                         if ($cache::setValue$record_key$object->toArray() ))
  289.                         {
  290.                             TTransaction::log($record_key ' stored in cache');
  291.                         }
  292.                     }
  293.                     // store the object in the $results array
  294.                     $results[$object;
  295.                 }
  296.             }
  297.             return $results;
  298.         }
  299.         else
  300.         {
  301.             // if there's no active transaction opened
  302.             throw new Exception(AdiantiCoreTranslator::translate('No active transactions'': ' . __METHOD__ .' '$this->getEntity());
  303.         }
  304.     }
  305.     
  306.     /**
  307.      * Load with no aggregates
  308.      */
  309.     public function loadStatic()
  310.     {
  311.         return $this->load(nullfalse);
  312.     }
  313.     
  314.     /**
  315.      * Return a indexed array
  316.      */
  317.     public function getIndexedArray($indexColumn$valueColumn NULL$criteria NULL)
  318.     {
  319.         if (is_null($valueColumn))
  320.         {
  321.             $valueColumn $indexColumn;
  322.         }
  323.         
  324.         $criteria (empty($criteria)) $this->criteria : $criteria;
  325.         $objects $this->load($criteriaFALSE);
  326.         
  327.         $indexedArray array();
  328.         if ($objects)
  329.         {
  330.             foreach ($objects as $object)
  331.             {
  332.                 $key (isset($object->$indexColumn)) $object->$indexColumn $object->render($indexColumn);
  333.                 $val (isset($object->$valueColumn)) $object->$valueColumn $object->render($valueColumn);
  334.                 
  335.                 $indexedArray$key $val;
  336.             }
  337.         }
  338.         
  339.         if (empty($criteriaor $criteria instanceof TCriteria and empty($criteria->getProperty('order')) ))
  340.         {
  341.             asort($indexedArray);
  342.         }
  343.         return $indexedArray;
  344.     }
  345.     
  346.     /**
  347.      * Update values in the repository
  348.      */
  349.     public function update($setValues NULLTCriteria $criteria NULL)
  350.     {
  351.         if (!$criteria)
  352.         {
  353.             $criteria = isset($this->criteria$this->criteria : new TCriteria;
  354.         }
  355.  
  356.         $deletedat $this->class::getDeletedAtColumn();
  357.         
  358.         if (!$this->trashed && $deletedat)
  359.         {
  360.             $criteria->add(new TFilter($deletedat'IS'NULL));
  361.         }
  362.  
  363.         $setValues = isset($setValues$setValues $this->setValues;
  364.         
  365.         $class $this->class;
  366.         
  367.         // get the connection of the active transaction
  368.         if ($conn TTransaction::get())
  369.         {
  370.             $dbinfo TTransaction::getDatabaseInfo()// get dbinfo
  371.             
  372.             // creates a UPDATE statement
  373.             $sql new TSqlUpdate;
  374.             if ($setValues)
  375.             {
  376.                 foreach ($setValues as $column => $value)
  377.                 {
  378.                     $sql->setRowData($column$value);
  379.                 }
  380.             }
  381.             $sql->setEntity($this->getEntity());
  382.             // assign the criteria to the UPDATE statement
  383.             $sql->setCriteria($criteria);
  384.             
  385.             if (isset($dbinfo['prep']AND $dbinfo['prep'== '1'// prepared ON
  386.             {
  387.                 $statement $conn-> prepare $sql->getInstructionTRUE array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
  388.                 $result $statement-> execute $sql->getPreparedVars() );
  389.             }
  390.             else
  391.             {
  392.                 // execute the UPDATE statement
  393.                 $result $conn->exec($sql->getInstruction());
  394.             }
  395.             
  396.             // register the operation in the LOG file
  397.             TTransaction::log($sql->getInstruction());
  398.             
  399.             // update cache
  400.             $record new $class;
  401.             if $cache $record->getCacheControl() )
  402.             {
  403.                 $pk $record->getPrimaryKey();
  404.                 
  405.                 // creates a SELECT statement
  406.                 $sql new TSqlSelect;
  407.                 $sql->addColumn($this->getAttributeList());
  408.                 $sql->setEntity($this->getEntity());
  409.                 // assign the criteria to the SELECT statement
  410.                 $sql->setCriteria($criteria);
  411.                 
  412.                 if (isset($dbinfo['prep']AND $dbinfo['prep'== '1'// prepared ON
  413.                 {
  414.                     $subresult $conn-> prepare $sql->getInstructionTRUE array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
  415.                     $subresult-> execute $criteria->getPreparedVars() );
  416.                 }
  417.                 else
  418.                 {
  419.                     $subresult $conn-> query($sql->getInstruction());
  420.                 }
  421.                 
  422.                 if ($subresult)
  423.                 {
  424.                     // iterate the results as objects
  425.                     while ($raw $subresult-> fetchObject())
  426.                     {
  427.                         $object new $this->class;
  428.                         $object->fromArray(array) $raw);
  429.                     
  430.                         $record_key $class '['$raw->$pk ']';
  431.                         if ($cache::setValue$record_key$object->toArray() ))
  432.                         {
  433.                             TTransaction::log($record_key ' stored in cache');
  434.                         }
  435.                     }
  436.                 }
  437.             }
  438.             
  439.             return $result;
  440.         }
  441.         else
  442.         {
  443.             // if there's no active transaction opened
  444.             throw new Exception(AdiantiCoreTranslator::translate('No active transactions'': ' . __METHOD__ .' '$this->getEntity());
  445.         }
  446.     }
  447.     
  448.     /**
  449.      * Delete a collection of Active Records from database
  450.      * @param $criteria  An TCriteria object, specifiyng the filters
  451.      * @return           The affected rows
  452.      */
  453.     public function delete(TCriteria $criteria NULL$callObjectLoad FALSE)
  454.     {
  455.         if (!$criteria)
  456.         {
  457.             $criteria = isset($this->criteria$this->criteria : new TCriteria;
  458.         }
  459.  
  460.         $deletedat $this->class::getDeletedAtColumn();
  461.         
  462.         if (!$this->trashed && $deletedat)
  463.         {
  464.             $criteria->add(new TFilter($deletedat'IS'NULL));
  465.         }
  466.         
  467.         $class $this->class;
  468.         
  469.         // get the connection of the active transaction
  470.         if ($conn TTransaction::get())
  471.         {
  472.             $dbinfo TTransaction::getDatabaseInfo()// get dbinfo
  473.             
  474.             // first, clear cache
  475.             $record new $class;
  476.             if ( ($cache $record->getCacheControl()) OR $callObjectLoad )
  477.             {
  478.                 $pk $record->getPrimaryKey();
  479.                 
  480.                 // creates a SELECT statement
  481.                 $sql new TSqlSelect;
  482.                 $sql->addColumn$pk );
  483.                 $sql->setEntity($this->getEntity());
  484.                 // assign the criteria to the SELECT statement
  485.                 $sql->setCriteria($criteria);
  486.                 
  487.                 if (isset($dbinfo['prep']AND $dbinfo['prep'== '1'// prepared ON
  488.                 {
  489.                     $result $conn-> prepare $sql->getInstructionTRUE array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
  490.                     $result-> execute $criteria->getPreparedVars() );
  491.                 }
  492.                 else
  493.                 {
  494.                     $result $conn-> query($sql->getInstruction());
  495.                 }
  496.                 
  497.                 if ($result)
  498.                 {
  499.                     // iterate the results as objects
  500.                     while ($row $result-> fetchObject())
  501.                     {
  502.                         if ($cache)
  503.                         {
  504.                             $record_key $class '['$row->$pk ']';
  505.                             if ($cache::delValue$record_key ))
  506.                             {
  507.                                 TTransaction::log($record_key ' deleted from cache');
  508.                             }
  509.                         }
  510.                         
  511.                         if ($callObjectLoad)
  512.                         {
  513.                             $object new $this->class;
  514.                             $object->fromArray(array) $row);
  515.                             $object->delete();
  516.                         }
  517.                     }
  518.                 }
  519.             }
  520.             
  521.             if ($deletedat)
  522.             {
  523.                 // creates a Update instruction
  524.                 $sql new TSqlUpdate;
  525.                 $sql->setEntity($this->getEntity());
  526.  
  527.                 $info TTransaction::getDatabaseInfo();
  528.                 $date_mask (in_array($info['type']['sqlsrv''dblib''mssql'])) 'Ymd H:i:s' 'Y-m-d H:i:s';
  529.                 $sql->setRowData($deletedatdate($date_mask));
  530.             }
  531.             else
  532.             {
  533.                 // creates a DELETE statement
  534.                 $sql new TSqlDelete;
  535.                 $sql->setEntity($this->getEntity());
  536.             }
  537.  
  538.             // assign the criteria to the DELETE statement
  539.             $sql->setCriteria($criteria);
  540.             
  541.             if (isset($dbinfo['prep']AND $dbinfo['prep'== '1'// prepared ON
  542.             {
  543.                 $result $conn-> prepare $sql->getInstructionTRUE array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
  544.                 
  545.                 if ($sql instanceof TSqlUpdate)
  546.                 {
  547.                     $result-> execute ($sql->getPreparedVars());
  548.                 }
  549.                 else
  550.                 {
  551.                     $result-> execute ($criteria->getPreparedVars());
  552.                 }
  553.             }
  554.             else
  555.             {
  556.                 // execute the DELETE statement
  557.                 $result $conn->exec($sql->getInstruction());
  558.             }
  559.             
  560.             // register the operation in the LOG file
  561.             TTransaction::log($sql->getInstruction());
  562.             
  563.             return $result;
  564.         }
  565.         else
  566.         {
  567.             // if there's no active transaction opened
  568.             throw new Exception(AdiantiCoreTranslator::translate('No active transactions'': ' . __METHOD__ .' '$this->getEntity());
  569.         }
  570.     }
  571.     
  572.     /**
  573.      * Return the amount of objects that satisfy a given criteria
  574.      * @param $criteria  An TCriteria object, specifiyng the filters
  575.      * @return           An Integer containing the amount of objects that satisfy the criteria
  576.      */
  577.     public function count(TCriteria $criteria NULL)
  578.     {
  579.         if (!$criteria)
  580.         {
  581.             $criteria = isset($this->criteria$this->criteria : new TCriteria;
  582.         }
  583.  
  584.         $deletedat $this->class::getDeletedAtColumn();
  585.         
  586.         if (!$this->trashed && $deletedat)
  587.         {
  588.             $criteria->add(new TFilter($deletedat'IS'NULL));
  589.         }
  590.  
  591.         // creates a SELECT statement
  592.         $sql new TSqlSelect;
  593.         $sql->addColumn('count(*)');
  594.         $sql->setEntity($this->getEntity());
  595.         // assign the criteria to the SELECT statement
  596.         $sql->setCriteria($criteria);
  597.         
  598.         // get the connection of the active transaction
  599.         if ($conn TTransaction::get())
  600.         {
  601.             // register the operation in the LOG file
  602.             TTransaction::log($sql->getInstruction());
  603.             
  604.             $dbinfo TTransaction::getDatabaseInfo()// get dbinfo
  605.             if (isset($dbinfo['prep']AND $dbinfo['prep'== '1'// prepared ON
  606.             {
  607.                 $result $conn-> prepare $sql->getInstructionTRUE array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
  608.                 $result-> execute $criteria->getPreparedVars() );
  609.             }
  610.             else
  611.             {
  612.                 // executes the SELECT statement
  613.                 $result$conn-> query($sql->getInstruction());
  614.             }
  615.             
  616.             if ($result)
  617.             {
  618.                 $row $result->fetch();
  619.                 return $row[0];
  620.             }
  621.         }
  622.         else
  623.         {
  624.             // if there's no active transaction opened
  625.             throw new Exception(AdiantiCoreTranslator::translate('No active transactions'': ' . __METHOD__ .' '$this->getEntity());
  626.         }
  627.     }
  628.     
  629.     /**
  630.      * Count distinct aggregate
  631.      * @param $column  Column to be aggregated
  632.      * @return         An array of objects or the total value (if does not have group by)
  633.      */
  634.     public function countDistinctBy($column$alias null)
  635.     {
  636.         $alias is_null($alias$column $alias;
  637.         return $this->aggregate('count''distinct ' $column$alias);
  638.     }
  639.     
  640.     /**
  641.      * Count aggregate
  642.      * @param $column  Column to be aggregated
  643.      * @param $alias   Column alias
  644.      * @return         An array of objects or the total value (if does not have group by)
  645.      */
  646.     public function countBy($column$alias null)
  647.     {
  648.         return $this->aggregate('count'$column$alias);
  649.     }
  650.     
  651.     /**
  652.      * Count aggregate and do another aggregate after
  653.      * @param $column  Column to be aggregated
  654.      * @param $alias   Column alias
  655.      * @return         self object
  656.      */
  657.     public function countByAnd($column$alias null)
  658.     {
  659.         $this->aggregates["count({$column}) as \"{$alias}\"";
  660.         return $this;
  661.     }
  662.     
  663.     /**
  664.      * Sum aggregate
  665.      * @param $column  Column to be aggregated
  666.      * @param $alias   Column alias
  667.      * @return         An array of objects or the total value (if does not have group by)
  668.      */
  669.     public function sumBy($column$alias null)
  670.     {
  671.         return $this->aggregate('sum'$column$alias);
  672.     }
  673.     
  674.     /**
  675.      * Sum aggregate and do another aggregate after
  676.      * @param $column  Column to be aggregated
  677.      * @param $alias   Column alias
  678.      * @return         self object
  679.      */
  680.     public function sumByAnd($column$alias null)
  681.     {
  682.         $this->aggregates["sum({$column}) as \"{$alias}\"";
  683.         return $this;
  684.     }
  685.     
  686.     /**
  687.      * Average aggregate
  688.      * @param $column  Column to be aggregated
  689.      * @param $alias   Column alias
  690.      * @return         An array of objects or the total value (if does not have group by)
  691.      */
  692.     public function avgBy($column$alias null)
  693.     {
  694.         return $this->aggregate('avg'$column$alias);
  695.     }
  696.     
  697.     /**
  698.      * Average aggregate and do another aggregate after
  699.      * @param $column  Column to be aggregated
  700.      * @param $alias   Column alias
  701.      * @return         self object
  702.      */
  703.     public function avgByAnd($column$alias null)
  704.     {
  705.         $this->aggregates["avg({$column}) as \"{$alias}\"";
  706.         return $this;
  707.     }
  708.     
  709.     /**
  710.      * Min aggregate
  711.      * @param $column  Column to be aggregated
  712.      * @param $alias   Column alias
  713.      * @return         An array of objects or the total value (if does not have group by)
  714.      */
  715.     public function minBy($column$alias null)
  716.     {
  717.         return $this->aggregate('min'$column$alias);
  718.     }
  719.     
  720.     /**
  721.      * Min aggregate and do another aggregate after
  722.      * @param $column  Column to be aggregated
  723.      * @param $alias   Column alias
  724.      * @return         self object
  725.      */
  726.     public function minByAnd($column$alias null)
  727.     {
  728.         $this->aggregates["min({$column}) as \"{$alias}\"";
  729.         return $this;
  730.     }
  731.     
  732.     /**
  733.      * Max aggregate
  734.      * @param $column  Column to be aggregated
  735.      * @param $alias   Column alias
  736.      * @return         An array of objects or the total value (if does not have group by)
  737.      */
  738.     public function maxBy($column$alias null)
  739.     {
  740.         return $this->aggregate('max'$column$alias);
  741.     }
  742.     
  743.     /**
  744.      * Max aggregate and do another aggregate after
  745.      * @param $column  Column to be aggregated
  746.      * @param $alias   Column alias
  747.      * @return         self object
  748.      */
  749.     public function maxByAnd($column$alias null)
  750.     {
  751.         $this->aggregates["max({$column}) as \"{$alias}\"";
  752.         return $this;
  753.     }
  754.     
  755.     /**
  756.      * Aggregate column
  757.      * @param $function Aggregate function (count, sum, min, max, avg)
  758.      * @return          An array of objects or the total value (if does not have group by)
  759.      */
  760.     protected function aggregate($function$column$alias null)
  761.     {
  762.         $criteria = isset($this->criteria$this->criteria : new TCriteria;
  763.         $alias $alias $alias $column;
  764.         // creates a SELECT statement
  765.         $sql new TSqlSelect;
  766.         if (!empty$this->criteria->getProperty('group') ))
  767.         {
  768.             $sql->addColumn$this->criteria->getProperty('group') );
  769.         }
  770.         
  771.         if ($this->aggregates)
  772.         {
  773.             foreach ($this->aggregates as $aggregate)
  774.             {
  775.                 $sql->addColumn($aggregate);
  776.             }
  777.         }
  778.         
  779.         $sql->addColumn("$function({$column}) as \"{$alias}\"");
  780.         
  781.         $sql->setEntity($this->getEntity());
  782.         
  783.         // assign the criteria to the SELECT statement
  784.         $sql->setCriteria($criteria);
  785.         
  786.         // get the connection of the active transaction
  787.         if ($conn TTransaction::get())
  788.         {
  789.             // register the operation in the LOG file
  790.             TTransaction::log($sql->getInstruction());
  791.             
  792.             $dbinfo TTransaction::getDatabaseInfo()// get dbinfo
  793.             if (isset($dbinfo['prep']AND $dbinfo['prep'== '1'// prepared ON
  794.             {
  795.                 $result $conn-> prepare $sql->getInstructionTRUE array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
  796.                 $result-> execute $criteria->getPreparedVars() );
  797.             }
  798.             else
  799.             {
  800.                 // executes the SELECT statement
  801.                 $result$conn-> query($sql->getInstruction());
  802.             }
  803.             
  804.             $results [];
  805.             
  806.             if ($result)
  807.             {
  808.                 // iterate the results as objects
  809.                 while ($raw $result-> fetchObject())
  810.                 {
  811.                     $results[$raw;
  812.                 }
  813.             }
  814.             
  815.             if ($results)
  816.             {
  817.                 if ( (count($results1|| !empty($this->criteria->getProperty('group')))
  818.                 {
  819.                     return $results;
  820.                 }
  821.                 else
  822.                 {
  823.                     return $results[0]->$alias;
  824.                 }
  825.             }
  826.             
  827.             return 0;
  828.         }
  829.         else
  830.         {
  831.             // if there's no active transaction opened
  832.             throw new Exception(AdiantiCoreTranslator::translate('No active transactions'': ' . __METHOD__ .' '$this->getEntity());
  833.         }
  834.     }
  835.     
  836.     /**
  837.      * Alias for load()
  838.      */
  839.     public function get(TCriteria $criteria NULL$callObjectLoad TRUE)
  840.     {
  841.         return $this->load($criteria$callObjectLoad);
  842.     }
  843.     
  844.     /**
  845.      * Returns the first collection item
  846.      */
  847.     public function first($callObjectLoad TRUE)
  848.     {
  849.         $collection $this->take(1)->load(null$callObjectLoad);
  850.         if (isset($collection[0]))
  851.         {
  852.             return $collection[0];
  853.         }
  854.     }
  855.     
  856.     /**
  857.      * Returns the last collection item
  858.      */
  859.     public function last($callObjectLoad TRUE)
  860.     {
  861.         $class $this->class;
  862.         $pk (new $class)->getPrimaryKey();
  863.         
  864.         $collection $this->orderBy($pk,'desc')->take(1)->load(null$callObjectLoad);
  865.         if (isset($collection[0]))
  866.         {
  867.             return $collection[0];
  868.         }
  869.     }
  870.     
  871.     /**
  872.      * Returns transformed collection
  873.      */
  874.     public function transformCallable $callback$callObjectLoad TRUE)
  875.     {
  876.         $collection $this->load(null$callObjectLoad);
  877.         
  878.         if ($collection)
  879.         {
  880.             foreach ($collection as $object)
  881.             {
  882.                 call_user_func($callback$object);
  883.             }
  884.         }
  885.         
  886.         return $collection;
  887.     }
  888.     
  889.     /**
  890.      * Returns filtered collection
  891.      */
  892.     public function filterCallable $callback$callObjectLoad TRUE)
  893.     {
  894.         $collection $this->load(null$callObjectLoad);
  895.         $newcollection [];
  896.         
  897.         if ($collection)
  898.         {
  899.             foreach ($collection as $object)
  900.             {
  901.                 if (call_user_func($callback$object))
  902.                 {
  903.                     $newcollection[$object;
  904.                 }
  905.             }
  906.         }
  907.         
  908.         return $newcollection;
  909.     }
  910.     
  911.     /**
  912.      * Dump Criteria
  913.      */
  914.     public function dump($prepared FALSE)
  915.     {
  916.         if (isset($this->criteriaAND $this->criteria)
  917.         {
  918.             $criteria clone $this->criteria;
  919.             $deletedat $this->class::getDeletedAtColumn();
  920.             
  921.             if (!$this->trashed && $deletedat)
  922.             {
  923.                 $criteria->add(new TFilter($deletedat'IS'NULL));
  924.             }
  925.  
  926.             return $criteria->dump($prepared);
  927.         }
  928.  
  929.         return NULL;
  930.     }
  931. }