CakePHP
  • Documentation
    • Book
    • API
    • Videos
    • Reporting Security Issues
    • Privacy Policy
    • Logos & Trademarks
  • Business Solutions
  • Swag
  • Road Trip
  • Team
  • Community
    • Community
    • Get Involved
    • Issues (GitHub)
    • Bakery
    • Featured Resources
    • Training
    • Meetups
    • My CakePHP
    • CakeFest
    • Newsletter
    • Linkedin
    • YouTube
    • Facebook
    • Twitter
    • Mastodon
    • Help & Support
    • Forum
    • Stack Overflow
    • Slack
    • Paid Support
CakePHP

C CakePHP 2.8 API

  • Overview
  • Tree
  • Deprecated
  • Version:
    • 2.8
      • 4.2
      • 4.1
      • 4.0
      • 3.9
      • 3.8
      • 3.7
      • 3.6
      • 3.5
      • 3.4
      • 3.3
      • 3.2
      • 3.1
      • 3.0
      • 2.10
      • 2.9
      • 2.8
      • 2.7
      • 2.6
      • 2.5
      • 2.4
      • 2.3
      • 2.2
      • 2.1
      • 2.0
      • 1.3
      • 1.2

Packages

  • Cake
    • Cache
      • Engine
    • Configure
    • Console
      • Command
        • Task
    • Controller
      • Component
        • Acl
        • Auth
    • Core
    • Error
    • Event
    • I18n
    • Log
      • Engine
    • Model
      • Behavior
      • Datasource
        • Database
        • Session
      • Validator
    • Network
      • Email
      • Http
    • Routing
      • Filter
      • Route
    • TestSuite
      • Coverage
      • Fixture
      • Reporter
    • Utility
    • View
      • Helper
  • None

Classes

  • Mysql
  • Postgres
  • Sqlite
  • Sqlserver
  1: <?php
  2: /**
  3:  * MS SQL Server layer for DBO
  4:  *
  5:  * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  6:  * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  7:  *
  8:  * Licensed under The MIT License
  9:  * For full copyright and license information, please see the LICENSE.txt
 10:  * Redistributions of files must retain the above copyright notice.
 11:  *
 12:  * @copyright     Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
 13:  * @link          http://cakephp.org CakePHP(tm) Project
 14:  * @package       Cake.Model.Datasource.Database
 15:  * @since         CakePHP(tm) v 0.10.5.1790
 16:  * @license       http://www.opensource.org/licenses/mit-license.php MIT License
 17:  */
 18: 
 19: App::uses('DboSource', 'Model/Datasource');
 20: 
 21: /**
 22:  * Dbo layer for Microsoft's official SQLServer driver
 23:  *
 24:  * A Dbo layer for MS SQL Server 2005 and higher. Requires the
 25:  * `pdo_sqlsrv` extension to be enabled.
 26:  *
 27:  * @link http://www.php.net/manual/en/ref.pdo-sqlsrv.php
 28:  *
 29:  * @package       Cake.Model.Datasource.Database
 30:  */
 31: class Sqlserver extends DboSource {
 32: 
 33: /**
 34:  * Driver description
 35:  *
 36:  * @var string
 37:  */
 38:     public $description = "SQL Server DBO Driver";
 39: 
 40: /**
 41:  * Starting quote character for quoted identifiers
 42:  *
 43:  * @var string
 44:  */
 45:     public $startQuote = "[";
 46: 
 47: /**
 48:  * Ending quote character for quoted identifiers
 49:  *
 50:  * @var string
 51:  */
 52:     public $endQuote = "]";
 53: 
 54: /**
 55:  * Creates a map between field aliases and numeric indexes. Workaround for the
 56:  * SQL Server driver's 30-character column name limitation.
 57:  *
 58:  * @var array
 59:  */
 60:     protected $_fieldMappings = array();
 61: 
 62: /**
 63:  * Storing the last affected value
 64:  *
 65:  * @var mixed
 66:  */
 67:     protected $_lastAffected = false;
 68: 
 69: /**
 70:  * Base configuration settings for MS SQL driver
 71:  *
 72:  * @var array
 73:  */
 74:     protected $_baseConfig = array(
 75:         'persistent' => true,
 76:         'host' => 'localhost\SQLEXPRESS',
 77:         'login' => '',
 78:         'password' => '',
 79:         'database' => 'cake',
 80:         'schema' => '',
 81:         'flags' => array()
 82:     );
 83: 
 84: /**
 85:  * MS SQL column definition
 86:  *
 87:  * @var array
 88:  */
 89:     public $columns = array(
 90:         'primary_key' => array('name' => 'IDENTITY (1, 1) NOT NULL'),
 91:         'string' => array('name' => 'nvarchar', 'limit' => '255'),
 92:         'text' => array('name' => 'nvarchar', 'limit' => 'MAX'),
 93:         'integer' => array('name' => 'int', 'formatter' => 'intval'),
 94:         'biginteger' => array('name' => 'bigint'),
 95:         'numeric' => array('name' => 'decimal', 'formatter' => 'floatval'),
 96:         'decimal' => array('name' => 'decimal', 'formatter' => 'floatval'),
 97:         'float' => array('name' => 'float', 'formatter' => 'floatval'),
 98:         'real' => array('name' => 'float', 'formatter' => 'floatval'),
 99:         'datetime' => array('name' => 'datetime', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
100:         'timestamp' => array('name' => 'timestamp', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
101:         'time' => array('name' => 'datetime', 'format' => 'H:i:s', 'formatter' => 'date'),
102:         'date' => array('name' => 'datetime', 'format' => 'Y-m-d', 'formatter' => 'date'),
103:         'binary' => array('name' => 'varbinary'),
104:         'boolean' => array('name' => 'bit')
105:     );
106: 
107: /**
108:  * Magic column name used to provide pagination support for SQLServer 2008
109:  * which lacks proper limit/offset support.
110:  *
111:  * @var string
112:  */
113:     const ROW_COUNTER = '_cake_page_rownum_';
114: 
115: /**
116:  * Connects to the database using options in the given configuration array.
117:  *
118:  * @return bool True if the database could be connected, else false
119:  * @throws MissingConnectionException
120:  */
121:     public function connect() {
122:         $config = $this->config;
123:         $this->connected = false;
124: 
125:         $flags = $config['flags'] + array(
126:             PDO::ATTR_PERSISTENT => $config['persistent'],
127:             PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
128:         );
129: 
130:         if (!empty($config['encoding'])) {
131:             $flags[PDO::SQLSRV_ATTR_ENCODING] = $config['encoding'];
132:         }
133: 
134:         try {
135:             $this->_connection = new PDO(
136:                 "sqlsrv:server={$config['host']};Database={$config['database']}",
137:                 $config['login'],
138:                 $config['password'],
139:                 $flags
140:             );
141:             $this->connected = true;
142:             if (!empty($config['settings'])) {
143:                 foreach ($config['settings'] as $key => $value) {
144:                     $this->_execute("SET $key $value");
145:                 }
146:             }
147:         } catch (PDOException $e) {
148:             throw new MissingConnectionException(array(
149:                 'class' => get_class($this),
150:                 'message' => $e->getMessage()
151:             ));
152:         }
153: 
154:         return $this->connected;
155:     }
156: 
157: /**
158:  * Check that PDO SQL Server is installed/loaded
159:  *
160:  * @return bool
161:  */
162:     public function enabled() {
163:         return in_array('sqlsrv', PDO::getAvailableDrivers());
164:     }
165: 
166: /**
167:  * Returns an array of sources (tables) in the database.
168:  *
169:  * @param mixed $data The names
170:  * @return array Array of table names in the database
171:  */
172:     public function listSources($data = null) {
173:         $cache = parent::listSources();
174:         if ($cache !== null) {
175:             return $cache;
176:         }
177:         $result = $this->_execute("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES");
178: 
179:         if (!$result) {
180:             $result->closeCursor();
181:             return array();
182:         }
183:         $tables = array();
184: 
185:         while ($line = $result->fetch(PDO::FETCH_NUM)) {
186:             $tables[] = $line[0];
187:         }
188: 
189:         $result->closeCursor();
190:         parent::listSources($tables);
191:         return $tables;
192:     }
193: 
194: /**
195:  * Returns an array of the fields in given table name.
196:  *
197:  * @param Model|string $model Model object to describe, or a string table name.
198:  * @return array Fields in table. Keys are name and type
199:  * @throws CakeException
200:  */
201:     public function describe($model) {
202:         $table = $this->fullTableName($model, false, false);
203:         $fulltable = $this->fullTableName($model, false, true);
204: 
205:         $cache = parent::describe($fulltable);
206:         if ($cache) {
207:             return $cache;
208:         }
209: 
210:         $fields = array();
211:         $schema = is_object($model) ? $model->schemaName : false;
212: 
213:         $cols = $this->_execute(
214:             "SELECT
215:                 COLUMN_NAME as Field,
216:                 DATA_TYPE as Type,
217:                 COL_LENGTH('" . ($schema ? $fulltable : $table) . "', COLUMN_NAME) as Length,
218:                 IS_NULLABLE As [Null],
219:                 COLUMN_DEFAULT as [Default],
220:                 COLUMNPROPERTY(OBJECT_ID('" . ($schema ? $fulltable : $table) . "'), COLUMN_NAME, 'IsIdentity') as [Key],
221:                 NUMERIC_SCALE as Size
222:             FROM INFORMATION_SCHEMA.COLUMNS
223:             WHERE TABLE_NAME = '" . $table . "'" . ($schema ? " AND TABLE_SCHEMA = '" . $schema . "'" : '')
224:         );
225: 
226:         if (!$cols) {
227:             throw new CakeException(__d('cake_dev', 'Could not describe table for %s', $table));
228:         }
229: 
230:         while ($column = $cols->fetch(PDO::FETCH_OBJ)) {
231:             $field = $column->Field;
232:             $fields[$field] = array(
233:                 'type' => $this->column($column),
234:                 'null' => ($column->Null === 'YES' ? true : false),
235:                 'default' => $column->Default,
236:                 'length' => $this->length($column),
237:                 'key' => ($column->Key == '1') ? 'primary' : false
238:             );
239: 
240:             if ($fields[$field]['default'] === 'null') {
241:                 $fields[$field]['default'] = null;
242:             }
243:             if ($fields[$field]['default'] !== null) {
244:                 $fields[$field]['default'] = preg_replace(
245:                     "/^[(]{1,2}'?([^')]*)?'?[)]{1,2}$/",
246:                     "$1",
247:                     $fields[$field]['default']
248:                 );
249:                 $this->value($fields[$field]['default'], $fields[$field]['type']);
250:             }
251: 
252:             if ($fields[$field]['key'] !== false && $fields[$field]['type'] === 'integer') {
253:                 $fields[$field]['length'] = 11;
254:             } elseif ($fields[$field]['key'] === false) {
255:                 unset($fields[$field]['key']);
256:             }
257:             if (in_array($fields[$field]['type'], array('date', 'time', 'datetime', 'timestamp'))) {
258:                 $fields[$field]['length'] = null;
259:             }
260:             if ($fields[$field]['type'] === 'float' && !empty($column->Size)) {
261:                 $fields[$field]['length'] = $fields[$field]['length'] . ',' . $column->Size;
262:             }
263:         }
264:         $this->_cacheDescription($table, $fields);
265:         $cols->closeCursor();
266:         return $fields;
267:     }
268: 
269: /**
270:  * Generates the fields list of an SQL query.
271:  *
272:  * @param Model $model The model to get fields for.
273:  * @param string $alias Alias table name
274:  * @param array $fields The fields so far.
275:  * @param bool $quote Whether or not to quote identfiers.
276:  * @return array
277:  */
278:     public function fields(Model $model, $alias = null, $fields = array(), $quote = true) {
279:         if (empty($alias)) {
280:             $alias = $model->alias;
281:         }
282:         $fields = parent::fields($model, $alias, $fields, false);
283:         $count = count($fields);
284: 
285:         if ($count >= 1 && strpos($fields[0], 'COUNT(*)') === false) {
286:             $result = array();
287:             for ($i = 0; $i < $count; $i++) {
288:                 $prepend = '';
289: 
290:                 if (strpos($fields[$i], 'DISTINCT') !== false && strpos($fields[$i], 'COUNT') === false) {
291:                     $prepend = 'DISTINCT ';
292:                     $fields[$i] = trim(str_replace('DISTINCT', '', $fields[$i]));
293:                 }
294: 
295:                 if (!preg_match('/\s+AS\s+/i', $fields[$i])) {
296:                     if (substr($fields[$i], -1) === '*') {
297:                         if (strpos($fields[$i], '.') !== false && $fields[$i] != $alias . '.*') {
298:                             $build = explode('.', $fields[$i]);
299:                             $AssociatedModel = $model->{$build[0]};
300:                         } else {
301:                             $AssociatedModel = $model;
302:                         }
303: 
304:                         $_fields = $this->fields($AssociatedModel, $AssociatedModel->alias, array_keys($AssociatedModel->schema()));
305:                         $result = array_merge($result, $_fields);
306:                         continue;
307:                     }
308: 
309:                     if (strpos($fields[$i], '.') === false) {
310:                         $this->_fieldMappings[$alias . '__' . $fields[$i]] = $alias . '.' . $fields[$i];
311:                         $fieldName = $this->name($alias . '.' . $fields[$i]);
312:                         $fieldAlias = $this->name($alias . '__' . $fields[$i]);
313:                     } else {
314:                         $build = explode('.', $fields[$i]);
315:                         $build[0] = trim($build[0], '[]');
316:                         $build[1] = trim($build[1], '[]');
317:                         $name = $build[0] . '.' . $build[1];
318:                         $alias = $build[0] . '__' . $build[1];
319: 
320:                         $this->_fieldMappings[$alias] = $name;
321:                         $fieldName = $this->name($name);
322:                         $fieldAlias = $this->name($alias);
323:                     }
324:                     if ($model->getColumnType($fields[$i]) === 'datetime') {
325:                         $fieldName = "CONVERT(VARCHAR(20), {$fieldName}, 20)";
326:                     }
327:                     $fields[$i] = "{$fieldName} AS {$fieldAlias}";
328:                 }
329:                 $result[] = $prepend . $fields[$i];
330:             }
331:             return $result;
332:         }
333:         return $fields;
334:     }
335: 
336: /**
337:  * Generates and executes an SQL INSERT statement for given model, fields, and values.
338:  * Removes Identity (primary key) column from update data before returning to parent, if
339:  * value is empty.
340:  *
341:  * @param Model $model The model to insert into.
342:  * @param array $fields The fields to set.
343:  * @param array $values The values to set.
344:  * @return array
345:  */
346:     public function create(Model $model, $fields = null, $values = null) {
347:         if (!empty($values)) {
348:             $fields = array_combine($fields, $values);
349:         }
350:         $primaryKey = $this->_getPrimaryKey($model);
351: 
352:         if (array_key_exists($primaryKey, $fields)) {
353:             if (empty($fields[$primaryKey])) {
354:                 unset($fields[$primaryKey]);
355:             } else {
356:                 $this->_execute('SET IDENTITY_INSERT ' . $this->fullTableName($model) . ' ON');
357:             }
358:         }
359:         $result = parent::create($model, array_keys($fields), array_values($fields));
360:         if (array_key_exists($primaryKey, $fields) && !empty($fields[$primaryKey])) {
361:             $this->_execute('SET IDENTITY_INSERT ' . $this->fullTableName($model) . ' OFF');
362:         }
363:         return $result;
364:     }
365: 
366: /**
367:  * Generates and executes an SQL UPDATE statement for given model, fields, and values.
368:  * Removes Identity (primary key) column from update data before returning to parent.
369:  *
370:  * @param Model $model The model to update.
371:  * @param array $fields The fields to set.
372:  * @param array $values The values to set.
373:  * @param mixed $conditions The conditions to use.
374:  * @return array
375:  */
376:     public function update(Model $model, $fields = array(), $values = null, $conditions = null) {
377:         if (!empty($values)) {
378:             $fields = array_combine($fields, $values);
379:         }
380:         if (isset($fields[$model->primaryKey])) {
381:             unset($fields[$model->primaryKey]);
382:         }
383:         if (empty($fields)) {
384:             return true;
385:         }
386:         return parent::update($model, array_keys($fields), array_values($fields), $conditions);
387:     }
388: 
389: /**
390:  * Returns a limit statement in the correct format for the particular database.
391:  *
392:  * @param int $limit Limit of results returned
393:  * @param int $offset Offset from which to start results
394:  * @return string SQL limit/offset statement
395:  */
396:     public function limit($limit, $offset = null) {
397:         if ($limit) {
398:             $rt = '';
399:             if (!strpos(strtolower($limit), 'top') || strpos(strtolower($limit), 'top') === 0) {
400:                 $rt = ' TOP';
401:             }
402:             $rt .= sprintf(' %u', $limit);
403:             if (is_int($offset) && $offset > 0) {
404:                 $rt = sprintf(' OFFSET %u ROWS FETCH FIRST %u ROWS ONLY', $offset, $limit);
405:             }
406:             return $rt;
407:         }
408:         return null;
409:     }
410: 
411: /**
412:  * Converts database-layer column types to basic types
413:  *
414:  * @param mixed $real Either the string value of the fields type.
415:  *    or the Result object from Sqlserver::describe()
416:  * @return string Abstract column type (i.e. "string")
417:  */
418:     public function column($real) {
419:         $limit = null;
420:         $col = $real;
421:         if (is_object($real) && isset($real->Field)) {
422:             $limit = $real->Length;
423:             $col = $real->Type;
424:         }
425: 
426:         if ($col === 'datetime2') {
427:             return 'datetime';
428:         }
429:         if (in_array($col, array('date', 'time', 'datetime', 'timestamp'))) {
430:             return $col;
431:         }
432:         if ($col === 'bit') {
433:             return 'boolean';
434:         }
435:         if (strpos($col, 'bigint') !== false) {
436:             return 'biginteger';
437:         }
438:         if (strpos($col, 'int') !== false) {
439:             return 'integer';
440:         }
441:         if (strpos($col, 'char') !== false && $limit == -1) {
442:             return 'text';
443:         }
444:         if (strpos($col, 'char') !== false) {
445:             return 'string';
446:         }
447:         if (strpos($col, 'text') !== false) {
448:             return 'text';
449:         }
450:         if (strpos($col, 'binary') !== false || $col === 'image') {
451:             return 'binary';
452:         }
453:         if (in_array($col, array('float', 'real'))) {
454:             return 'float';
455:         }
456:         if (in_array($col, array('decimal', 'numeric'))) {
457:             return 'decimal';
458:         }
459:         return 'text';
460:     }
461: 
462: /**
463:  * Handle SQLServer specific length properties.
464:  * SQLServer handles text types as nvarchar/varchar with a length of -1.
465:  *
466:  * @param mixed $length Either the length as a string, or a Column descriptor object.
467:  * @return mixed null|integer with length of column.
468:  */
469:     public function length($length) {
470:         if (is_object($length) && isset($length->Length)) {
471:             if ($length->Length == -1 && strpos($length->Type, 'char') !== false) {
472:                 return null;
473:             }
474:             if (in_array($length->Type, array('nchar', 'nvarchar'))) {
475:                 return floor($length->Length / 2);
476:             }
477:             if ($length->Type === 'text') {
478:                 return null;
479:             }
480:             return $length->Length;
481:         }
482:         return parent::length($length);
483:     }
484: 
485: /**
486:  * Builds a map of the columns contained in a result
487:  *
488:  * @param PDOStatement $results The result to modify.
489:  * @return void
490:  */
491:     public function resultSet($results) {
492:         $this->map = array();
493:         $numFields = $results->columnCount();
494:         $index = 0;
495: 
496:         while ($numFields-- > 0) {
497:             $column = $results->getColumnMeta($index);
498:             $name = $column['name'];
499: 
500:             if (strpos($name, '__')) {
501:                 if (isset($this->_fieldMappings[$name]) && strpos($this->_fieldMappings[$name], '.')) {
502:                     $map = explode('.', $this->_fieldMappings[$name]);
503:                 } elseif (isset($this->_fieldMappings[$name])) {
504:                     $map = array(0, $this->_fieldMappings[$name]);
505:                 } else {
506:                     $map = array(0, $name);
507:                 }
508:             } else {
509:                 $map = array(0, $name);
510:             }
511:             $map[] = ($column['sqlsrv:decl_type'] === 'bit') ? 'boolean' : $column['native_type'];
512:             $this->map[$index++] = $map;
513:         }
514:     }
515: 
516: /**
517:  * Builds final SQL statement
518:  *
519:  * @param string $type Query type
520:  * @param array $data Query data
521:  * @return string
522:  */
523:     public function renderStatement($type, $data) {
524:         switch (strtolower($type)) {
525:             case 'select':
526:                 extract($data);
527:                 $fields = trim($fields);
528: 
529:                 if (strpos($limit, 'TOP') !== false && strpos($fields, 'DISTINCT ') === 0) {
530:                     $limit = 'DISTINCT ' . trim($limit);
531:                     $fields = substr($fields, 9);
532:                 }
533: 
534:                 // hack order as SQLServer requires an order if there is a limit.
535:                 if ($limit && !$order) {
536:                     $order = 'ORDER BY (SELECT NULL)';
537:                 }
538: 
539:                 // For older versions use the subquery version of pagination.
540:                 if (version_compare($this->getVersion(), '11', '<') && preg_match('/FETCH\sFIRST\s+([0-9]+)/i', $limit, $offset)) {
541:                     preg_match('/OFFSET\s*(\d+)\s*.*?(\d+)\s*ROWS/', $limit, $limitOffset);
542: 
543:                     $limit = 'TOP ' . (int)$limitOffset[2];
544:                     $page = (int)($limitOffset[1] / $limitOffset[2]);
545:                     $offset = (int)($limitOffset[2] * $page);
546: 
547:                     $rowCounter = static::ROW_COUNTER;
548:                     $sql = "SELECT {$limit} * FROM (
549:                             SELECT {$fields}, ROW_NUMBER() OVER ({$order}) AS {$rowCounter}
550:                             FROM {$table} {$alias} {$joins} {$conditions} {$group}
551:                         ) AS _cake_paging_
552:                         WHERE _cake_paging_.{$rowCounter} > {$offset}
553:                         ORDER BY _cake_paging_.{$rowCounter}
554:                     ";
555:                     return trim($sql);
556:                 }
557:                 if (strpos($limit, 'FETCH') !== false) {
558:                     return trim("SELECT {$fields} FROM {$table} {$alias} {$joins} {$conditions} {$group} {$order} {$limit}");
559:                 }
560:                 return trim("SELECT {$limit} {$fields} FROM {$table} {$alias} {$joins} {$conditions} {$group} {$order}");
561:             case "schema":
562:                 extract($data);
563: 
564:                 foreach ($indexes as $i => $index) {
565:                     if (preg_match('/PRIMARY KEY/', $index)) {
566:                         unset($indexes[$i]);
567:                         break;
568:                     }
569:                 }
570: 
571:                 foreach (array('columns', 'indexes') as $var) {
572:                     if (is_array(${$var})) {
573:                         ${$var} = "\t" . implode(",\n\t", array_filter(${$var}));
574:                     }
575:                 }
576:                 return trim("CREATE TABLE {$table} (\n{$columns});\n{$indexes}");
577:             default:
578:                 return parent::renderStatement($type, $data);
579:         }
580:     }
581: 
582: /**
583:  * Returns a quoted and escaped string of $data for use in an SQL statement.
584:  *
585:  * @param string $data String to be prepared for use in an SQL statement
586:  * @param string $column The column into which this data will be inserted
587:  * @param bool $null Column allows NULL values
588:  * @return string Quoted and escaped data
589:  */
590:     public function value($data, $column = null, $null = true) {
591:         if ($data === null || is_array($data) || is_object($data)) {
592:             return parent::value($data, $column, $null);
593:         }
594:         if (in_array($data, array('{$__cakeID__$}', '{$__cakeForeignKey__$}'), true)) {
595:             return $data;
596:         }
597: 
598:         if (empty($column)) {
599:             $column = $this->introspectType($data);
600:         }
601: 
602:         switch ($column) {
603:             case 'string':
604:             case 'text':
605:                 return 'N' . $this->_connection->quote($data, PDO::PARAM_STR);
606:             default:
607:                 return parent::value($data, $column, $null);
608:         }
609:     }
610: 
611: /**
612:  * Returns an array of all result rows for a given SQL query.
613:  * Returns false if no rows matched.
614:  *
615:  * @param Model $model The model to read from
616:  * @param array $queryData The query data
617:  * @param int $recursive How many layers to go.
618:  * @return array|false Array of resultset rows, or false if no rows matched
619:  */
620:     public function read(Model $model, $queryData = array(), $recursive = null) {
621:         $results = parent::read($model, $queryData, $recursive);
622:         $this->_fieldMappings = array();
623:         return $results;
624:     }
625: 
626: /**
627:  * Fetches the next row from the current result set.
628:  * Eats the magic ROW_COUNTER variable.
629:  *
630:  * @return mixed
631:  */
632:     public function fetchResult() {
633:         if ($row = $this->_result->fetch(PDO::FETCH_NUM)) {
634:             $resultRow = array();
635:             foreach ($this->map as $col => $meta) {
636:                 list($table, $column, $type) = $meta;
637:                 if ($table === 0 && $column === static::ROW_COUNTER) {
638:                     continue;
639:                 }
640:                 $resultRow[$table][$column] = $row[$col];
641:                 if ($type === 'boolean' && $row[$col] !== null) {
642:                     $resultRow[$table][$column] = $this->boolean($resultRow[$table][$column]);
643:                 }
644:             }
645:             return $resultRow;
646:         }
647:         $this->_result->closeCursor();
648:         return false;
649:     }
650: 
651: /**
652:  * Inserts multiple values into a table
653:  *
654:  * @param string $table The table to insert into.
655:  * @param string $fields The fields to set.
656:  * @param array $values The values to set.
657:  * @return void
658:  */
659:     public function insertMulti($table, $fields, $values) {
660:         $primaryKey = $this->_getPrimaryKey($table);
661:         $hasPrimaryKey = $primaryKey && (
662:             (is_array($fields) && in_array($primaryKey, $fields)
663:             || (is_string($fields) && strpos($fields, $this->startQuote . $primaryKey . $this->endQuote) !== false))
664:         );
665: 
666:         if ($hasPrimaryKey) {
667:             $this->_execute('SET IDENTITY_INSERT ' . $this->fullTableName($table) . ' ON');
668:         }
669: 
670:         parent::insertMulti($table, $fields, $values);
671: 
672:         if ($hasPrimaryKey) {
673:             $this->_execute('SET IDENTITY_INSERT ' . $this->fullTableName($table) . ' OFF');
674:         }
675:     }
676: 
677: /**
678:  * Generate a database-native column schema string
679:  *
680:  * @param array $column An array structured like the
681:  *   following: array('name'=>'value', 'type'=>'value'[, options]),
682:  *   where options can be 'default', 'length', or 'key'.
683:  * @return string
684:  */
685:     public function buildColumn($column) {
686:         $result = parent::buildColumn($column);
687:         $result = preg_replace('/(bigint|int|integer)\([0-9]+\)/i', '$1', $result);
688:         $result = preg_replace('/(bit)\([0-9]+\)/i', '$1', $result);
689:         if (strpos($result, 'DEFAULT NULL') !== false) {
690:             if (isset($column['default']) && $column['default'] === '') {
691:                 $result = str_replace('DEFAULT NULL', "DEFAULT ''", $result);
692:             } else {
693:                 $result = str_replace('DEFAULT NULL', 'NULL', $result);
694:             }
695:         } elseif (array_keys($column) === array('type', 'name')) {
696:             $result .= ' NULL';
697:         } elseif (strpos($result, "DEFAULT N'")) {
698:             $result = str_replace("DEFAULT N'", "DEFAULT '", $result);
699:         }
700:         return $result;
701:     }
702: 
703: /**
704:  * Format indexes for create table
705:  *
706:  * @param array $indexes The indexes to build
707:  * @param string $table The table to make indexes for.
708:  * @return string
709:  */
710:     public function buildIndex($indexes, $table = null) {
711:         $join = array();
712: 
713:         foreach ($indexes as $name => $value) {
714:             if ($name === 'PRIMARY') {
715:                 $join[] = 'PRIMARY KEY (' . $this->name($value['column']) . ')';
716:             } elseif (isset($value['unique']) && $value['unique']) {
717:                 $out = "ALTER TABLE {$table} ADD CONSTRAINT {$name} UNIQUE";
718: 
719:                 if (is_array($value['column'])) {
720:                     $value['column'] = implode(', ', array_map(array(&$this, 'name'), $value['column']));
721:                 } else {
722:                     $value['column'] = $this->name($value['column']);
723:                 }
724:                 $out .= "({$value['column']});";
725:                 $join[] = $out;
726:             }
727:         }
728:         return $join;
729:     }
730: 
731: /**
732:  * Makes sure it will return the primary key
733:  *
734:  * @param Model|string $model Model instance of table name
735:  * @return string
736:  */
737:     protected function _getPrimaryKey($model) {
738:         $schema = $this->describe($model);
739:         foreach ($schema as $field => $props) {
740:             if (isset($props['key']) && $props['key'] === 'primary') {
741:                 return $field;
742:             }
743:         }
744:         return null;
745:     }
746: 
747: /**
748:  * Returns number of affected rows in previous database operation. If no previous operation exists,
749:  * this returns false.
750:  *
751:  * @param mixed $source Unused
752:  * @return int Number of affected rows
753:  */
754:     public function lastAffected($source = null) {
755:         $affected = parent::lastAffected();
756:         if ($affected === null && $this->_lastAffected !== false) {
757:             return $this->_lastAffected;
758:         }
759:         return $affected;
760:     }
761: 
762: /**
763:  * Executes given SQL statement.
764:  *
765:  * @param string $sql SQL statement
766:  * @param array $params list of params to be bound to query (supported only in select)
767:  * @param array $prepareOptions Options to be used in the prepare statement
768:  * @return mixed PDOStatement if query executes with no problem, true as the result of a successful, false on error
769:  * query returning no rows, such as a CREATE statement, false otherwise
770:  * @throws PDOException
771:  */
772:     protected function _execute($sql, $params = array(), $prepareOptions = array()) {
773:         $this->_lastAffected = false;
774:         $sql = trim($sql);
775:         if (strncasecmp($sql, 'SELECT', 6) === 0 || preg_match('/^EXEC(?:UTE)?\s/mi', $sql) > 0) {
776:             $prepareOptions += array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL);
777:             return parent::_execute($sql, $params, $prepareOptions);
778:         }
779:         try {
780:             $this->_lastAffected = $this->_connection->exec($sql);
781:             if ($this->_lastAffected === false) {
782:                 $this->_results = null;
783:                 $error = $this->_connection->errorInfo();
784:                 $this->error = $error[2];
785:                 return false;
786:             }
787:             return true;
788:         } catch (PDOException $e) {
789:             if (isset($query->queryString)) {
790:                 $e->queryString = $query->queryString;
791:             } else {
792:                 $e->queryString = $sql;
793:             }
794:             throw $e;
795:         }
796:     }
797: 
798: /**
799:  * Generate a "drop table" statement for the given table
800:  *
801:  * @param type $table Name of the table to drop
802:  * @return string Drop table SQL statement
803:  */
804:     protected function _dropTable($table) {
805:         return "IF OBJECT_ID('" . $this->fullTableName($table, false) . "', 'U') IS NOT NULL DROP TABLE " . $this->fullTableName($table) . ";";
806:     }
807: 
808: /**
809:  * Gets the schema name
810:  *
811:  * @return string The schema name
812:  */
813:     public function getSchemaName() {
814:         return $this->config['schema'];
815:     }
816: 
817: }
818: 
OpenHub
Rackspace
Rackspace
  • Business Solutions
  • Showcase
  • Documentation
  • Book
  • API
  • Videos
  • Reporting Security Issues
  • Privacy Policy
  • Logos & Trademarks
  • Community
  • Get Involved
  • Issues (GitHub)
  • Bakery
  • Featured Resources
  • Training
  • Meetups
  • My CakePHP
  • CakeFest
  • Newsletter
  • Linkedin
  • YouTube
  • Facebook
  • Twitter
  • Mastodon
  • Help & Support
  • Forum
  • Stack Overflow
  • Slack
  • Paid Support

Generated using CakePHP API Docs