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

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