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.3 API

  • Overview
  • Tree
  • Deprecated
  • Version:
    • 2.3
      • 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

Classes

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