1 2/** 3 * This file is part of the Phalcon Framework. 4 * 5 * (c) Phalcon Team <team@phalcon.io> 6 * 7 * For the full copyright and license information, please view the LICENSE.txt 8 * file that was distributed with this source code. 9 * 10 * Implementation of this file has been influenced by AtlasPHP 11 * 12 * @link https://github.com/atlasphp/Atlas.Query 13 * @license https://github.com/atlasphp/Atlas.Qyert/blob/1.x/LICENSE.md 14 */ 15 16namespace Phalcon\DataMapper\Query; 17 18use Phalcon\Helper\Arr; 19 20/** 21 * Class AbstractConditions 22 */ 23abstract class AbstractConditions extends AbstractQuery 24{ 25 /** 26 * Sets the `LIMIT` clause 27 * 28 * @param int $limit 29 * 30 * @return AbstractConditions 31 */ 32 public function limit(int limit) -> <AbstractConditions> 33 { 34 let this->store["LIMIT"] = limit; 35 36 return this; 37 } 38 39 /** 40 * Sets the `OFFSET` clause 41 * 42 * @param int $offset 43 * 44 * @return AbstractConditions 45 */ 46 public function offset(int offset) -> <AbstractConditions> 47 { 48 let this->store["OFFSET"] = offset; 49 50 return this; 51 } 52 53 /** 54 * Sets a `AND` for a `WHERE` condition 55 * 56 * @param string $condition 57 * @param mixed|null $value 58 * @param int $type 59 * 60 * @return AbstractConditions 61 */ 62 public function andWhere( 63 string condition, 64 var value = null, 65 int type = -1 66 ) -> <AbstractConditions> { 67 this->where(condition, value, type); 68 69 return this; 70 } 71 72 /** 73 * Concatenates to the most recent `WHERE` clause 74 * 75 * @param string $condition 76 * @param mixed|null $value 77 * @param int $type 78 * 79 * @return AbstractConditions 80 */ 81 public function appendWhere( 82 string condition, 83 var value = null, 84 int type = -1 85 ) -> <AbstractConditions> { 86 this->appendCondition("WHERE", condition, value, type); 87 88 return this; 89 } 90 91 /** 92 * Sets the `ORDER BY` 93 * 94 * @param array|string $orderBy 95 * 96 * @return AbstractConditions 97 */ 98 public function orderBy(var orderBy) -> <AbstractConditions> 99 { 100 this->processValue("ORDER", orderBy); 101 102 return this; 103 } 104 105 /** 106 * Sets a `OR` for a `WHERE` condition 107 * 108 * @param string $condition 109 * @param mixed|null $value 110 * @param int $type 111 * 112 * @return AbstractConditions 113 */ 114 public function orWhere( 115 string condition, 116 var value = null, 117 int type = -1 118 ) -> <AbstractConditions> { 119 this->addCondition("WHERE", "OR ", condition, value, type); 120 121 return this; 122 } 123 124 /** 125 * Sets a `WHERE` condition 126 * 127 * @param string $condition 128 * @param mixed|null $value 129 * @param int $type 130 * 131 * @return AbstractConditions 132 */ 133 public function where( 134 string condition, 135 var value = null, 136 int type = -1 137 ) -> <AbstractConditions> { 138 this->addCondition("WHERE", "AND ", condition, value, type); 139 140 return this; 141 } 142 143 /** 144 * @param array $columnsValues 145 * 146 * @return AbstractConditions 147 */ 148 public function whereEquals(array columnsValues) -> <AbstractConditions> 149 { 150 var key, value; 151 152 for key, value in columnsValues { 153 if is_numeric(key) { 154 this->where(value); 155 } elseif null === value { 156 this->where(key . " IS NULL"); 157 } elseif typeof value === "array" { 158 this->where(key . " IN ", value); 159 } else { 160 this->where(key . " = ", value); 161 } 162 } 163 164 return this; 165 } 166 167 /** 168 * Appends a conditional 169 * 170 * @param string $store 171 * @param string $andor 172 * @param string $condition 173 * @param mixed|null $value 174 * @param int $type 175 */ 176 protected function addCondition( 177 string store, 178 string andor, 179 string condition, 180 var value = null, 181 int type = -1 182 ) -> void { 183 if !empty value { 184 let condition .= this->bindInline(value, type); 185 } 186 187 if empty this->store[store] { 188 let andor = ""; 189 } 190 191 let this->store[store][] = andor . condition; 192 } 193 194 /** 195 * Builds a `BY` list 196 * 197 * @param string $type 198 * 199 * @return string 200 */ 201 protected function buildBy(string type) -> string 202 { 203 if empty this->store[type] { 204 return ""; 205 } 206 207 return " " . type . " BY" 208 . this->indent(this->store[type], ","); 209 } 210 211 /** 212 * Builds the conditional string 213 * 214 * @param string $type 215 * 216 * @return string 217 */ 218 protected function buildCondition(string type) -> string 219 { 220 if empty this->store[type] { 221 return ""; 222 } 223 224 return " " . type 225 . this->indent(this->store[type]); 226 } 227 228 /** 229 * Builds the early `LIMIT` clause - MS SQLServer 230 * 231 * @return string 232 */ 233 protected function buildLimitEarly() -> string 234 { 235 string limit = ""; 236 237 if ( 238 "sqlsrv" === this->connection->getDriverName() && 239 this->store["LIMIT"] > 0 && 240 0 === this->store["OFFSET"] 241 ) { 242 let limit = " TOP " . this->store["LIMIT"]; 243 } 244 245 return limit; 246 } 247 248 /** 249 * Builds the `LIMIT` clause 250 * 251 * @return string 252 */ 253 protected function buildLimit() -> string 254 { 255 var method, suffix; 256 257 let suffix = this->connection->getDriverName(); 258 259 if "sqlsrv" !== suffix { 260 let suffix = "common"; 261 } 262 263 let method = "buildLimit" . ucfirst(suffix); 264 265 return this->{method}(); 266 } 267 268 /** 269 * Builds the `LIMIT` clause for all drivers 270 * 271 * @return string 272 */ 273 274 protected function buildLimitCommon() -> string 275 { 276 string limit = ""; 277 278 if 0 !== this->store["LIMIT"] { 279 let limit .= "LIMIT " . this->store["LIMIT"]; 280 } 281 282 if 0 !== this->store["OFFSET"] { 283 let limit .= " OFFSET " . this->store["OFFSET"]; 284 } 285 286 if "" !== limit { 287 let limit = " " . ltrim(limit); 288 } 289 290 return limit; 291 } 292 293 /** 294 * Builds the `LIMIT` clause for MSSQLServer 295 * 296 * @return string 297 */ 298 protected function buildLimitSqlsrv() -> string 299 { 300 string limit = ""; 301 302 if this->store["LIMIT"] > 0 && this->store["OFFSET"] > 0 { 303 let limit = " OFFSET " . this->store["OFFSET"] . " ROWS" 304 . " FETCH NEXT " . this->store["LIMIT"] . " ROWS ONLY"; 305 } 306 307 return limit; 308 } 309 310 /** 311 * Concatenates a conditional 312 * 313 * @param string $store 314 * @param string $condition 315 * @param mixed $value 316 * @param int $type 317 */ 318 protected function appendCondition( 319 string store, 320 string condition, 321 var value = null, 322 int type = -1 323 ) -> void { 324 var key; 325 326 if !empty value { 327 let condition .= this->bindInline(value, type); 328 } 329 330 if empty this->store[store] { 331 let this->store[store][] = ""; 332 } 333 334 let key = Arr::lastKey(this->store[store]); 335 336 let this->store[store][key] = this->store[store][key] . condition; 337 } 338 339 /** 340 * Processes a value (array or string) and merges it with the store 341 * 342 * @param string $store 343 * @param array|string $data 344 */ 345 protected function processValue(string store, var data) -> void 346 { 347 if typeof data === "string" { 348 let data = [data]; 349 } 350 351 if typeof data === "array" { 352 let this->store[store] = array_merge( 353 this->store[store], 354 data 355 ); 356 } 357 } 358} 359