FunctionExpression.php 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. <?php
  2. /**
  3. * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  4. * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  5. *
  6. * Licensed under The MIT License
  7. * For full copyright and license information, please see the LICENSE.txt
  8. * Redistributions of files must retain the above copyright notice.
  9. *
  10. * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  11. * @link http://cakephp.org CakePHP(tm) Project
  12. * @since 3.0.0
  13. * @license http://www.opensource.org/licenses/mit-license.php MIT License
  14. */
  15. namespace Cake\Database\Expression;
  16. use Cake\Database\ExpressionInterface;
  17. use Cake\Database\TypedResultInterface;
  18. use Cake\Database\TypedResultTrait;
  19. use Cake\Database\Type\ExpressionTypeCasterTrait;
  20. use Cake\Database\ValueBinder;
  21. /**
  22. * This class represents a function call string in a SQL statement. Calls can be
  23. * constructed by passing the name of the function and a list of params.
  24. * For security reasons, all params passed are quoted by default unless
  25. * explicitly told otherwise.
  26. */
  27. class FunctionExpression extends QueryExpression implements TypedResultInterface
  28. {
  29. use ExpressionTypeCasterTrait;
  30. use TypedResultTrait;
  31. /**
  32. * The name of the function to be constructed when generating the SQL string
  33. *
  34. * @var string
  35. */
  36. protected $_name;
  37. /**
  38. * Constructor. Takes a name for the function to be invoked and a list of params
  39. * to be passed into the function. Optionally you can pass a list of types to
  40. * be used for each bound param.
  41. *
  42. * By default, all params that are passed will be quoted. If you wish to use
  43. * literal arguments, you need to explicitly hint this function.
  44. *
  45. * ### Examples:
  46. *
  47. * `$f = new FunctionExpression('CONCAT', ['CakePHP', ' rules']);`
  48. *
  49. * Previous line will generate `CONCAT('CakePHP', ' rules')`
  50. *
  51. * `$f = new FunctionExpression('CONCAT', ['name' => 'literal', ' rules']);`
  52. *
  53. * Will produce `CONCAT(name, ' rules')`
  54. *
  55. * @param string $name the name of the function to be constructed
  56. * @param array $params list of arguments to be passed to the function
  57. * If associative the key would be used as argument when value is 'literal'
  58. * @param array $types associative array of types to be associated with the
  59. * passed arguments
  60. * @param string $returnType The return type of this expression
  61. */
  62. public function __construct($name, $params = [], $types = [], $returnType = 'string')
  63. {
  64. $this->_name = $name;
  65. $this->_returnType = $returnType;
  66. parent::__construct($params, $types, ',');
  67. }
  68. /**
  69. * Sets the name of the SQL function to be invoke in this expression.
  70. *
  71. * @param string $name The name of the function
  72. * @return $this
  73. */
  74. public function setName($name)
  75. {
  76. $this->_name = $name;
  77. return $this;
  78. }
  79. /**
  80. * Gets the name of the SQL function to be invoke in this expression.
  81. *
  82. * @return string
  83. */
  84. public function getName()
  85. {
  86. return $this->_name;
  87. }
  88. /**
  89. * Sets the name of the SQL function to be invoke in this expression,
  90. * if no value is passed it will return current name
  91. *
  92. * @deprecated 3.4.0 Use setName()/getName() instead.
  93. * @param string|null $name The name of the function
  94. * @return string|$this
  95. */
  96. public function name($name = null)
  97. {
  98. if ($name !== null) {
  99. return $this->setName($name);
  100. }
  101. return $this->getName();
  102. }
  103. /**
  104. * Adds one or more arguments for the function call.
  105. *
  106. * @param array $params list of arguments to be passed to the function
  107. * If associative the key would be used as argument when value is 'literal'
  108. * @param array $types associative array of types to be associated with the
  109. * passed arguments
  110. * @param bool $prepend Whether to prepend or append to the list of arguments
  111. * @see \Cake\Database\Expression\FunctionExpression::__construct() for more details.
  112. * @return $this
  113. */
  114. public function add($params, $types = [], $prepend = false)
  115. {
  116. $put = $prepend ? 'array_unshift' : 'array_push';
  117. $typeMap = $this->getTypeMap()->setTypes($types);
  118. foreach ($params as $k => $p) {
  119. if ($p === 'literal') {
  120. $put($this->_conditions, $k);
  121. continue;
  122. }
  123. if ($p === 'identifier') {
  124. $put($this->_conditions, new IdentifierExpression($k));
  125. continue;
  126. }
  127. $type = $typeMap->type($k);
  128. if ($type !== null && !$p instanceof ExpressionInterface) {
  129. $p = $this->_castToExpression($p, $type);
  130. }
  131. if ($p instanceof ExpressionInterface) {
  132. $put($this->_conditions, $p);
  133. continue;
  134. }
  135. $put($this->_conditions, ['value' => $p, 'type' => $type]);
  136. }
  137. return $this;
  138. }
  139. /**
  140. * Returns the string representation of this object so that it can be used in a
  141. * SQL query. Note that values condition values are not included in the string,
  142. * in their place placeholders are put and can be replaced by the quoted values
  143. * accordingly.
  144. *
  145. * @param \Cake\Database\ValueBinder $generator Placeholder generator object
  146. * @return string
  147. */
  148. public function sql(ValueBinder $generator)
  149. {
  150. $parts = [];
  151. foreach ($this->_conditions as $condition) {
  152. if ($condition instanceof ExpressionInterface) {
  153. $condition = sprintf('(%s)', $condition->sql($generator));
  154. } elseif (is_array($condition)) {
  155. $p = $generator->placeholder('param');
  156. $generator->bind($p, $condition['value'], $condition['type']);
  157. $condition = $p;
  158. }
  159. $parts[] = $condition;
  160. }
  161. return $this->_name . sprintf('(%s)', implode(
  162. $this->_conjunction . ' ',
  163. $parts
  164. ));
  165. }
  166. /**
  167. * The name of the function is in itself an expression to generate, thus
  168. * always adding 1 to the amount of expressions stored in this object.
  169. *
  170. * @return int
  171. */
  172. public function count()
  173. {
  174. return 1 + count($this->_conditions);
  175. }
  176. }