merged skunkworks into develop.
This commit is contained in:
@@ -9,13 +9,6 @@ class Connection {
|
||||
*/
|
||||
public $pdo;
|
||||
|
||||
/**
|
||||
* All of the queries that have been executed on the connection.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $queries = array();
|
||||
|
||||
/**
|
||||
* The connection configuration array.
|
||||
*
|
||||
@@ -30,6 +23,13 @@ class Connection {
|
||||
*/
|
||||
protected $grammar;
|
||||
|
||||
/**
|
||||
* All of the queries that have been executed on all connections.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $queries = array();
|
||||
|
||||
/**
|
||||
* Create a new database connection instance.
|
||||
*
|
||||
@@ -46,6 +46,14 @@ class Connection {
|
||||
/**
|
||||
* Begin a fluent query against a table.
|
||||
*
|
||||
* <code>
|
||||
* // Start a fluent query against the "users" table
|
||||
* $query = DB::connection()->table('users');
|
||||
*
|
||||
* // Start a fluent query against the "users" table and get all the users
|
||||
* $users = DB::connection()->table('users')->get();
|
||||
* </code>
|
||||
*
|
||||
* @param string $table
|
||||
* @return Query
|
||||
*/
|
||||
@@ -57,27 +65,22 @@ class Connection {
|
||||
/**
|
||||
* Create a new query grammar for the connection.
|
||||
*
|
||||
* Query grammars allow support for new database systems to be added quickly
|
||||
* and easily. Since the responsibility of the query generation is delegated
|
||||
* to the grammar classes, it is simple to override only the methods with
|
||||
* SQL syntax that differs from the default implementation.
|
||||
*
|
||||
* @return Grammars\Grammar
|
||||
* @return Query\Grammars\Grammar
|
||||
*/
|
||||
protected function grammar()
|
||||
{
|
||||
if (isset($this->grammar)) return $this->grammar;
|
||||
|
||||
// We allow the developer to hard-code a grammar for the connection. This really
|
||||
// has no use yet; however, if database systems that can use multiple grammars
|
||||
// like ODBC are added in the future, this will be needed.
|
||||
switch (isset($this->config['grammar']) ? $this->config['grammar'] : $this->driver())
|
||||
{
|
||||
case 'mysql':
|
||||
return $this->grammar = new Grammars\MySQL;
|
||||
return $this->grammar = new Query\Grammars\MySQL;
|
||||
|
||||
case 'sqlsrv':
|
||||
return $this->grammar = new Query\Grammars\SQLServer;
|
||||
|
||||
default:
|
||||
return $this->grammar = new Grammars\Grammar;
|
||||
return $this->grammar = new Query\Grammars\Grammar;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,9 +101,9 @@ class Connection {
|
||||
*/
|
||||
public function only($sql, $bindings = array())
|
||||
{
|
||||
$result = (array) $this->first($sql, $bindings);
|
||||
$results = (array) $this->first($sql, $bindings);
|
||||
|
||||
return reset($result);
|
||||
return reset($results);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -127,67 +130,124 @@ class Connection {
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a SQL query against the connection.
|
||||
*
|
||||
* The method returns the following based on query type:
|
||||
*
|
||||
* SELECT -> Array of stdClasses
|
||||
* UPDATE -> Number of rows affected.
|
||||
* DELETE -> Number of Rows affected.
|
||||
* ELSE -> Boolean true / false depending on success.
|
||||
*
|
||||
* <code>
|
||||
* // Execute a query against the database connection
|
||||
* $users = DB::connection()->query('select * from users');
|
||||
*
|
||||
* // Execute a query with bound parameters
|
||||
* $user = DB::connection()->query('select * from users where id = ?', array($id));
|
||||
* </code>
|
||||
* Execute a SQL query and return an array of StdClass objects.
|
||||
*
|
||||
* @param string $sql
|
||||
* @param array $bindings
|
||||
* @return mixed
|
||||
* @return array
|
||||
*/
|
||||
public function query($sql, $bindings = array())
|
||||
{
|
||||
// Since expressions are injected into the query as raw strings, we need
|
||||
// to remove them from the array of bindings. They are not truly bound
|
||||
// to the PDO statement as named parameters.
|
||||
foreach ($bindings as $key => $value)
|
||||
{
|
||||
if ($value instanceof Expression) unset($bindings[$key]);
|
||||
}
|
||||
list($statement, $result) = $this->execute($sql, $bindings);
|
||||
|
||||
$bindings = array_values($bindings);
|
||||
return $statement->fetchAll(PDO::FETCH_CLASS, 'stdClass');
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a SQL UPDATE query and return the affected row count.
|
||||
*
|
||||
* @param string $sql
|
||||
* @param array $bindings
|
||||
* @return int
|
||||
*/
|
||||
public function update($sql, $bindings = array())
|
||||
{
|
||||
list($statement, $result) = $this->execute($sql, $bindings);
|
||||
|
||||
return $statement->rowCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a SQL DELETE query and return the affected row count.
|
||||
*
|
||||
* @param string $sql
|
||||
* @param array $bindings
|
||||
* @return int
|
||||
*/
|
||||
public function delete($sql, $bindings = array())
|
||||
{
|
||||
list($statement, $result) = $this->execute($sql, $bindings);
|
||||
|
||||
return $statement->rowCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute an SQL query and return the boolean result of the PDO statement.
|
||||
*
|
||||
* @param string $sql
|
||||
* @param array $bindings
|
||||
* @return bool
|
||||
*/
|
||||
public function statement($sql, $bindings = array())
|
||||
{
|
||||
list($statement, $result) = $this->execute($sql, $bindings);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a SQL query against the connection.
|
||||
*
|
||||
* The PDO statement and boolean result will be return in an array.
|
||||
*
|
||||
* @param string $sql
|
||||
* @param array $bindings
|
||||
* @return array
|
||||
*/
|
||||
protected function execute($sql, $bindings = array())
|
||||
{
|
||||
// Since expressions are injected into the query as strings, we need to
|
||||
// remove them from the array of bindings. After we have removed them,
|
||||
// we'll reset the array so there aren't gaps in the keys.
|
||||
$bindings = array_values(array_filter($bindings, function($binding)
|
||||
{
|
||||
return ! $binding instanceof Expression;
|
||||
}));
|
||||
|
||||
$sql = $this->transform($sql, $bindings);
|
||||
|
||||
$this->queries[] = compact('sql', 'bindings');
|
||||
$statement = $this->pdo->prepare($sql);
|
||||
|
||||
return $this->execute($this->pdo->prepare($sql), $bindings);
|
||||
// Every query is timed so that we can log the executinon time along
|
||||
// with the query SQL and array of bindings. This should be make it
|
||||
// convenient for the developer to profile the application's query
|
||||
// performance to diagnose bottlenecks.
|
||||
$time = microtime(true);
|
||||
|
||||
$result = $statement->execute($bindings);
|
||||
|
||||
$time = number_format((microtime(true) - $time) * 1000, 2);
|
||||
|
||||
// Once we have execute the query, we log the SQL, bindings, and
|
||||
// execution time in a static array that is accessed by all of
|
||||
// the connections used by the application. This allows us to
|
||||
// review all of the executed SQL.
|
||||
static::$queries[] = compact('sql', 'bindings', 'time');
|
||||
|
||||
return array($statement, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform an SQL query into an executable query.
|
||||
*
|
||||
* Laravel provides a convenient short-cut when writing raw queries for
|
||||
* handling cumbersome "where in" statements. This method will transform
|
||||
* those segments into their full SQL counterparts.
|
||||
*
|
||||
* @param string $sql
|
||||
* @param array $bindings
|
||||
* @return string
|
||||
*/
|
||||
protected function transform($sql, $bindings)
|
||||
{
|
||||
// Laravel provides an easy short-cut notation for writing raw
|
||||
// WHERE IN statements. If (...) is in the query, it will be
|
||||
// replaced with the correct number of parameters based on
|
||||
// the bindings for the query.
|
||||
if (strpos($sql, '(...)') !== false)
|
||||
{
|
||||
for ($i = 0; $i < count($bindings); $i++)
|
||||
{
|
||||
// If the binding is an array, we can assume it is being used to fill
|
||||
// a "where in" condition, so we will replace the next place-holder
|
||||
// in the query with the correct number of parameters based on the
|
||||
// number of elements in this binding.
|
||||
// If the binding is an array, we can assume it is being used
|
||||
// to fill a "where in" condition, so we'll replace the next
|
||||
// place-holder in the SQL query with the correct number of
|
||||
// parameters based on the elements in the binding.
|
||||
if (is_array($bindings[$i]))
|
||||
{
|
||||
$parameters = implode(', ', array_fill(0, count($bindings[$i]), '?'));
|
||||
@@ -200,33 +260,6 @@ class Connection {
|
||||
return trim($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a prepared PDO statement and return the appropriate results.
|
||||
*
|
||||
* @param PDOStatement $statement
|
||||
* @param array $bindings
|
||||
* @return mixed
|
||||
*/
|
||||
protected function execute(PDOStatement $statement, $bindings)
|
||||
{
|
||||
$result = $statement->execute($bindings);
|
||||
|
||||
$sql = strtoupper($statement->queryString);
|
||||
|
||||
if (strpos($sql, 'SELECT') === 0)
|
||||
{
|
||||
return $statement->fetchAll(PDO::FETCH_CLASS, 'stdClass');
|
||||
}
|
||||
elseif (strpos($sql, 'UPDATE') === 0 or strpos($sql, 'DELETE') === 0)
|
||||
{
|
||||
return $statement->rowCount();
|
||||
}
|
||||
else
|
||||
{
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the driver name for the database connection.
|
||||
*
|
||||
|
||||
@@ -16,7 +16,7 @@ abstract class Connector {
|
||||
);
|
||||
|
||||
/**
|
||||
* Establish a PDO database connection for a given database configuration.
|
||||
* Establish a PDO database connection.
|
||||
*
|
||||
* @param array $config
|
||||
* @return PDO
|
||||
@@ -24,7 +24,7 @@ abstract class Connector {
|
||||
abstract public function connect($config);
|
||||
|
||||
/**
|
||||
* Get the PDO connection options for a given database configuration.
|
||||
* Get the PDO connection options for the configuration.
|
||||
*
|
||||
* Developer specified options will override the default connection options.
|
||||
*
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
class MySQL extends Connector {
|
||||
|
||||
/**
|
||||
* Establish a PDO database connection for a given database configuration.
|
||||
* Establish a PDO database connection.
|
||||
*
|
||||
* @param array $config
|
||||
* @return PDO
|
||||
@@ -15,7 +15,7 @@ class MySQL extends Connector {
|
||||
// Format the initial MySQL PDO connection string. These options are required
|
||||
// for every MySQL connection that is established. The connection strings
|
||||
// have the following convention: "mysql:host=hostname;dbname=database"
|
||||
$dsn = sprintf('%s:host=%s;dbname=%s', $driver, $host, $database);
|
||||
$dsn = "mysql:host={$host};dbname={$database}";
|
||||
|
||||
// Check for any optional MySQL PDO options. These options are not required
|
||||
// to establish a PDO connection; however, may be needed in certain server
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
class Postgres extends Connector {
|
||||
|
||||
/**
|
||||
* Establish a PDO database connection for a given database configuration.
|
||||
* Establish a PDO database connection.
|
||||
*
|
||||
* @param array $config
|
||||
* @return PDO
|
||||
@@ -15,7 +15,7 @@ class Postgres extends Connector {
|
||||
// Format the initial Postgres PDO connection string. These options are required
|
||||
// for every Postgres connection that is established. The connection strings
|
||||
// have the following convention: "pgsql:host=hostname;dbname=database"
|
||||
$dsn = sprintf('%s:host=%s;dbname=%s', $driver, $host, $database);
|
||||
$dsn = "pgsql:host={$host};dbname={$database}";
|
||||
|
||||
// Check for any optional Postgres PDO options. These options are not required
|
||||
// to establish a PDO connection; however, may be needed in certain server
|
||||
|
||||
@@ -3,25 +3,7 @@
|
||||
class SQLite extends Connector {
|
||||
|
||||
/**
|
||||
* The path to the SQLite databases for the application.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $path;
|
||||
|
||||
/**
|
||||
* Create a new SQLite database connector instance.
|
||||
*
|
||||
* @param string $path
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($path)
|
||||
{
|
||||
$this->path = $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Establish a PDO database connection for a given database configuration.
|
||||
* Establish a PDO database connection.
|
||||
*
|
||||
* @param array $config
|
||||
* @return PDO
|
||||
@@ -32,27 +14,19 @@ class SQLite extends Connector {
|
||||
|
||||
// SQLite provides supported for "in-memory" databases, which exist only for the
|
||||
// lifetime of the request. Any given in-memory database may only have one PDO
|
||||
// connection open to it at a time. Generally, these databases are use for
|
||||
// connection open to it at a time. Generally, these databases are used for
|
||||
// testing and development purposes, not in production scenarios.
|
||||
if ($config['database'] == ':memory:')
|
||||
{
|
||||
return new PDO('sqlite::memory:', null, null, $options);
|
||||
}
|
||||
|
||||
// First, we will check for the database in the default storage directory for the
|
||||
// application. If we don't find the database there, we will assume the database
|
||||
// name is actually a full qualified path to the database on disk and attempt
|
||||
// to load it. If we still can't find it, we'll bail out.
|
||||
elseif (file_exists($path = $this->path.$config['database'].'.sqlite'))
|
||||
if (file_exists($path = DATABASE_PATH.$config['database'].'.sqlite'))
|
||||
{
|
||||
return new PDO('sqlite:'.$path, null, null, $options);
|
||||
}
|
||||
elseif (file_exists($config['database']))
|
||||
{
|
||||
return new PDO('sqlite:'.$config['database'], null, null, $options);
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException("SQLite database [{$config['database']}] could not be found.");
|
||||
throw new \Exception("SQLite database [{$config['database']}] could not be found.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
38
laravel/database/connectors/sqlserver.php
Normal file
38
laravel/database/connectors/sqlserver.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php namespace Laravel\Database\Connectors; use PDO;
|
||||
|
||||
class SQLServer extends Connector {
|
||||
|
||||
/**
|
||||
* The PDO connection options.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $options = array(
|
||||
PDO::ATTR_CASE => PDO::CASE_LOWER,
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
PDO::ATTR_ORACLE_NULLS => PDO::NULL_NATURAL,
|
||||
PDO::ATTR_STRINGIFY_FETCHES => false,
|
||||
);
|
||||
|
||||
/**
|
||||
* Establish a PDO database connection.
|
||||
*
|
||||
* @param array $config
|
||||
* @return PDO
|
||||
*/
|
||||
public function connect($config)
|
||||
{
|
||||
extract($config);
|
||||
|
||||
// Format the SQL Server connection string. This connection string format can
|
||||
// also be used to connect to Azure SQL Server databases. The port is defined
|
||||
// directly after the server name, so we'll create that and then create the
|
||||
// final DSN string to pass to PDO.
|
||||
$port = (isset($port)) ? ','.$port : '';
|
||||
|
||||
$dsn = "sqlsrv:Server={$host}{$port};Database={$database}";
|
||||
|
||||
return new PDO($dsn, $username, $password, $this->options($config));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,212 +0,0 @@
|
||||
<?php namespace Laravel\Database\Eloquent;
|
||||
|
||||
class Hydrator {
|
||||
|
||||
/**
|
||||
* Load the array of hydrated models and their eager relationships.
|
||||
*
|
||||
* @param Model $eloquent
|
||||
* @return array
|
||||
*/
|
||||
public static function hydrate($eloquent)
|
||||
{
|
||||
$results = static::base(get_class($eloquent), $eloquent->query->get());
|
||||
|
||||
if (count($results) > 0)
|
||||
{
|
||||
foreach ($eloquent->includes as $include)
|
||||
{
|
||||
if ( ! method_exists($eloquent, $include))
|
||||
{
|
||||
throw new \LogicException("Attempting to eager load [$include], but the relationship is not defined.");
|
||||
}
|
||||
|
||||
static::eagerly($eloquent, $results, $include);
|
||||
}
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hydrate the base models for a query.
|
||||
*
|
||||
* The resulting model array is keyed by the primary keys of the models.
|
||||
* This allows the models to easily be matched to their children.
|
||||
*
|
||||
* @param string $class
|
||||
* @param array $results
|
||||
* @return array
|
||||
*/
|
||||
private static function base($class, $results)
|
||||
{
|
||||
$models = array();
|
||||
|
||||
foreach ($results as $result)
|
||||
{
|
||||
$model = new $class;
|
||||
|
||||
$model->attributes = (array) $result;
|
||||
|
||||
$model->exists = true;
|
||||
|
||||
if (isset($model->attributes['id']))
|
||||
{
|
||||
$models[$model->id] = $model;
|
||||
}
|
||||
else
|
||||
{
|
||||
$models[] = $model;
|
||||
}
|
||||
}
|
||||
|
||||
return $models;
|
||||
}
|
||||
|
||||
/**
|
||||
* Eagerly load a relationship.
|
||||
*
|
||||
* @param object $eloquent
|
||||
* @param array $parents
|
||||
* @param string $include
|
||||
* @return void
|
||||
*/
|
||||
private static function eagerly($eloquent, &$parents, $include)
|
||||
{
|
||||
// We temporarily spoof the query attributes to allow the query to be fetched without
|
||||
// any problems, since the belongs_to method actually gets the related attribute.
|
||||
$first = reset($parents);
|
||||
|
||||
$eloquent->attributes = $first->attributes;
|
||||
|
||||
$relationship = $eloquent->$include();
|
||||
|
||||
$eloquent->attributes = array();
|
||||
|
||||
// Reset the WHERE clause and bindings on the query. We'll add our own WHERE clause soon.
|
||||
// This will allow us to load a range of related models instead of only one.
|
||||
$relationship->query->reset_where();
|
||||
|
||||
// Initialize the relationship attribute on the parents. As expected, "many" relationships
|
||||
// are initialized to an array and "one" relationships are initialized to null.
|
||||
foreach ($parents as &$parent)
|
||||
{
|
||||
$parent->ignore[$include] = (in_array($eloquent->relating, array('has_many', 'has_and_belongs_to_many'))) ? array() : null;
|
||||
}
|
||||
|
||||
if (in_array($relating = $eloquent->relating, array('has_one', 'has_many', 'belongs_to')))
|
||||
{
|
||||
return static::$relating($relationship, $parents, $eloquent->relating_key, $include);
|
||||
}
|
||||
else
|
||||
{
|
||||
static::has_and_belongs_to_many($relationship, $parents, $eloquent->relating_key, $eloquent->relating_table, $include);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Eagerly load a 1:1 relationship.
|
||||
*
|
||||
* @param object $relationship
|
||||
* @param array $parents
|
||||
* @param string $relating_key
|
||||
* @param string $relating
|
||||
* @param string $include
|
||||
* @return void
|
||||
*/
|
||||
private static function has_one($relationship, &$parents, $relating_key, $include)
|
||||
{
|
||||
foreach ($relationship->where_in($relating_key, array_keys($parents))->get() as $key => $child)
|
||||
{
|
||||
$parents[$child->$relating_key]->ignore[$include] = $child;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Eagerly load a 1:* relationship.
|
||||
*
|
||||
* @param object $relationship
|
||||
* @param array $parents
|
||||
* @param string $relating_key
|
||||
* @param string $relating
|
||||
* @param string $include
|
||||
* @return void
|
||||
*/
|
||||
private static function has_many($relationship, &$parents, $relating_key, $include)
|
||||
{
|
||||
foreach ($relationship->where_in($relating_key, array_keys($parents))->get() as $key => $child)
|
||||
{
|
||||
$parents[$child->$relating_key]->ignore[$include][$child->id] = $child;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Eagerly load a 1:1 belonging relationship.
|
||||
*
|
||||
* @param object $relationship
|
||||
* @param array $parents
|
||||
* @param string $relating_key
|
||||
* @param string $include
|
||||
* @return void
|
||||
*/
|
||||
private static function belongs_to($relationship, &$parents, $relating_key, $include)
|
||||
{
|
||||
$keys = array();
|
||||
|
||||
foreach ($parents as &$parent)
|
||||
{
|
||||
$keys[] = $parent->$relating_key;
|
||||
}
|
||||
|
||||
$children = $relationship->where_in('id', array_unique($keys))->get();
|
||||
|
||||
foreach ($parents as &$parent)
|
||||
{
|
||||
if (array_key_exists($parent->$relating_key, $children))
|
||||
{
|
||||
$parent->ignore[$include] = $children[$parent->$relating_key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Eagerly load a many-to-many relationship.
|
||||
*
|
||||
* @param object $relationship
|
||||
* @param array $parents
|
||||
* @param string $relating_key
|
||||
* @param string $relating_table
|
||||
* @param string $include
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private static function has_and_belongs_to_many($relationship, &$parents, $relating_key, $relating_table, $include)
|
||||
{
|
||||
// The model "has and belongs to many" method sets the SELECT clause; however, we need
|
||||
// to clear it here since we will be adding the foreign key to the select.
|
||||
$relationship->query->select = null;
|
||||
|
||||
$relationship->query->where_in($relating_table.'.'.$relating_key, array_keys($parents));
|
||||
|
||||
// The foreign key is added to the select to allow us to easily match the models back to their parents.
|
||||
// Otherwise, there would be no apparent connection between the models to allow us to match them.
|
||||
$children = $relationship->query->get(array(Model::table(get_class($relationship)).'.*', $relating_table.'.'.$relating_key));
|
||||
|
||||
$class = get_class($relationship);
|
||||
|
||||
foreach ($children as $child)
|
||||
{
|
||||
$related = new $class;
|
||||
|
||||
$related->attributes = (array) $child;
|
||||
|
||||
$related->exists = true;
|
||||
|
||||
// Remove the foreign key since it was only added to the query to help match the models.
|
||||
unset($related->attributes[$relating_key]);
|
||||
|
||||
$parents[$child->$relating_key]->ignore[$include][$child->id] = $related;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,538 +0,0 @@
|
||||
<?php namespace Laravel\Database\Eloquent;
|
||||
|
||||
use Laravel\Str;
|
||||
use Laravel\Inflector;
|
||||
use Laravel\Paginator;
|
||||
use Laravel\Database\Manager as DB;
|
||||
|
||||
abstract class Model {
|
||||
|
||||
/**
|
||||
* The connection that should be used for the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $connection;
|
||||
|
||||
/**
|
||||
* Indicates if the model has creation and update timestamps.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public static $timestamps = false;
|
||||
|
||||
/**
|
||||
* The name of the auto-incrementing sequence associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $sequence = null;
|
||||
|
||||
/**
|
||||
* The model query instance.
|
||||
*
|
||||
* @var Query
|
||||
*/
|
||||
public $query;
|
||||
|
||||
/**
|
||||
* Indicates if the model exists in the database.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $exists = false;
|
||||
|
||||
/**
|
||||
* The model's attributes.
|
||||
*
|
||||
* Typically, a model has an attribute for each column on the table.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $attributes = array();
|
||||
|
||||
/**
|
||||
* The model's dirty attributes.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $dirty = array();
|
||||
|
||||
/**
|
||||
* The model's ignored attributes.
|
||||
*
|
||||
* Ignored attributes will not be saved to the database, and are
|
||||
* primarily used to hold relationships.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $ignore = array();
|
||||
|
||||
/**
|
||||
* The relationships that should be eagerly loaded.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $includes = array();
|
||||
|
||||
/**
|
||||
* The relationship type the model is currently resolving.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $relating;
|
||||
|
||||
/**
|
||||
* The foreign key of the "relating" relationship.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $relating_key;
|
||||
|
||||
/**
|
||||
* The table name of the model being resolved.
|
||||
*
|
||||
* This is used during many-to-many eager loading.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $relating_table;
|
||||
|
||||
/**
|
||||
* Create a new Eloquent model instance.
|
||||
*
|
||||
* @param array $attributes
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($attributes = array())
|
||||
{
|
||||
$this->fill($attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the attributes of the model using an array.
|
||||
*
|
||||
* @param array $attributes
|
||||
* @return Model
|
||||
*/
|
||||
public function fill($attributes)
|
||||
{
|
||||
foreach ($attributes as $key => $value)
|
||||
{
|
||||
$this->$key = $value;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the eagerly loaded models on the queryable model.
|
||||
*
|
||||
* @return Model
|
||||
*/
|
||||
private function _with()
|
||||
{
|
||||
$this->includes = func_get_args();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory for creating queryable Eloquent model instances.
|
||||
*
|
||||
* @param string $class
|
||||
* @return object
|
||||
*/
|
||||
public static function query($class)
|
||||
{
|
||||
$model = new $class;
|
||||
|
||||
// Since this method is only used for instantiating models for querying
|
||||
// purposes, we will go ahead and set the Query instance on the model.
|
||||
$model->query = DB::connection(static::$connection)->table(static::table($class));
|
||||
|
||||
return $model;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the table name for a model.
|
||||
*
|
||||
* @param string $class
|
||||
* @return string
|
||||
*/
|
||||
public static function table($class)
|
||||
{
|
||||
if (property_exists($class, 'table')) return $class::$table;
|
||||
|
||||
return strtolower(Inflector::plural(static::model_name($class)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an Eloquent model name without any namespaces.
|
||||
*
|
||||
* @param string|Model $model
|
||||
* @return string
|
||||
*/
|
||||
public static function model_name($model)
|
||||
{
|
||||
$class = (is_object($model)) ? get_class($model) : $model;
|
||||
|
||||
$segments = array_reverse(explode('\\', $class));
|
||||
|
||||
return $segments[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all of the models from the database.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function all()
|
||||
{
|
||||
return Hydrator::hydrate(static::query(get_called_class()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a model by the primary key.
|
||||
*
|
||||
* @param int $id
|
||||
* @return mixed
|
||||
*/
|
||||
public static function find($id)
|
||||
{
|
||||
return static::query(get_called_class())->where('id', '=', $id)->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array of models from the database.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function _get()
|
||||
{
|
||||
return Hydrator::hydrate($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the first model result
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private function _first()
|
||||
{
|
||||
return (count($results = $this->take(1)->_get()) > 0) ? reset($results) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get paginated model results as a Paginator instance.
|
||||
*
|
||||
* @param int $per_page
|
||||
* @return Paginator
|
||||
*/
|
||||
private function _paginate($per_page = null)
|
||||
{
|
||||
$total = $this->query->count();
|
||||
|
||||
// The number of models to show per page may be specified as a static property
|
||||
// on the model. The models shown per page may also be overriden for the model
|
||||
// by passing the number into this method. If the models to show per page is
|
||||
// not available via either of these avenues, a default number will be shown.
|
||||
if (is_null($per_page))
|
||||
{
|
||||
$per_page = (property_exists(get_class($this), 'per_page')) ? static::$per_page : 20;
|
||||
}
|
||||
|
||||
return Paginator::make($this->for_page(Paginator::page($total, $per_page), $per_page)->get(), $total, $per_page);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the query for a 1:1 relationship.
|
||||
*
|
||||
* @param string $model
|
||||
* @param string $foreign_key
|
||||
* @return mixed
|
||||
*/
|
||||
public function has_one($model, $foreign_key = null)
|
||||
{
|
||||
$this->relating = __FUNCTION__;
|
||||
|
||||
return $this->has_one_or_many($model, $foreign_key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the query for a 1:* relationship.
|
||||
*
|
||||
* @param string $model
|
||||
* @param string $foreign_key
|
||||
* @return mixed
|
||||
*/
|
||||
public function has_many($model, $foreign_key = null)
|
||||
{
|
||||
$this->relating = __FUNCTION__;
|
||||
|
||||
return $this->has_one_or_many($model, $foreign_key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the query for a 1:1 or 1:* relationship.
|
||||
*
|
||||
* The default foreign key for has one and has many relationships is the name
|
||||
* of the model with an appended _id. For example, the foreign key for a
|
||||
* User model would be user_id. Photo would be photo_id, etc.
|
||||
*
|
||||
* @param string $model
|
||||
* @param string $foreign_key
|
||||
* @return mixed
|
||||
*/
|
||||
private function has_one_or_many($model, $foreign_key)
|
||||
{
|
||||
$this->relating_key = (is_null($foreign_key)) ? strtolower(static::model_name($this)).'_id' : $foreign_key;
|
||||
|
||||
return static::query($model)->where($this->relating_key, '=', $this->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the query for a 1:1 belonging relationship.
|
||||
*
|
||||
* The default foreign key for belonging relationships is the name of the
|
||||
* relationship method name with _id. So, if a model has a "manager" method
|
||||
* returning a belongs_to relationship, the key would be manager_id.
|
||||
*
|
||||
* @param string $model
|
||||
* @param string $foreign_key
|
||||
* @return mixed
|
||||
*/
|
||||
public function belongs_to($model, $foreign_key = null)
|
||||
{
|
||||
$this->relating = __FUNCTION__;
|
||||
|
||||
if ( ! is_null($foreign_key))
|
||||
{
|
||||
$this->relating_key = $foreign_key;
|
||||
}
|
||||
else
|
||||
{
|
||||
list(, $caller) = debug_backtrace(false);
|
||||
|
||||
$this->relating_key = $caller['function'].'_id';
|
||||
}
|
||||
|
||||
return static::query($model)->where('id', '=', $this->attributes[$this->relating_key]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the query for a *:* relationship.
|
||||
*
|
||||
* The default foreign key for many-to-many relations is the name of the model
|
||||
* with an appended _id. This is the same convention as has_one and has_many.
|
||||
*
|
||||
* @param string $model
|
||||
* @param string $table
|
||||
* @param string $foreign_key
|
||||
* @param string $associated_key
|
||||
* @return mixed
|
||||
*/
|
||||
public function has_and_belongs_to_many($model, $table = null, $foreign_key = null, $associated_key = null)
|
||||
{
|
||||
$this->relating = __FUNCTION__;
|
||||
|
||||
$this->relating_table = (is_null($table)) ? $this->intermediate_table($model) : $table;
|
||||
|
||||
// Allowing the overriding of the foreign and associated keys provides
|
||||
// the flexibility for self-referential many-to-many relationships.
|
||||
$this->relating_key = (is_null($foreign_key)) ? strtolower(static::model_name($this)).'_id' : $foreign_key;
|
||||
|
||||
// The associated key is the foreign key name of the related model.
|
||||
// If the related model is "Role", the key would be "role_id".
|
||||
$associated_key = (is_null($associated_key)) ? strtolower(static::model_name($model)).'_id' : $associated_key;
|
||||
|
||||
return static::query($model)
|
||||
->select(array(static::table($model).'.*'))
|
||||
->join($this->relating_table, static::table($model).'.id', '=', $this->relating_table.'.'.$associated_key)
|
||||
->where($this->relating_table.'.'.$this->relating_key, '=', $this->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the intermediate table name for a given model.
|
||||
*
|
||||
* By default, the intermediate table name is the plural names of the models
|
||||
* arranged alphabetically and concatenated with an underscore.
|
||||
*
|
||||
* @param string $model
|
||||
* @return string
|
||||
*/
|
||||
private function intermediate_table($model)
|
||||
{
|
||||
$models = array(Inflector::plural(static::model_name($model)), Inflector::plural(static::model_name($this)));
|
||||
|
||||
sort($models);
|
||||
|
||||
return strtolower($models[0].'_'.$models[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the model to the database.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
// If the model does not have any dirty attributes, there is no reason
|
||||
// to save it to the database.
|
||||
if ($this->exists and count($this->dirty) == 0) return true;
|
||||
|
||||
$model = get_class($this);
|
||||
|
||||
// Since the model was instantiated using "new", a query instance has not been set.
|
||||
// Only models being used for querying have their query instances set by default.
|
||||
$this->query = DB::connection(static::$connection)->table(static::table($model));
|
||||
|
||||
if (property_exists($model, 'timestamps') and $model::$timestamps)
|
||||
{
|
||||
$this->timestamp();
|
||||
}
|
||||
|
||||
// If the model already exists in the database, we will just update it.
|
||||
// Otherwise, we will insert the model and set the ID attribute.
|
||||
if ($this->exists)
|
||||
{
|
||||
$success = ($this->query->where_id($this->attributes['id'])->update($this->dirty) === 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
$success = is_numeric($this->attributes['id'] = $this->query->insert_get_id($this->attributes, static::$sequence));
|
||||
}
|
||||
|
||||
($this->exists = true) and $this->dirty = array();
|
||||
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the creation and update timestamps on the model.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function timestamp()
|
||||
{
|
||||
$this->updated_at = date('Y-m-d H:i:s');
|
||||
|
||||
if ( ! $this->exists) $this->created_at = $this->updated_at;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a model from the database.
|
||||
*
|
||||
* @param int $id
|
||||
* @return int
|
||||
*/
|
||||
public function delete($id = null)
|
||||
{
|
||||
// If the delete method is being called on an existing model, we only want to delete
|
||||
// that model. If it is being called from an Eloquent query model, it is probably
|
||||
// the developer's intention to delete more than one model, so we will pass the
|
||||
// delete statement to the query instance.
|
||||
if ( ! $this->exists) return $this->query->delete();
|
||||
|
||||
$table = static::table(get_class($this));
|
||||
|
||||
return DB::connection(static::$connection)->table($table)->delete($this->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic method for retrieving model attributes.
|
||||
*/
|
||||
public function __get($key)
|
||||
{
|
||||
if (array_key_exists($key, $this->attributes))
|
||||
{
|
||||
return $this->attributes[$key];
|
||||
}
|
||||
// Is the requested item a model relationship that has already been loaded?
|
||||
// All of the loaded relationships are stored in the "ignore" array.
|
||||
elseif (array_key_exists($key, $this->ignore))
|
||||
{
|
||||
return $this->ignore[$key];
|
||||
}
|
||||
// Is the requested item a model relationship? If it is, we will dynamically
|
||||
// load it and return the results of the relationship query.
|
||||
elseif (method_exists($this, $key))
|
||||
{
|
||||
$query = $this->$key();
|
||||
|
||||
return $this->ignore[$key] = (in_array($this->relating, array('has_one', 'belongs_to'))) ? $query->first() : $query->get();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic Method for setting model attributes.
|
||||
*/
|
||||
public function __set($key, $value)
|
||||
{
|
||||
// If the key is a relationship, add it to the ignored attributes.
|
||||
// Ignored attributes are not stored in the database.
|
||||
if (method_exists($this, $key))
|
||||
{
|
||||
$this->ignore[$key] = $value;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->attributes[$key] = $value;
|
||||
$this->dirty[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic Method for determining if a model attribute is set.
|
||||
*/
|
||||
public function __isset($key)
|
||||
{
|
||||
return (array_key_exists($key, $this->attributes) or array_key_exists($key, $this->ignore));
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic Method for unsetting model attributes.
|
||||
*/
|
||||
public function __unset($key)
|
||||
{
|
||||
unset($this->attributes[$key], $this->ignore[$key], $this->dirty[$key]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic Method for handling dynamic method calls.
|
||||
*/
|
||||
public function __call($method, $parameters)
|
||||
{
|
||||
// To allow the "with", "get", "first", and "paginate" methods to be called both
|
||||
// staticly and on an instance, we need to have private, underscored versions
|
||||
// of the methods and handle them dynamically.
|
||||
if (in_array($method, array('with', 'get', 'first', 'paginate')))
|
||||
{
|
||||
return call_user_func_array(array($this, '_'.$method), $parameters);
|
||||
}
|
||||
|
||||
// All of the aggregate and persistance functions can be passed directly to the query
|
||||
// instance. For these functions, we can simply return the response of the query.
|
||||
if (in_array($method, array('insert', 'update', 'increment', 'decrement', 'abs', 'count', 'sum', 'min', 'max', 'avg')))
|
||||
{
|
||||
return call_user_func_array(array($this->query, $method), $parameters);
|
||||
}
|
||||
|
||||
// Pass the method to the query instance. This allows the chaining of methods
|
||||
// from the query builder, providing the same convenient query API as the
|
||||
// query builder itself.
|
||||
call_user_func_array(array($this->query, $method), $parameters);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic Method for handling dynamic static method calls.
|
||||
*/
|
||||
public static function __callStatic($method, $parameters)
|
||||
{
|
||||
// Just pass the method to a model instance and let the __call method take care of it.
|
||||
return call_user_func_array(array(static::query(get_called_class()), $method), $parameters);
|
||||
}
|
||||
|
||||
}
|
||||
108
laravel/database/grammar.php
Normal file
108
laravel/database/grammar.php
Normal file
@@ -0,0 +1,108 @@
|
||||
<?php namespace Laravel\Database;
|
||||
|
||||
abstract class Grammar {
|
||||
|
||||
/**
|
||||
* The keyword identifier for the database system.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $wrapper = '"%s"';
|
||||
|
||||
/**
|
||||
* Wrap a value in keyword identifiers.
|
||||
*
|
||||
* @param string $value
|
||||
* @return string
|
||||
*/
|
||||
public function wrap($value)
|
||||
{
|
||||
// If the value being wrapped contains a column alias, we need to
|
||||
// wrap it a little differently as each segment must be wrapped
|
||||
// and not the entire string. We'll split the value on the "as"
|
||||
// joiner to extract the column and the alias.
|
||||
if (strpos(strtolower($value), ' as ') !== false)
|
||||
{
|
||||
$segments = explode(' ', $value);
|
||||
|
||||
return $this->wrap($segments[0]).' AS '.$this->wrap($segments[2]);
|
||||
}
|
||||
|
||||
// Expressions should be injected into the query as raw strings,
|
||||
// so we do not want to wrap them in any way. We'll just return
|
||||
// the string value from the expression to be included.
|
||||
if ($value instanceof Expression) return $value->get();
|
||||
|
||||
// Since columns may be prefixed with their corresponding table
|
||||
// name so as to not make them ambiguous, we will need to wrap
|
||||
// the table and the column in keyword identifiers.
|
||||
foreach (explode('.', $value) as $segment)
|
||||
{
|
||||
if ($segment == '*')
|
||||
{
|
||||
$wrapped[] = $segment;
|
||||
}
|
||||
else
|
||||
{
|
||||
$wrapped[] = sprintf($this->wrapper, $segment);
|
||||
}
|
||||
}
|
||||
|
||||
return implode('.', $wrapped);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create query parameters from an array of values.
|
||||
*
|
||||
* <code>
|
||||
* Returns "?, ?, ?", which may be used as PDO place-holders
|
||||
* $parameters = $grammar->parameterize(array(1, 2, 3));
|
||||
*
|
||||
* // Returns "?, "Taylor"" since an expression is used
|
||||
* $parameters = $grammar->parameterize(array(1, DB::raw('Taylor')));
|
||||
* </code>
|
||||
*
|
||||
* @param array $values
|
||||
* @return string
|
||||
*/
|
||||
final public function parameterize($values)
|
||||
{
|
||||
return implode(', ', array_map(array($this, 'parameter'), $values));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the appropriate query parameter string for a value.
|
||||
*
|
||||
* <code>
|
||||
* // Returns a "?" PDO place-holder
|
||||
* $value = $grammar->parameter('Taylor Otwell');
|
||||
*
|
||||
* // Returns "Taylor Otwell" as the raw value of the expression
|
||||
* $value = $grammar->parameter(DB::raw('Taylor Otwell'));
|
||||
* </code>
|
||||
*
|
||||
* @param mixed $value
|
||||
* @return string
|
||||
*/
|
||||
final public function parameter($value)
|
||||
{
|
||||
return ($value instanceof Expression) ? $value->get() : '?';
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a comma-delimited list of wrapped column names.
|
||||
*
|
||||
* <code>
|
||||
* // Returns ""Taylor", "Otwell"" when the identifier is quotes
|
||||
* $columns = $grammar->columnize(array('Taylor', 'Otwell'));
|
||||
* </code>
|
||||
*
|
||||
* @param array $columns
|
||||
* @return string
|
||||
*/
|
||||
final public function columnize($columns)
|
||||
{
|
||||
return implode(', ', array_map(array($this, 'wrap'), $columns));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,134 +0,0 @@
|
||||
<?php namespace Laravel\Database;
|
||||
|
||||
use Laravel\IoC;
|
||||
use Laravel\Config;
|
||||
|
||||
class Manager {
|
||||
|
||||
/**
|
||||
* The established database connections.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $connections = array();
|
||||
|
||||
/**
|
||||
* Get a database connection.
|
||||
*
|
||||
* If no database name is specified, the default connection will be returned.
|
||||
*
|
||||
* <code>
|
||||
* // Get the default database connection for the application
|
||||
* $connection = DB::connection();
|
||||
*
|
||||
* // Get a specific connection by passing the connection name
|
||||
* $connection = DB::connection('mysql');
|
||||
* </code>
|
||||
*
|
||||
* @param string $connection
|
||||
* @return Connection
|
||||
*/
|
||||
public static function connection($connection = null)
|
||||
{
|
||||
if (is_null($connection)) $connection = Config::get('database.default');
|
||||
|
||||
if ( ! isset(static::$connections[$connection]))
|
||||
{
|
||||
$config = Config::get("database.connections.{$connection}");
|
||||
|
||||
if (is_null($config))
|
||||
{
|
||||
throw new \OutOfBoundsException("Connection is not defined for [$connection].");
|
||||
}
|
||||
|
||||
static::$connections[$connection] = new Connection(static::connect($config), $config);
|
||||
}
|
||||
|
||||
return static::$connections[$connection];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a PDO database connection for a given database configuration.
|
||||
*
|
||||
* @param array $config
|
||||
* @return PDO
|
||||
*/
|
||||
protected static function connect($config)
|
||||
{
|
||||
// We allow the developer to place a "connector" option in the database
|
||||
// configuration, which should have a Closure value. If the connector
|
||||
// is present, we will use the Closure to retrieve the PDO connection
|
||||
// to the database. This allows the flexiblity to connect to database
|
||||
// systems that are not officially supported by the the framework.
|
||||
if (isset($config['connector']))
|
||||
{
|
||||
return call_user_func($config['connector'], $config);
|
||||
}
|
||||
|
||||
return static::connector($config['driver'])->connect($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new database connector instance.
|
||||
*
|
||||
* The database connectors are responsible for simply establishing a PDO
|
||||
* database connection given a configuration. This allows us to easily
|
||||
* drop in support for new database systems by writing a connector.
|
||||
*
|
||||
* @param string $driver
|
||||
* @return Connector
|
||||
*/
|
||||
protected static function connector($driver)
|
||||
{
|
||||
switch ($driver)
|
||||
{
|
||||
case 'sqlite':
|
||||
return new Connectors\SQLite(DATABASE_PATH);
|
||||
|
||||
case 'mysql':
|
||||
return new Connectors\MySQL;
|
||||
|
||||
case 'pgsql':
|
||||
return new Connectors\Postgres;
|
||||
|
||||
default:
|
||||
throw new \DomainException("Database driver [$driver] is not supported.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Begin a fluent query against a table.
|
||||
*
|
||||
* @param string $table
|
||||
* @param string $connection
|
||||
* @return Queries\Query
|
||||
*/
|
||||
public static function table($table, $connection = null)
|
||||
{
|
||||
return static::connection($connection)->table($table);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new database expression instance.
|
||||
*
|
||||
* Database expressions are used to inject raw SQL into a fluent query.
|
||||
*
|
||||
* @param string $value
|
||||
* @return Expression
|
||||
*/
|
||||
public static function raw($value)
|
||||
{
|
||||
return new Expression($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic Method for calling methods on the default database connection.
|
||||
*
|
||||
* This provides a convenient API for querying or examining the default database connection.
|
||||
*/
|
||||
public static function __callStatic($method, $parameters)
|
||||
{
|
||||
return call_user_func_array(array(static::connection(), $method), $parameters);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,4 +1,10 @@
|
||||
<?php namespace Laravel\Database; use Laravel\Paginator;
|
||||
<?php namespace Laravel\Database;
|
||||
|
||||
use Closure;
|
||||
use Laravel\Database;
|
||||
use Laravel\Paginator;
|
||||
use Laravel\Database\Query\Grammars\Grammar;
|
||||
use Laravel\Database\Query\Grammars\SQLServer;
|
||||
|
||||
class Query {
|
||||
|
||||
@@ -12,7 +18,7 @@ class Query {
|
||||
/**
|
||||
* The query grammar instance.
|
||||
*
|
||||
* @var Grammars\Grammar
|
||||
* @var Query\Grammars\Grammar
|
||||
*/
|
||||
public $grammar;
|
||||
|
||||
@@ -58,6 +64,13 @@ class Query {
|
||||
*/
|
||||
public $wheres;
|
||||
|
||||
/**
|
||||
* The GROUP BY clauses.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $groupings;
|
||||
|
||||
/**
|
||||
* The ORDER BY clauses.
|
||||
*
|
||||
@@ -89,12 +102,12 @@ class Query {
|
||||
/**
|
||||
* Create a new query instance.
|
||||
*
|
||||
* @param Connection $connection
|
||||
* @param Grammars\Grammar $grammar
|
||||
* @param string $table
|
||||
* @param Connection $connection
|
||||
* @param Grammar $grammar
|
||||
* @param string $table
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Connection $connection, Grammars\Grammar $grammar, $table)
|
||||
public function __construct(Connection $connection, Grammar $grammar, $table)
|
||||
{
|
||||
$this->from = $table;
|
||||
$this->grammar = $grammar;
|
||||
@@ -156,7 +169,7 @@ class Query {
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the where clause to its initial state. All bindings will be cleared.
|
||||
* Reset the where clause to its initial state.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
@@ -203,8 +216,16 @@ class Query {
|
||||
* @param string $connector
|
||||
* @return Query
|
||||
*/
|
||||
public function where($column, $operator, $value, $connector = 'AND')
|
||||
public function where($column, $operator = null, $value = null, $connector = 'AND')
|
||||
{
|
||||
// If a CLosure is passed into the method, it means a nested where
|
||||
// clause is being initiated, so we will take a different course
|
||||
// of action than when the statement is just a simple where.
|
||||
if ($column instanceof Closure)
|
||||
{
|
||||
return $this->where_nested($column, $connector);
|
||||
}
|
||||
|
||||
$type = 'where';
|
||||
|
||||
$this->wheres[] = compact('type', 'column', 'operator', 'value', 'connector');
|
||||
@@ -222,7 +243,7 @@ class Query {
|
||||
* @param mixed $value
|
||||
* @return Query
|
||||
*/
|
||||
public function or_where($column, $operator, $value)
|
||||
public function or_where($column, $operator = null, $value = null)
|
||||
{
|
||||
return $this->where($column, $operator, $value, 'OR');
|
||||
}
|
||||
@@ -347,10 +368,35 @@ class Query {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add dynamic where conditions to the query.
|
||||
* Add a nested where condition to the query.
|
||||
*
|
||||
* Dynamic queries are caught by the __call magic method and are parsed here.
|
||||
* They provide a convenient, expressive API for building simple conditions.
|
||||
* @param Closure $callback
|
||||
* @param string $connector
|
||||
* @return Query
|
||||
*/
|
||||
protected function where_nested($callback, $connector)
|
||||
{
|
||||
$type = 'where_nested';
|
||||
|
||||
// To handle a nested where statement, we will actually instantiate a
|
||||
// new Query instance and run the callback over that instance, which
|
||||
// will allow the developer to have a fresh query to work with.
|
||||
$query = new Query($this->connection, $this->grammar, $this->from);
|
||||
|
||||
// Once the callback has been run on the query, we will store the
|
||||
// nested query instance on the where clause array so that it's
|
||||
// passed to the query grammar.
|
||||
call_user_func($callback, $query);
|
||||
|
||||
$this->wheres[] = compact('type', 'query', 'connector');
|
||||
|
||||
$this->bindings = array_merge($this->bindings, $query->bindings);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add dynamic where conditions to the query.
|
||||
*
|
||||
* @param string $method
|
||||
* @param array $parameters
|
||||
@@ -358,11 +404,11 @@ class Query {
|
||||
*/
|
||||
private function dynamic_where($method, $parameters)
|
||||
{
|
||||
// Strip the "where_" off of the method.
|
||||
$finder = substr($method, 6);
|
||||
|
||||
// Split the column names from the connectors.
|
||||
$segments = preg_split('/(_and_|_or_)/i', $finder, -1, PREG_SPLIT_DELIM_CAPTURE);
|
||||
$flags = PREG_SPLIT_DELIM_CAPTURE;
|
||||
|
||||
$segments = preg_split('/(_and_|_or_)/i', $finder, -1, $flags);
|
||||
|
||||
// The connector variable will determine which connector will be
|
||||
// used for the condition. We'll change it as we come across new
|
||||
@@ -377,6 +423,13 @@ class Query {
|
||||
|
||||
foreach ($segments as $segment)
|
||||
{
|
||||
// If the segment is not a boolean connector, we can assume it
|
||||
// it is a column name, and we'll add it to the query as a new
|
||||
// where clause.
|
||||
//
|
||||
// Otherwise, we'll store the connector so that we know how to
|
||||
// connection the next where clause we find to the query, as
|
||||
// all connectors should precede a new where clause.
|
||||
if ($segment != '_and_' and $segment != '_or_')
|
||||
{
|
||||
$this->where($segment, '=', $parameters[$index], $connector);
|
||||
@@ -392,6 +445,18 @@ class Query {
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a grouping to the query.
|
||||
*
|
||||
* @param string $column
|
||||
* @return Query
|
||||
*/
|
||||
public function group_by($column)
|
||||
{
|
||||
$this->groupings[] = $column;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an ordering to the query.
|
||||
*
|
||||
@@ -430,7 +495,7 @@ class Query {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the query limit and offset for a given page and item per page count.
|
||||
* Set the query limit and offset for a given page.
|
||||
*
|
||||
* @param int $page
|
||||
* @param int $per_page
|
||||
@@ -461,16 +526,14 @@ class Query {
|
||||
*/
|
||||
public function only($column)
|
||||
{
|
||||
$this->select(array($column));
|
||||
$sql = $this->grammar->select($this->select(array($column)));
|
||||
|
||||
return $this->connection->only($this->grammar->select($this), $this->bindings);
|
||||
return $this->connection->only($sql, $this->bindings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the query as a SELECT statement and return the first result.
|
||||
*
|
||||
* If a single column is selected from the database, only the value of that column will be returned.
|
||||
*
|
||||
* @param array $columns
|
||||
* @return mixed
|
||||
*/
|
||||
@@ -478,7 +541,51 @@ class Query {
|
||||
{
|
||||
$columns = (array) $columns;
|
||||
|
||||
return (count($results = $this->take(1)->get($columns)) > 0) ? $results[0] : null;
|
||||
// Since we only need the first result, we'll go ahead and set the
|
||||
// limit clause to 1, since this will be much faster than getting
|
||||
// all of the rows and then only returning the first.
|
||||
$results = $this->take(1)->get($columns);
|
||||
|
||||
return (count($results) > 0) ? $results[0] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array with the values of a given column.
|
||||
*
|
||||
* @param string $column
|
||||
* @param string $key
|
||||
* @return array
|
||||
*/
|
||||
public function lists($column, $key = null)
|
||||
{
|
||||
$columns = (is_null($key)) ? array($column) : array($column, $key);
|
||||
|
||||
$results = $this->get($columns);
|
||||
|
||||
// First we will get the array of values for the requested column.
|
||||
// Of course, this array will simply have numeric keys. After we
|
||||
// have this array we will determine if we need to key the array
|
||||
// by another column from the result set.
|
||||
$values = array_map(function($row) use ($column)
|
||||
{
|
||||
return $row->$column;
|
||||
|
||||
}, $results);
|
||||
|
||||
// If a key was provided, we will extract an array of keys and
|
||||
// set the keys on the array of values using the array_combine
|
||||
// function provided by PHP, which should give us the proper
|
||||
// array form to return from the method.
|
||||
if ( ! is_null($key))
|
||||
{
|
||||
return array_combine(array_map(function($row) use ($key)
|
||||
{
|
||||
return $row->$key;
|
||||
|
||||
}, $results), $values);
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -491,11 +598,25 @@ class Query {
|
||||
{
|
||||
if (is_null($this->selects)) $this->select($columns);
|
||||
|
||||
$results = $this->connection->query($this->grammar->select($this), $this->bindings);
|
||||
$sql = $this->grammar->select($this);
|
||||
|
||||
$results = $this->connection->query($sql, $this->bindings);
|
||||
|
||||
// If the query has an offset and we are using the SQL Server grammar,
|
||||
// we need to spin through the results and remove the "rownum" from
|
||||
// each of the objects. Unfortunately SQL Server does not have an
|
||||
// offset keyword, so we have to use row numbers in the query.
|
||||
if ($this->offset > 0 and $this->grammar instanceof SQLServer)
|
||||
{
|
||||
array_walk($results, function($result)
|
||||
{
|
||||
unset($result->rownum);
|
||||
});
|
||||
}
|
||||
|
||||
// Reset the SELECT clause so more queries can be performed using
|
||||
// the same instance. This is helpful for getting aggregates and
|
||||
// then getting actual results.
|
||||
// then getting actual results from the query.
|
||||
$this->selects = null;
|
||||
|
||||
return $results;
|
||||
@@ -512,11 +633,13 @@ class Query {
|
||||
{
|
||||
$this->aggregate = compact('aggregator', 'column');
|
||||
|
||||
$result = $this->connection->only($this->grammar->select($this), $this->bindings);
|
||||
$sql = $this->grammar->select($this);
|
||||
|
||||
$result = $this->connection->only($sql, $this->bindings);
|
||||
|
||||
// Reset the aggregate so more queries can be performed using
|
||||
// the same instance. This is helpful for getting aggregates
|
||||
// and then getting actual results.
|
||||
// and then getting actual results from the query.
|
||||
$this->aggregate = null;
|
||||
|
||||
return $result;
|
||||
@@ -531,17 +654,23 @@ class Query {
|
||||
*/
|
||||
public function paginate($per_page = 20, $columns = array('*'))
|
||||
{
|
||||
// Because some database engines may throw errors if we leave
|
||||
// orderings on the query when retrieving the total number
|
||||
// of records, we will remove all of the ordreings and put
|
||||
// them back on the query after we have the count.
|
||||
// Because some database engines may throw errors if we leave orderings
|
||||
// on the query when retrieving the total number of records, we will
|
||||
// remove all of the ordreings and put them back on the query after
|
||||
// we have the count.
|
||||
list($orderings, $this->orderings) = array($this->orderings, null);
|
||||
|
||||
$page = Paginator::page($total = $this->count(), $per_page);
|
||||
|
||||
$this->orderings = $orderings;
|
||||
|
||||
return Paginator::make($this->for_page($page, $per_page)->get($columns), $total, $per_page);
|
||||
// Now we're ready to get the actual pagination results from the
|
||||
// database table. The "for_page" method provides a convenient
|
||||
// way to set the limit and offset so we get the correct span
|
||||
// of results from the table.
|
||||
$results = $this->for_page($page, $per_page)->get($columns);
|
||||
|
||||
return Paginator::make($results, $total, $per_page);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -559,17 +688,21 @@ class Query {
|
||||
|
||||
$bindings = array();
|
||||
|
||||
// We need to merge the the insert values into the array of the query
|
||||
// bindings so that they will be bound to the PDO statement when it
|
||||
// is executed by the database connection.
|
||||
foreach ($values as $value)
|
||||
{
|
||||
$bindings = array_merge($bindings, array_values($value));
|
||||
}
|
||||
|
||||
return $this->connection->query($this->grammar->insert($this, $values), $bindings);
|
||||
$sql = $this->grammar->insert($this, $values);
|
||||
|
||||
return $this->connection->statement($sql, $bindings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert an array of values into the database table and
|
||||
* return the value of the ID column.
|
||||
* Insert an array of values into the database table and return the ID.
|
||||
*
|
||||
* @param array $values
|
||||
* @param string $sequence
|
||||
@@ -577,8 +710,13 @@ class Query {
|
||||
*/
|
||||
public function insert_get_id($values, $sequence = null)
|
||||
{
|
||||
$this->connection->query($this->grammar->insert($this, $values), array_values($values));
|
||||
$sql = $this->grammar->insert($this, $values);
|
||||
|
||||
$this->connection->statement($sql, array_values($values));
|
||||
|
||||
// Some database systems (Postgres) require a sequence name to be
|
||||
// given when retrieving the auto-incrementing ID, so we'll pass
|
||||
// the given sequence into the method just in case.
|
||||
return (int) $this->connection->pdo->lastInsertId($sequence);
|
||||
}
|
||||
|
||||
@@ -616,7 +754,10 @@ class Query {
|
||||
*/
|
||||
protected function adjust($column, $amount, $operator)
|
||||
{
|
||||
$value = Manager::raw($this->grammar->wrap($column).$operator.$amount);
|
||||
// To make the adjustment to the column, we'll wrap the expression
|
||||
// in an Expression instance, which forces the adjustment to be
|
||||
// injected into the query as a string instead of bound.
|
||||
$value = Database::raw($this->grammar->wrap($column).$operator.$amount);
|
||||
|
||||
return $this->update(array($column => $value));
|
||||
}
|
||||
@@ -629,9 +770,15 @@ class Query {
|
||||
*/
|
||||
public function update($values)
|
||||
{
|
||||
// For update statements, we need to merge the bindings such that
|
||||
// the update values occur before the where bindings in the array
|
||||
// since the set statements will precede any of the where clauses
|
||||
// in the SQL syntax that is generated.
|
||||
$bindings = array_merge(array_values($values), $this->bindings);
|
||||
|
||||
return $this->connection->query($this->grammar->update($this, $values), $bindings);
|
||||
$sql = $this->grammar->update($this, $values);
|
||||
|
||||
return $this->connection->update($sql, $bindings);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -644,16 +791,23 @@ class Query {
|
||||
*/
|
||||
public function delete($id = null)
|
||||
{
|
||||
if ( ! is_null($id)) $this->where('id', '=', $id);
|
||||
// If an ID is given to the method, we'll set the where clause
|
||||
// to match on the value of the ID. This allows the developer
|
||||
// to quickly delete a row by its primary key value.
|
||||
if ( ! is_null($id))
|
||||
{
|
||||
$this->where('id', '=', $id);
|
||||
}
|
||||
|
||||
return $this->connection->query($this->grammar->delete($this), $this->bindings);
|
||||
$sql = $this->grammar->delete($this);
|
||||
|
||||
return $this->connection->delete($sql, $this->bindings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic Method for handling dynamic functions.
|
||||
*
|
||||
* This method handles all calls to aggregate functions as well
|
||||
* as the construction of dynamic where clauses.
|
||||
* This method handles calls to aggregates as well as dynamic where clauses.
|
||||
*/
|
||||
public function __call($method, $parameters)
|
||||
{
|
||||
@@ -662,7 +816,7 @@ class Query {
|
||||
return $this->dynamic_where($method, $parameters, $this);
|
||||
}
|
||||
|
||||
if (in_array($method, array('abs', 'count', 'min', 'max', 'avg', 'sum')))
|
||||
if (in_array($method, array('count', 'min', 'max', 'avg', 'sum')))
|
||||
{
|
||||
if ($method == 'count')
|
||||
{
|
||||
@@ -674,7 +828,7 @@ class Query {
|
||||
}
|
||||
}
|
||||
|
||||
throw new \BadMethodCallException("Method [$method] is not defined on the Query class.");
|
||||
throw new \Exception("Method [$method] is not defined on the Query class.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,61 +1,70 @@
|
||||
<?php namespace Laravel\Database\Grammars;
|
||||
<?php namespace Laravel\Database\Query\Grammars;
|
||||
|
||||
use Laravel\Arr;
|
||||
use Laravel\Database\Query;
|
||||
use Laravel\Database\Expression;
|
||||
|
||||
class Grammar {
|
||||
|
||||
/**
|
||||
* The keyword identifier for the database system.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $wrapper = '"';
|
||||
class Grammar extends \Laravel\Database\Grammar {
|
||||
|
||||
/**
|
||||
* All of the query componenets in the order they should be built.
|
||||
*
|
||||
* Each derived compiler may adjust these components and place them in the
|
||||
* order needed for its particular database system, providing greater
|
||||
* control over how the query is structured.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $components = array(
|
||||
'aggregate',
|
||||
'selects',
|
||||
'from',
|
||||
'joins',
|
||||
'wheres',
|
||||
'orderings',
|
||||
'limit',
|
||||
'offset'
|
||||
'aggregate', 'selects', 'from', 'joins', 'wheres',
|
||||
'groupings', 'orderings', 'limit', 'offset',
|
||||
);
|
||||
|
||||
/**
|
||||
* Compile a SQL SELECT statement from a Query instance.
|
||||
*
|
||||
* The query will be compiled according to the order of the elements specified
|
||||
* in the "components" property. The entire query is passed into each component
|
||||
* compiler for convenience.
|
||||
*
|
||||
* @param Query $query
|
||||
* @return string
|
||||
*/
|
||||
final public function select(Query $query)
|
||||
public function select(Query $query)
|
||||
{
|
||||
$sql = array();
|
||||
return $this->concatenate($this->components($query));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the SQL for every component of the query.
|
||||
*
|
||||
* @param Query $query
|
||||
* @return array
|
||||
*/
|
||||
final protected function components($query)
|
||||
{
|
||||
// Each portion of the statement is compiled by a function corresponding
|
||||
// to an item in the components array. This lets us to keep the creation
|
||||
// of the query very granular, and allows for the flexible customization
|
||||
// of the query building process by each database system's grammar.
|
||||
//
|
||||
// Note that each component also corresponds to a public property on the
|
||||
// query instance, allowing us to pass the appropriate data into each of
|
||||
// the compiler functions.
|
||||
foreach ($this->components as $component)
|
||||
{
|
||||
if ( ! is_null($query->$component))
|
||||
{
|
||||
$sql[] = call_user_func(array($this, $component), $query);
|
||||
$sql[$component] = call_user_func(array($this, $component), $query);
|
||||
}
|
||||
}
|
||||
|
||||
return implode(' ', Arr::without($sql, array(null, '')));
|
||||
return (array) $sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenate an array of SQL segments, removing those that are empty.
|
||||
*
|
||||
* @param array $components
|
||||
* @return string
|
||||
*/
|
||||
final protected function concatenate($components)
|
||||
{
|
||||
return implode(' ', array_filter($components, function($value)
|
||||
{
|
||||
return (string) $value !== '';
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,11 +83,6 @@ class Grammar {
|
||||
/**
|
||||
* Compile an aggregating SELECT clause for a query.
|
||||
*
|
||||
* If an aggregate function is called on the query instance, no select
|
||||
* columns will be set, so it is safe to assume that the "selects"
|
||||
* compiler function will not be called. We can simply build the
|
||||
* aggregating select clause within this function.
|
||||
*
|
||||
* @param Query $query
|
||||
* @return string
|
||||
*/
|
||||
@@ -92,9 +96,6 @@ class Grammar {
|
||||
/**
|
||||
* Compile the FROM clause for a query.
|
||||
*
|
||||
* This method should not handle the construction of "join" clauses.
|
||||
* The join clauses will be constructured by their own compiler.
|
||||
*
|
||||
* @param Query $query
|
||||
* @return string
|
||||
*/
|
||||
@@ -111,8 +112,13 @@ class Grammar {
|
||||
*/
|
||||
protected function joins(Query $query)
|
||||
{
|
||||
$format = '%s JOIN %s ON %s %s %s';
|
||||
|
||||
// We need to iterate through each JOIN clause that is attached to the
|
||||
// query an translate it into SQL. The table and the columns will be
|
||||
// wrapped in identifiers to avoid naming collisions.
|
||||
//
|
||||
// Once all of the JOINs have been compiled, we can concatenate them
|
||||
// together using a single space, which should give us the complete
|
||||
// set of joins in valid SQL that can appended to the query.
|
||||
foreach ($query->joins as $join)
|
||||
{
|
||||
$table = $this->wrap($join['table']);
|
||||
@@ -121,7 +127,7 @@ class Grammar {
|
||||
|
||||
$column2 = $this->wrap($join['column2']);
|
||||
|
||||
$sql[] = sprintf($format, $join['type'], $table, $column1, $join['operator'], $column2);
|
||||
$sql[] = "{$join['type']} JOIN {$table} ON {$column1} {$join['operator']} {$column2}";
|
||||
}
|
||||
|
||||
return implode(' ', $sql);
|
||||
@@ -136,26 +142,44 @@ class Grammar {
|
||||
final protected function wheres(Query $query)
|
||||
{
|
||||
// Each WHERE clause array has a "type" that is assigned by the query
|
||||
// builder, and each type has its own compiler function. We will simply
|
||||
// iterate through the where clauses and call the appropriate compiler
|
||||
// for each clause.
|
||||
// builder, and each type has its own compiler function. We will call
|
||||
// the appropriate compiler for each where clause in the query.
|
||||
//
|
||||
// Keeping each particular where clause in its own "compiler" allows
|
||||
// us to keep the query generation process very granular, making it
|
||||
// easier to customize derived grammars for other databases.
|
||||
foreach ($query->wheres as $where)
|
||||
{
|
||||
$sql[] = $where['connector'].' '.$this->{$where['type']}($where);
|
||||
}
|
||||
|
||||
if (isset($sql)) return implode(' ', array_merge(array('WHERE 1 = 1'), $sql));
|
||||
if (isset($sql))
|
||||
{
|
||||
// We attach the boolean connector to every where segment just
|
||||
// for convenience. Once we have built the entire clause we'll
|
||||
// remove the first instance of a connector from the clause.
|
||||
return 'WHERE '.preg_replace('/AND |OR /', '', implode(' ', $sql), 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile a nested WHERE clause.
|
||||
*
|
||||
* @param array $where
|
||||
* @return string
|
||||
*/
|
||||
protected function where_nested($where)
|
||||
{
|
||||
// To generate a nested WHERE clause, we'll just feed the query
|
||||
// back into the "wheres" method. Once we have the clause, we
|
||||
// will strip off the first six characters to get rid of the
|
||||
// leading WHERE keyword.
|
||||
return '('.substr($this->wheres($where['query']), 6).')';
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile a simple WHERE clause.
|
||||
*
|
||||
* This method handles the compilation of the structures created by the
|
||||
* "where" and "or_where" methods on the query builder.
|
||||
*
|
||||
* This method also handles database expressions, so care must be taken
|
||||
* to implement this functionality in any derived database grammars.
|
||||
*
|
||||
* @param array $where
|
||||
* @return string
|
||||
*/
|
||||
@@ -220,11 +244,22 @@ class Grammar {
|
||||
* @param array $where
|
||||
* @return string
|
||||
*/
|
||||
protected function where_raw($where)
|
||||
final protected function where_raw($where)
|
||||
{
|
||||
return $where['sql'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile the GROUP BY clause for a query.
|
||||
*
|
||||
* @param Query $query
|
||||
* @return string
|
||||
*/
|
||||
protected function groupings(Query $query)
|
||||
{
|
||||
return 'GROUP BY '.$this->columnize($query->groupings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile the ORDER BY clause for a query.
|
||||
*
|
||||
@@ -235,7 +270,9 @@ class Grammar {
|
||||
{
|
||||
foreach ($query->orderings as $ordering)
|
||||
{
|
||||
$sql[] = $this->wrap($ordering['column']).' '.strtoupper($ordering['direction']);
|
||||
$direction = strtoupper($ordering['direction']);
|
||||
|
||||
$sql[] = $this->wrap($ordering['column']).' '.$direction;
|
||||
}
|
||||
|
||||
return 'ORDER BY '.implode(', ', $sql);
|
||||
@@ -266,7 +303,7 @@ class Grammar {
|
||||
/**
|
||||
* Compile a SQL INSERT statment from a Query instance.
|
||||
*
|
||||
* Note: This method handles the compilation of single row inserts and batch inserts.
|
||||
* This method handles the compilation of single row inserts and batch inserts.
|
||||
*
|
||||
* @param Query $query
|
||||
* @param array $values
|
||||
@@ -274,14 +311,16 @@ class Grammar {
|
||||
*/
|
||||
public function insert(Query $query, $values)
|
||||
{
|
||||
// Force every insert to be treated like a batch insert. This simple makes
|
||||
$table = $this->wrap($query->from);
|
||||
|
||||
// Force every insert to be treated like a batch insert. This simply makes
|
||||
// creating the SQL syntax a little easier on us since we can always treat
|
||||
// the values as if it is an array containing multiple inserts.
|
||||
if ( ! is_array(reset($values))) $values = array($values);
|
||||
|
||||
// Since we only care about the column names, we can pass any of the insert
|
||||
// arrays into the "columnize" method. The names should be the same for
|
||||
// every insert to the table.
|
||||
// arrays into the "columnize" method. The columns should be the same for
|
||||
// every insert to the table so we can just use the first record.
|
||||
$columns = $this->columnize(array_keys(reset($values)));
|
||||
|
||||
// Build the list of parameter place-holders of values bound to the query.
|
||||
@@ -289,24 +328,26 @@ class Grammar {
|
||||
// just use the first array of values.
|
||||
$parameters = $this->parameterize(reset($values));
|
||||
|
||||
$parameters = implode(', ', array_fill(0, count($values), '('.$parameters.')'));
|
||||
$parameters = implode(', ', array_fill(0, count($values), "($parameters)"));
|
||||
|
||||
return 'INSERT INTO '.$this->wrap($query->from).' ('.$columns.') VALUES '.$parameters;
|
||||
return "INSERT INTO {$table} ({$columns}) VALUES {$parameters}";
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile a SQL UPDATE statment from a Query instance.
|
||||
*
|
||||
* Note: Since UPDATE statements can be limited by a WHERE clause,
|
||||
* this method will use the same WHERE clause compilation
|
||||
* functions as the "select" method.
|
||||
*
|
||||
* @param Query $query
|
||||
* @param array $values
|
||||
* @return string
|
||||
*/
|
||||
public function update(Query $query, $values)
|
||||
{
|
||||
$table = $this->wrap($query->from);
|
||||
|
||||
// Each column in the UPDATE statement needs to be wrapped in keyword
|
||||
// identifiers, and a place-holder needs to be created for each value
|
||||
// in the array of bindings. Of course, if the value of the binding
|
||||
// is an expression, the expression string will be injected.
|
||||
foreach ($values as $column => $value)
|
||||
{
|
||||
$columns[] = $this->wrap($column).' = '.$this->parameter($value);
|
||||
@@ -314,7 +355,11 @@ class Grammar {
|
||||
|
||||
$columns = implode(', ', $columns);
|
||||
|
||||
return trim('UPDATE '.$this->wrap($query->from).' SET '.$columns.' '.$this->wheres($query));
|
||||
// UPDATE statements may be constrained by a WHERE clause, so we'll
|
||||
// run the entire where compilation process for those contraints.
|
||||
// This is easily achieved by passing the query to the "wheres"
|
||||
// method which will call all of the where compilers.
|
||||
return trim("UPDATE {$table} SET {$columns} ".$this->wheres($query));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -325,103 +370,13 @@ class Grammar {
|
||||
*/
|
||||
public function delete(Query $query)
|
||||
{
|
||||
return trim('DELETE FROM '.$this->wrap($query->from).' '.$this->wheres($query));
|
||||
}
|
||||
$table = $this->wrap($query->from);
|
||||
|
||||
/**
|
||||
* The following functions primarily serve as utility functions for
|
||||
* the grammar. They perform tasks such as wrapping values in keyword
|
||||
* identifiers or creating variable lists of bindings.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a comma-delimited list of wrapped column names.
|
||||
*
|
||||
* @param array $columns
|
||||
* @return string
|
||||
*/
|
||||
final public function columnize($columns)
|
||||
{
|
||||
return implode(', ', array_map(array($this, 'wrap'), $columns));
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap a value in keyword identifiers.
|
||||
*
|
||||
* They keyword identifier used by the method is specified as
|
||||
* a property on the grammar class so it can be conveniently
|
||||
* overriden without changing the wrapping logic itself.
|
||||
*
|
||||
* @param string $value
|
||||
* @return string
|
||||
*/
|
||||
public function wrap($value)
|
||||
{
|
||||
// If the value being wrapped contains a column alias, we need to wrap
|
||||
// it a little differently since each segment must be wrapped and not
|
||||
// the entire string.
|
||||
if (strpos(strtolower($value), ' as ') !== false)
|
||||
{
|
||||
return $this->alias($value);
|
||||
}
|
||||
|
||||
// Expressions should be injected into the query as raw strings, so we
|
||||
// do not want to wrap them in any way. We will just return the string
|
||||
// value from the expression to be included in the query.
|
||||
if ($value instanceof Expression) return $value->get();
|
||||
|
||||
foreach (explode('.', $value) as $segment)
|
||||
{
|
||||
if ($segment === '*')
|
||||
{
|
||||
$wrapped[] = $segment;
|
||||
}
|
||||
else
|
||||
{
|
||||
$wrapped[] = $this->wrapper.$segment.$this->wrapper;
|
||||
}
|
||||
}
|
||||
|
||||
return implode('.', $wrapped);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap an alias in keyword identifiers.
|
||||
*
|
||||
* @param string $value
|
||||
* @return string
|
||||
*/
|
||||
protected function alias($value)
|
||||
{
|
||||
$segments = explode(' ', $value);
|
||||
|
||||
return $this->wrap($segments[0]).' AS '.$this->wrap($segments[2]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create query parameters from an array of values.
|
||||
*
|
||||
* @param array $values
|
||||
* @return string
|
||||
*/
|
||||
public function parameterize($values)
|
||||
{
|
||||
return implode(', ', array_map(array($this, 'parameter'), $values));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the appropriate query parameter string for a value.
|
||||
*
|
||||
* If the value is an expression, the raw expression string should
|
||||
* be returned, otherwise, the parameter place-holder will be
|
||||
* returned by the method.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @return string
|
||||
*/
|
||||
public function parameter($value)
|
||||
{
|
||||
return ($value instanceof Expression) ? $value->get() : '?';
|
||||
// Like the UPDATE statement, the DELETE statement is constrained
|
||||
// by WHERE clauses, so we'll need to run the "wheres" method to
|
||||
// make the WHERE clauses for the query. The "wheres" method
|
||||
// encapsulates the logic to create the full WHERE clause.
|
||||
return trim("DELETE FROM {$table} ".$this->wheres($query));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
<?php namespace Laravel\Database\Grammars;
|
||||
<?php namespace Laravel\Database\Query\Grammars;
|
||||
|
||||
class MySQL extends Grammar {
|
||||
|
||||
@@ -7,6 +7,6 @@ class MySQL extends Grammar {
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $wrapper = '`';
|
||||
protected $wrapper = '`%s`';
|
||||
|
||||
}
|
||||
139
laravel/database/query/grammars/sqlserver.php
Normal file
139
laravel/database/query/grammars/sqlserver.php
Normal file
@@ -0,0 +1,139 @@
|
||||
<?php namespace Laravel\Database\Query\Grammars;
|
||||
|
||||
use Laravel\Database\Query;
|
||||
|
||||
class SQLServer extends Grammar {
|
||||
|
||||
/**
|
||||
* The keyword identifier for the database system.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $wrapper = '[%s]';
|
||||
|
||||
/**
|
||||
* Compile a SQL SELECT statement from a Query instance.
|
||||
*
|
||||
* @param Query $query
|
||||
* @return string
|
||||
*/
|
||||
public function select(Query $query)
|
||||
{
|
||||
$sql = parent::components($query);
|
||||
|
||||
// SQL Server does not currently implement an "OFFSET" type keyword, so we
|
||||
// actually have to generate the ANSI standard SQL for doing offset like
|
||||
// functionality. In the next version of SQL Server, an OFFSET like
|
||||
// keyword is included for convenience.
|
||||
if ($query->offset > 0)
|
||||
{
|
||||
return $this->ansi_offset($query, $sql);
|
||||
}
|
||||
|
||||
// Once all of the clauses have been compiled, we can join them all as
|
||||
// one statement. Any segments that are null or an empty string will
|
||||
// be removed from the array of clauses before they are imploded.
|
||||
return $this->concatenate($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile the SELECT clause for a query.
|
||||
*
|
||||
* @param Query $query
|
||||
* @return string
|
||||
*/
|
||||
protected function selects(Query $query)
|
||||
{
|
||||
$select = ($query->distinct) ? 'SELECT DISTINCT ' : 'SELECT ';
|
||||
|
||||
// Instead of using a "LIMIT" keyword, SQL Server uses the "TOP"
|
||||
// keyword within the SELECT statement. So, if we have a limit,
|
||||
// we will add it here.
|
||||
//
|
||||
// We will not add the TOP clause if there is an offset however,
|
||||
// since we will have to handle offsets using the ANSI syntax
|
||||
// and will need to remove the TOP clause in that situation.
|
||||
if ($query->limit > 0 and $query->offset <= 0)
|
||||
{
|
||||
$select .= 'TOP '.$query->limit.' ';
|
||||
}
|
||||
|
||||
return $select.$this->columnize($query->selects);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the ANSI standard SQL for an offset clause.
|
||||
*
|
||||
* @param Query $query
|
||||
* @param array $components
|
||||
* @return array
|
||||
*/
|
||||
protected function ansi_offset(Query $query, $components)
|
||||
{
|
||||
// An ORDER BY clause is required to make this offset query
|
||||
// work, so if one doesn't exist, we'll just create a dummy
|
||||
// clause to satisfy the database.
|
||||
if ( ! isset($components['orderings']))
|
||||
{
|
||||
$components['orderings'] = 'ORDER BY (SELECT 0)';
|
||||
}
|
||||
|
||||
// We need to add the row number to the query results so we
|
||||
// can compare it against the offset and limit values given
|
||||
// for the statement. To do that we'll add an expression to
|
||||
// the select statement for the row number.
|
||||
$orderings = $components['orderings'];
|
||||
|
||||
$components['selects'] .= ", ROW_NUMBER() OVER ({$orderings}) AS RowNum";
|
||||
|
||||
unset($components['orderings']);
|
||||
|
||||
$start = $query->offset + 1;
|
||||
|
||||
// Next we need to calculate the constraint that should be
|
||||
// placed on the row number to get the correct offset and
|
||||
// limit on the query. If a limit has not been set, we'll
|
||||
// only add a constraint to handle offset.
|
||||
if ($query->limit > 0)
|
||||
{
|
||||
$finish = $query->offset + $query->limit;
|
||||
|
||||
$constraint = "BETWEEN {$start} AND {$finish}";
|
||||
}
|
||||
else
|
||||
{
|
||||
$constraint = ">= {$start}";
|
||||
}
|
||||
|
||||
// Now, we're finally ready to build the final SQL query.
|
||||
// We'll create a common table expression with the query
|
||||
// and then select all of the results from it where the
|
||||
// row number is between oru given limit and offset.
|
||||
$sql = $this->concatenate($components);
|
||||
|
||||
return "SELECT * FROM ($sql) AS TempTable WHERE RowNum {$constraint}";
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile the LIMIT clause for a query.
|
||||
*
|
||||
* @param Query $query
|
||||
* @return string
|
||||
*/
|
||||
protected function limit(Query $query)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile the OFFSET clause for a query.
|
||||
*
|
||||
* @param Query $query
|
||||
* @return string
|
||||
*/
|
||||
protected function offset(Query $query)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
119
laravel/database/schema.php
Normal file
119
laravel/database/schema.php
Normal file
@@ -0,0 +1,119 @@
|
||||
<?php namespace Laravel\Database;
|
||||
|
||||
use Laravel\Fluent;
|
||||
use Laravel\Database as DB;
|
||||
|
||||
class Schema {
|
||||
|
||||
/**
|
||||
* Begin a fluent schema operation on a database table.
|
||||
*
|
||||
* @param string $table
|
||||
* @param Closure $callback
|
||||
* @return void
|
||||
*/
|
||||
public static function table($table, $callback)
|
||||
{
|
||||
call_user_func($callback, $table = new Schema\Table($table));
|
||||
|
||||
static::implications($table);
|
||||
|
||||
return static::execute($table);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the given schema operation against the database.
|
||||
*
|
||||
* @param Schema\Table $table
|
||||
* @return void
|
||||
*/
|
||||
public static function execute($table)
|
||||
{
|
||||
foreach ($table->commands as $command)
|
||||
{
|
||||
$connection = DB::connection($table->connection);
|
||||
|
||||
$grammar = static::grammar($connection->driver());
|
||||
|
||||
// Each grammar has a function that corresponds to the command type
|
||||
// and is responsible for building that's commands SQL. This lets
|
||||
// the SQL generation stay very granular and makes it simply to
|
||||
// add new database systems to the schema system.
|
||||
if (method_exists($grammar, $method = $command->type))
|
||||
{
|
||||
$statements = $grammar->$method($table, $command);
|
||||
|
||||
// Once we have the statements, we will cast them to an array even
|
||||
// though not all of the commands return an array. This is just in
|
||||
// case the command needs to run more than one query to do what
|
||||
// it needs to do what is requested by the developer.
|
||||
foreach ((array) $statements as $statement)
|
||||
{
|
||||
$connection->statement($statement);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add any implicit commands to the schema table operation.
|
||||
*
|
||||
* @param Schema\Table $table
|
||||
* @return void
|
||||
*/
|
||||
protected static function implications($table)
|
||||
{
|
||||
// If the developer has specified columns for the table and the
|
||||
// table is not being created, we will assume they simply want
|
||||
// to add the columns to the table, and will generate an add
|
||||
// command for them, adding the columns to the command.
|
||||
if (count($table->columns) > 0 and ! $table->creating())
|
||||
{
|
||||
$command = new Fluent(array('type' => 'add'));
|
||||
|
||||
array_unshift($table->commands, $command);
|
||||
}
|
||||
|
||||
// For some extra syntax sugar, we'll check for any implicit
|
||||
// indexes on the table. The developer may specify the index
|
||||
// type on the fluent column declaration. Here we'll find
|
||||
// any such implicit index and add the actual command.
|
||||
foreach ($table->columns as $column)
|
||||
{
|
||||
foreach (array('primary', 'unique', 'fulltext', 'index') as $key)
|
||||
{
|
||||
if ($column->$key === true)
|
||||
{
|
||||
$table->$key($column->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the appropriate schema grammar for the driver.
|
||||
*
|
||||
* @param string $driver
|
||||
* @return Grammar
|
||||
*/
|
||||
public static function grammar($driver)
|
||||
{
|
||||
switch ($driver)
|
||||
{
|
||||
case 'mysql':
|
||||
return new Schema\Grammars\MySQL;
|
||||
|
||||
case 'pgsql':
|
||||
return new Schema\Grammars\Postgres;
|
||||
|
||||
case 'sqlsrv':
|
||||
return new Schema\Grammars\SQLServer;
|
||||
|
||||
case 'sqlite':
|
||||
return new Schema\Grammars\SQLite;
|
||||
}
|
||||
|
||||
throw new \Exception("Schema operations not supported for [$driver].");
|
||||
}
|
||||
|
||||
}
|
||||
38
laravel/database/schema/grammars/grammar.php
Normal file
38
laravel/database/schema/grammars/grammar.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php namespace Laravel\Database\Schema\Grammars;
|
||||
|
||||
use Laravel\Fluent;
|
||||
use Laravel\Database\Schema\Table;
|
||||
|
||||
abstract class Grammar extends \Laravel\Database\Grammar {
|
||||
|
||||
/**
|
||||
* Get the appropriate data type definition for the column.
|
||||
*
|
||||
* @param Fluent $column
|
||||
* @return string
|
||||
*/
|
||||
protected function type(Fluent $column)
|
||||
{
|
||||
return $this->{'type_'.$column->type}($column);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap a value in keyword identifiers.
|
||||
*
|
||||
* @param Table|string $value
|
||||
* @return string
|
||||
*/
|
||||
public function wrap($value)
|
||||
{
|
||||
// This method is primarily for convenience so we can just pass a
|
||||
// column or table instance into the wrap method without sending
|
||||
// in the name each time we need to wrap one of these objects.
|
||||
if ($value instanceof Table or $value instanceof Fluent)
|
||||
{
|
||||
$value = $value->name;
|
||||
}
|
||||
|
||||
return parent::wrap($value);
|
||||
}
|
||||
|
||||
}
|
||||
386
laravel/database/schema/grammars/mysql.php
Normal file
386
laravel/database/schema/grammars/mysql.php
Normal file
@@ -0,0 +1,386 @@
|
||||
<?php namespace Laravel\Database\Schema\Grammars;
|
||||
|
||||
use Laravel\Fluent;
|
||||
use Laravel\Database\Schema\Table;
|
||||
|
||||
class MySQL extends Grammar {
|
||||
|
||||
/**
|
||||
* The keyword identifier for the database system.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $wrapper = '`%s`';
|
||||
|
||||
/**
|
||||
* Generate the SQL statements for a table creation command.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $command
|
||||
* @return array
|
||||
*/
|
||||
public function create(Table $table, Fluent $command)
|
||||
{
|
||||
$columns = implode(', ', $this->columns($table));
|
||||
|
||||
// First we will generate the base table creation statement. Other than
|
||||
// auto-incrementing keys, no indexes will be created during the first
|
||||
// creation of the table. They will be added in separate commands.
|
||||
$sql = 'CREATE TABLE '.$this->wrap($table).' ('.$columns.')';
|
||||
|
||||
// MySQL supports various "engines" for database tables. If an engine
|
||||
// was specified by the developer, we will set it after adding the
|
||||
// columns the table creation statement.
|
||||
if ( ! is_null($table->engine))
|
||||
{
|
||||
$sql .= ' ENGINE = '.$table->engine;
|
||||
}
|
||||
|
||||
return $sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Geenrate the SQL statements for a table modification command.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $command
|
||||
* @return array
|
||||
*/
|
||||
public function add(Table $table, Fluent $command)
|
||||
{
|
||||
$columns = $this->columns($table);
|
||||
|
||||
// Once we the array of column definitions, we need to add "add"
|
||||
// to the front of each definition, then we'll concatenate the
|
||||
// definitions using commas like normal and generate the SQL.
|
||||
$columns = implode(', ', array_map(function($column)
|
||||
{
|
||||
return 'ADD '.$column;
|
||||
|
||||
}, $columns));
|
||||
|
||||
return 'ALTER TABLE '.$this->wrap($table).' '.$columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the individual column definitions for the table.
|
||||
*
|
||||
* @param Table $table
|
||||
* @return array
|
||||
*/
|
||||
protected function columns(Table $table)
|
||||
{
|
||||
$columns = array();
|
||||
|
||||
foreach ($table->columns as $column)
|
||||
{
|
||||
// Each of the data type's have their own definition creation method,
|
||||
// which is responsible for creating the SQL for the type. This lets
|
||||
// us to keep the syntax easy and fluent, while translating the
|
||||
// types to the types used by the database.
|
||||
$sql = $this->wrap($column).' '.$this->type($column);
|
||||
|
||||
$elements = array('nullable', 'defaults', 'incrementer');
|
||||
|
||||
foreach ($elements as $element)
|
||||
{
|
||||
$sql .= $this->$element($table, $column);
|
||||
}
|
||||
|
||||
$columns[] = $sql;
|
||||
}
|
||||
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the SQL syntax for indicating if a column is nullable.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $column
|
||||
* @return string
|
||||
*/
|
||||
protected function nullable(Table $table, Fluent $column)
|
||||
{
|
||||
return ($column->nullable) ? ' NULL' : ' NOT NULL';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the SQL syntax for specifying a default value on a column.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $column
|
||||
* @return string
|
||||
*/
|
||||
protected function defaults(Table $table, Fluent $column)
|
||||
{
|
||||
if ( ! is_null($column->default))
|
||||
{
|
||||
return " DEFAULT '".$column->default."'";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the SQL syntax for defining an auto-incrementing column.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $column
|
||||
* @return string
|
||||
*/
|
||||
protected function incrementer(Table $table, Fluent $column)
|
||||
{
|
||||
if ($column->type == 'integer' and $column->increment)
|
||||
{
|
||||
return ' AUTO_INCREMENT PRIMARY KEY';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the SQL statement for creating a primary key.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $command
|
||||
* @return string
|
||||
*/
|
||||
public function primary(Table $table, Fluent $command)
|
||||
{
|
||||
return $this->key($table, $command, 'PRIMARY KEY');
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the SQL statement for creating a unique index.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $command
|
||||
* @return string
|
||||
*/
|
||||
public function unique(Table $table, Fluent $command)
|
||||
{
|
||||
return $this->key($table, $command, 'UNIQUE');
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the SQL statement for creating a full-text index.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $command
|
||||
* @return string
|
||||
*/
|
||||
public function fulltext(Table $table, Fluent $command)
|
||||
{
|
||||
return $this->key($table, $command, 'FULLTEXT');
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the SQL statement for creating a regular index.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $command
|
||||
* @return string
|
||||
*/
|
||||
public function index(Table $table, Fluent $command)
|
||||
{
|
||||
return $this->key($table, $command, 'INDEX');
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the SQL statement for creating a new index.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $command
|
||||
* @param string $type
|
||||
* @return string
|
||||
*/
|
||||
protected function key(Table $table, Fluent $command, $type)
|
||||
{
|
||||
$keys = $this->columnize($command->columns);
|
||||
|
||||
$name = $command->name;
|
||||
|
||||
return 'ALTER TABLE '.$this->wrap($table)." ADD {$type} {$name}({$keys})";
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the SQL statement for a drop table command.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $command
|
||||
* @return string
|
||||
*/
|
||||
public function drop(Table $table, Fluent $command)
|
||||
{
|
||||
return 'DROP TABLE '.$this->wrap($table);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the SQL statement for a drop column command.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $command
|
||||
* @return string
|
||||
*/
|
||||
public function drop_column(Table $table, Fluent $command)
|
||||
{
|
||||
$columns = array_map(array($this, 'wrap'), $command->columns);
|
||||
|
||||
// Once we the array of column names, we need to add "drop" to the
|
||||
// front of each column, then we'll concatenate the columns using
|
||||
// commas and generate the alter statement SQL.
|
||||
$columns = implode(', ', array_map(function($column)
|
||||
{
|
||||
return 'DROP '.$column;
|
||||
|
||||
}, $columns));
|
||||
|
||||
return 'ALTER TABLE '.$this->wrap($table).' '.$columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the SQL statement for a drop primary key command.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $command
|
||||
* @return string
|
||||
*/
|
||||
public function drop_primary(Table $table, Fluent $command)
|
||||
{
|
||||
return 'ALTER TABLE '.$this->wrap($table).' DROP PRIMARY KEY';
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the SQL statement for a drop unqique key command.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $command
|
||||
* @return string
|
||||
*/
|
||||
public function drop_unique(Table $table, Fluent $command)
|
||||
{
|
||||
return $this->drop_key($table, $command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the SQL statement for a drop full-text key command.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $command
|
||||
* @return string
|
||||
*/
|
||||
public function drop_fulltext(Table $table, Fluent $command)
|
||||
{
|
||||
return $this->drop_key($table, $command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the SQL statement for a drop unqique key command.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $command
|
||||
* @return string
|
||||
*/
|
||||
public function drop_index(Table $table, Fluent $command)
|
||||
{
|
||||
return $this->drop_key($table, $command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the SQL statement for a drop key command.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $command
|
||||
* @return string
|
||||
*/
|
||||
protected function drop_key(Table $table, Fluent $command)
|
||||
{
|
||||
return 'ALTER TABLE '.$this->wrap($table)." DROP INDEX {$command->name}";
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the data-type definition for a string.
|
||||
*
|
||||
* @param Fluent $column
|
||||
* @return string
|
||||
*/
|
||||
protected function type_string(Fluent $column)
|
||||
{
|
||||
return 'VARCHAR('.$column->length.')';
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the data-type definition for an integer.
|
||||
*
|
||||
* @param Fluent $column
|
||||
* @return string
|
||||
*/
|
||||
protected function type_integer(Fluent $column)
|
||||
{
|
||||
return 'INT';
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the data-type definition for an integer.
|
||||
*
|
||||
* @param Fluent $column
|
||||
* @return string
|
||||
*/
|
||||
protected function type_float(Fluent $column)
|
||||
{
|
||||
return 'FLOAT';
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the data-type definition for a boolean.
|
||||
*
|
||||
* @param Fluent $column
|
||||
* @return string
|
||||
*/
|
||||
protected function type_boolean(Fluent $column)
|
||||
{
|
||||
return 'TINYINT';
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the data-type definition for a date.
|
||||
*
|
||||
* @param Fluent $column
|
||||
* @return string
|
||||
*/
|
||||
protected function type_date(Fluent $column)
|
||||
{
|
||||
return 'DATETIME';
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the data-type definition for a timestamp.
|
||||
*
|
||||
* @param Fluent $column
|
||||
* @return string
|
||||
*/
|
||||
protected function type_timestamp(Fluent $column)
|
||||
{
|
||||
return 'TIMESTAMP';
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the data-type definition for a text column.
|
||||
*
|
||||
* @param Fluent $column
|
||||
* @return string
|
||||
*/
|
||||
protected function type_text(Fluent $column)
|
||||
{
|
||||
return 'TEXT';
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the data-type definition for a blob.
|
||||
*
|
||||
* @param Fluent $column
|
||||
* @return string
|
||||
*/
|
||||
protected function type_blob(Fluent $column)
|
||||
{
|
||||
return 'BLOB';
|
||||
}
|
||||
|
||||
}
|
||||
381
laravel/database/schema/grammars/postgres.php
Normal file
381
laravel/database/schema/grammars/postgres.php
Normal file
@@ -0,0 +1,381 @@
|
||||
<?php namespace Laravel\Database\Schema\Grammars;
|
||||
|
||||
use Laravel\Fluent;
|
||||
use Laravel\Database\Schema\Table;
|
||||
|
||||
class Postgres extends Grammar {
|
||||
|
||||
/**
|
||||
* Generate the SQL statements for a table creation command.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $command
|
||||
* @return array
|
||||
*/
|
||||
public function create(Table $table, Fluent $command)
|
||||
{
|
||||
$columns = implode(', ', $this->columns($table));
|
||||
|
||||
// First we will generate the base table creation statement. Other than
|
||||
// auto-incrementing keys, no indexes will be created during the first
|
||||
// creation of the table. They will be added in separate commands.
|
||||
$sql = 'CREATE TABLE '.$this->wrap($table).' ('.$columns.')';
|
||||
|
||||
return $sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Geenrate the SQL statements for a table modification command.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $command
|
||||
* @return array
|
||||
*/
|
||||
public function add(Table $table, Fluent $command)
|
||||
{
|
||||
$columns = $this->columns($table);
|
||||
|
||||
// Once we the array of column definitions, we'll add "add column"
|
||||
// to the front of each definition, then we'll concatenate the
|
||||
// definitions using commas like normal and generate the SQL.
|
||||
$columns = implode(', ', array_map(function($column)
|
||||
{
|
||||
return 'ADD COLUMN '.$column;
|
||||
|
||||
}, $columns));
|
||||
|
||||
return 'ALTER TABLE '.$this->wrap($table).' '.$columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the individual column definitions for the table.
|
||||
*
|
||||
* @param Table $table
|
||||
* @return array
|
||||
*/
|
||||
protected function columns(Table $table)
|
||||
{
|
||||
$columns = array();
|
||||
|
||||
foreach ($table->columns as $column)
|
||||
{
|
||||
// Each of the data type's have their own definition creation method,
|
||||
// which is responsible for creating the SQL for the type. This lets
|
||||
// us to keep the syntax easy and fluent, while translating the
|
||||
// types to the types used by the database.
|
||||
$sql = $this->wrap($column).' '.$this->type($column);
|
||||
|
||||
$elements = array('incrementer', 'nullable', 'defaults');
|
||||
|
||||
foreach ($elements as $element)
|
||||
{
|
||||
$sql .= $this->$element($table, $column);
|
||||
}
|
||||
|
||||
$columns[] = $sql;
|
||||
}
|
||||
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the SQL syntax for indicating if a column is nullable.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $column
|
||||
* @return string
|
||||
*/
|
||||
protected function nullable(Table $table, Fluent $column)
|
||||
{
|
||||
return ($column->nullable) ? ' NULL' : ' NOT NULL';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the SQL syntax for specifying a default value on a column.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $column
|
||||
* @return string
|
||||
*/
|
||||
protected function defaults(Table $table, Fluent $column)
|
||||
{
|
||||
if ( ! is_null($column->default))
|
||||
{
|
||||
return " DEFAULT '".$column->default."'";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the SQL syntax for defining an auto-incrementing column.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $column
|
||||
* @return string
|
||||
*/
|
||||
protected function incrementer(Table $table, Fluent $column)
|
||||
{
|
||||
// We don't actually need to specify an "auto_increment" keyword since
|
||||
// we handle the auto-increment definition in the type definition for
|
||||
// integers by changing the type to "serial", which is a convenient
|
||||
// notational short-cut provided by Postgres.
|
||||
if ($column->type == 'integer' and $column->increment)
|
||||
{
|
||||
return ' PRIMARY KEY';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the SQL statement for creating a primary key.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $command
|
||||
* @return string
|
||||
*/
|
||||
public function primary(Table $table, Fluent $command)
|
||||
{
|
||||
$columns = $this->columnize($command->columns);
|
||||
|
||||
return 'ALTER TABLE '.$this->wrap($table)." ADD PRIMARY KEY ({$columns})";
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the SQL statement for creating a unique index.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $command
|
||||
* @return string
|
||||
*/
|
||||
public function unique(Table $table, Fluent $command)
|
||||
{
|
||||
return $this->key($table, $command, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the SQL statement for creating a full-text index.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $command
|
||||
* @return string
|
||||
*/
|
||||
public function fulltext(Table $table, Fluent $command)
|
||||
{
|
||||
$name = $command->name;
|
||||
|
||||
$columns = $this->columnize($command->columns);
|
||||
|
||||
return "CREATE INDEX {$name} ON ".$this->wrap($table)." USING gin({$columns})";
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the SQL statement for creating a regular index.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $command
|
||||
* @return string
|
||||
*/
|
||||
public function index(Table $table, Fluent $command)
|
||||
{
|
||||
return $this->key($table, $command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the SQL statement for creating a new index.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $command
|
||||
* @param bool $unique
|
||||
* @return string
|
||||
*/
|
||||
protected function key(Table $table, Fluent $command, $unique = false)
|
||||
{
|
||||
$columns = $this->columnize($command->columns);
|
||||
|
||||
$create = ($unique) ? 'CREATE UNIQUE' : 'CREATE';
|
||||
|
||||
return $create." INDEX {$command->name} ON ".$this->wrap($table)." ({$columns})";
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the SQL statement for a drop table command.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $command
|
||||
* @return string
|
||||
*/
|
||||
public function drop(Table $table, Fluent $command)
|
||||
{
|
||||
return 'DROP TABLE '.$this->wrap($table);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the SQL statement for a drop column command.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $command
|
||||
* @return string
|
||||
*/
|
||||
public function drop_column(Table $table, Fluent $command)
|
||||
{
|
||||
$columns = array_map(array($this, 'wrap'), $command->columns);
|
||||
|
||||
// Once we the array of column names, we need to add "drop" to the
|
||||
// front of each column, then we'll concatenate the columns using
|
||||
// commas and generate the alter statement SQL.
|
||||
$columns = implode(', ', array_map(function($column)
|
||||
{
|
||||
return 'DROP COLUMN '.$column;
|
||||
|
||||
}, $columns));
|
||||
|
||||
return 'ALTER TABLE '.$this->wrap($table).' '.$columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the SQL statement for a drop primary key command.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $command
|
||||
* @return string
|
||||
*/
|
||||
public function drop_primary(Table $table, Fluent $command)
|
||||
{
|
||||
return 'ALTER TABLE '.$this->wrap($table).' DROP CONSTRAINT '.$table->name.'_pkey';
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the SQL statement for a drop unqique key command.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $command
|
||||
* @return string
|
||||
*/
|
||||
public function drop_unique(Table $table, Fluent $command)
|
||||
{
|
||||
return $this->drop_key($table, $command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the SQL statement for a drop full-text key command.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $command
|
||||
* @return string
|
||||
*/
|
||||
public function drop_fulltext(Table $table, Fluent $command)
|
||||
{
|
||||
return $this->drop_key($table, $command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the SQL statement for a drop index command.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $command
|
||||
* @return string
|
||||
*/
|
||||
public function drop_index(Table $table, Fluent $command)
|
||||
{
|
||||
return $this->drop_key($table, $command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the SQL statement for a drop key command.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $command
|
||||
* @return string
|
||||
*/
|
||||
protected function drop_key(Table $table, Fluent $command)
|
||||
{
|
||||
return 'DROP INDEX '.$command->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the data-type definition for a string.
|
||||
*
|
||||
* @param Fluent $column
|
||||
* @return string
|
||||
*/
|
||||
protected function type_string(Fluent $column)
|
||||
{
|
||||
return 'VARCHAR('.$column->length.')';
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the data-type definition for an integer.
|
||||
*
|
||||
* @param Fluent $column
|
||||
* @return string
|
||||
*/
|
||||
protected function type_integer(Fluent $column)
|
||||
{
|
||||
return ($column->increment) ? 'SERIAL' : 'INTEGER';
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the data-type definition for an integer.
|
||||
*
|
||||
* @param Fluent $column
|
||||
* @return string
|
||||
*/
|
||||
protected function type_float(Fluent $column)
|
||||
{
|
||||
return 'REAL';
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the data-type definition for a boolean.
|
||||
*
|
||||
* @param Fluent $column
|
||||
* @return string
|
||||
*/
|
||||
protected function type_boolean(Fluent $column)
|
||||
{
|
||||
return 'SMALLINT';
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the data-type definition for a date.
|
||||
*
|
||||
* @param Fluent $column
|
||||
* @return string
|
||||
*/
|
||||
protected function type_date(Fluent $column)
|
||||
{
|
||||
return 'TIMESTAMP';
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the data-type definition for a timestamp.
|
||||
*
|
||||
* @param Fluent $column
|
||||
* @return string
|
||||
*/
|
||||
protected function type_timestamp(Fluent $column)
|
||||
{
|
||||
return 'TIMESTAMP';
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the data-type definition for a text column.
|
||||
*
|
||||
* @param Fluent $column
|
||||
* @return string
|
||||
*/
|
||||
protected function type_text(Fluent $column)
|
||||
{
|
||||
return 'TEXT';
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the data-type definition for a blob.
|
||||
*
|
||||
* @param Fluent $column
|
||||
* @return string
|
||||
*/
|
||||
protected function type_blob(Fluent $column)
|
||||
{
|
||||
return 'BYTEA';
|
||||
}
|
||||
|
||||
}
|
||||
344
laravel/database/schema/grammars/sqlite.php
Normal file
344
laravel/database/schema/grammars/sqlite.php
Normal file
@@ -0,0 +1,344 @@
|
||||
<?php namespace Laravel\Database\Schema\Grammars;
|
||||
|
||||
use Laravel\Fluent;
|
||||
use Laravel\Database\Schema\Table;
|
||||
|
||||
class SQLite extends Grammar {
|
||||
|
||||
/**
|
||||
* Generate the SQL statements for a table creation command.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $command
|
||||
* @return array
|
||||
*/
|
||||
public function create(Table $table, Fluent $command)
|
||||
{
|
||||
$columns = implode(', ', $this->columns($table));
|
||||
|
||||
// First we will generate the base table creation statement. Other than
|
||||
// auto-incrementing keys, no indexes will be created during the first
|
||||
// creation of the table. They will be added in separate commands.
|
||||
$sql = 'CREATE TABLE '.$this->wrap($table).' ('.$columns;
|
||||
|
||||
// SQLite does not allow adding a primary key as a command apart from
|
||||
// when the table is initially created, so we'll need to sniff out
|
||||
// any primary keys here and add them to the table.
|
||||
//
|
||||
// Because of this, this class does not have the typical "primary"
|
||||
// method as it would be pointless since the primary keys can't
|
||||
// be set on anything but the table creation statement.
|
||||
$primary = array_first($table->commands, function($key, $value)
|
||||
{
|
||||
return $value->type == 'primary';
|
||||
});
|
||||
|
||||
// If we found primary key in the array of commands, we'll create
|
||||
// the SQL for the key addition and append it to the SQL table
|
||||
// creation statement for the schema table.
|
||||
if ( ! is_null($primary))
|
||||
{
|
||||
$columns = $this->columnize($primary->columns);
|
||||
|
||||
$sql .= ", PRIMARY KEY ({$columns})";
|
||||
}
|
||||
|
||||
return $sql .= ')';
|
||||
}
|
||||
|
||||
/**
|
||||
* Geenrate the SQL statements for a table modification command.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $command
|
||||
* @return array
|
||||
*/
|
||||
public function add(Table $table, Fluent $command)
|
||||
{
|
||||
$columns = $this->columns($table);
|
||||
|
||||
// Once we have an array of all of the column definitions, we need to
|
||||
// spin through each one and prepend "ADD COLUMN" to each of them,
|
||||
// which is the syntax used by SQLite when adding columns.
|
||||
$columns = array_map(function($column)
|
||||
{
|
||||
return 'ADD COLUMN '.$column;
|
||||
|
||||
}, $columns);
|
||||
|
||||
// SQLite only allows one column to be added in an ALTER statement,
|
||||
// so we will create an array of statements and return them all to
|
||||
// the schema manager, which will execute each one.
|
||||
foreach ($columns as $column)
|
||||
{
|
||||
$sql[] = 'ALTER TABLE '.$this->wrap($table).' '.$column;
|
||||
}
|
||||
|
||||
return (array) $sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the individual column definitions for the table.
|
||||
*
|
||||
* @param Table $table
|
||||
* @return array
|
||||
*/
|
||||
protected function columns(Table $table)
|
||||
{
|
||||
$columns = array();
|
||||
|
||||
foreach ($table->columns as $column)
|
||||
{
|
||||
// Each of the data type's have their own definition creation method
|
||||
// which is responsible for creating the SQL for the type. This lets
|
||||
// us to keep the syntax easy and fluent, while translating the
|
||||
// types to the types used by the database.
|
||||
$sql = $this->wrap($column).' '.$this->type($column);
|
||||
|
||||
$elements = array('nullable', 'defaults', 'incrementer');
|
||||
|
||||
foreach ($elements as $element)
|
||||
{
|
||||
$sql .= $this->$element($table, $column);
|
||||
}
|
||||
|
||||
$columns[] = $sql;
|
||||
}
|
||||
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the SQL syntax for indicating if a column is nullable.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $column
|
||||
* @return string
|
||||
*/
|
||||
protected function nullable(Table $table, Fluent $column)
|
||||
{
|
||||
return ($column->nullable) ? ' NULL' : ' NOT NULL';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the SQL syntax for specifying a default value on a column.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $column
|
||||
* @return string
|
||||
*/
|
||||
protected function defaults(Table $table, Fluent $column)
|
||||
{
|
||||
if ( ! is_null($column->default))
|
||||
{
|
||||
return ' DEFAULT '.$this->wrap($column->default);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the SQL syntax for defining an auto-incrementing column.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $column
|
||||
* @return string
|
||||
*/
|
||||
protected function incrementer(Table $table, Fluent $column)
|
||||
{
|
||||
if ($column->type == 'integer' and $column->increment)
|
||||
{
|
||||
return ' PRIMARY KEY AUTOINCREMENT';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the SQL statement for creating a unique index.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $command
|
||||
* @return string
|
||||
*/
|
||||
public function unique(Table $table, Fluent $command)
|
||||
{
|
||||
return $this->key($table, $command, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the SQL statement for creating a full-text index.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $command
|
||||
* @return string
|
||||
*/
|
||||
public function fulltext(Table $table, Fluent $command)
|
||||
{
|
||||
$columns = $this->columnize($command->columns);
|
||||
|
||||
return 'CREATE VIRTUAL TABLE '.$this->wrap($table)." USING fts4({$columns})";
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the SQL statement for creating a regular index.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $command
|
||||
* @return string
|
||||
*/
|
||||
public function index(Table $table, Fluent $command)
|
||||
{
|
||||
return $this->key($table, $command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the SQL statement for creating a new index.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $command
|
||||
* @param bool $unique
|
||||
* @return string
|
||||
*/
|
||||
protected function key(Table $table, Fluent $command, $unique = false)
|
||||
{
|
||||
$columns = $this->columnize($command->columns);
|
||||
|
||||
$create = ($unique) ? 'CREATE UNIQUE' : 'CREATE';
|
||||
|
||||
return $create." INDEX {$command->name} ON ".$this->wrap($table)." ({$columns})";
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the SQL statement for a drop table command.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $command
|
||||
* @return string
|
||||
*/
|
||||
public function drop(Table $table, Fluent $command)
|
||||
{
|
||||
return 'DROP TABLE '.$this->wrap($table);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the SQL statement for a drop unqique key command.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $command
|
||||
* @return string
|
||||
*/
|
||||
public function drop_unique(Table $table, Fluent $command)
|
||||
{
|
||||
return $this->drop_key($table, $command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the SQL statement for a drop unqique key command.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $command
|
||||
* @return string
|
||||
*/
|
||||
public function drop_index(Table $table, Fluent $command)
|
||||
{
|
||||
return $this->drop_key($table, $command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the SQL statement for a drop key command.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $command
|
||||
* @return string
|
||||
*/
|
||||
protected function drop_key(Table $table, Fluent $command)
|
||||
{
|
||||
return 'DROP INDEX '.$this->wrap($command->name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the data-type definition for a string.
|
||||
*
|
||||
* @param Fluent $column
|
||||
* @return string
|
||||
*/
|
||||
protected function type_string(Fluent $column)
|
||||
{
|
||||
return 'VARCHAR';
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the data-type definition for an integer.
|
||||
*
|
||||
* @param Fluent $column
|
||||
* @return string
|
||||
*/
|
||||
protected function type_integer(Fluent $column)
|
||||
{
|
||||
return 'INTEGER';
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the data-type definition for an integer.
|
||||
*
|
||||
* @param Fluent $column
|
||||
* @return string
|
||||
*/
|
||||
protected function type_float(Fluent $column)
|
||||
{
|
||||
return 'FLOAT';
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the data-type definition for a boolean.
|
||||
*
|
||||
* @param Fluent $column
|
||||
* @return string
|
||||
*/
|
||||
protected function type_boolean(Fluent $column)
|
||||
{
|
||||
return 'INTEGER';
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the data-type definition for a date.
|
||||
*
|
||||
* @param Fluent $column
|
||||
* @return string
|
||||
*/
|
||||
protected function type_date(Fluent $column)
|
||||
{
|
||||
return 'DATETIME';
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the data-type definition for a timestamp.
|
||||
*
|
||||
* @param Fluent $column
|
||||
* @return string
|
||||
*/
|
||||
protected function type_timestamp(Fluent $column)
|
||||
{
|
||||
return 'DATETIME';
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the data-type definition for a text column.
|
||||
*
|
||||
* @param Fluent $column
|
||||
* @return string
|
||||
*/
|
||||
protected function type_text(Fluent $column)
|
||||
{
|
||||
return 'TEXT';
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the data-type definition for a blob.
|
||||
*
|
||||
* @param Fluent $column
|
||||
* @return string
|
||||
*/
|
||||
protected function type_blob(Fluent $column)
|
||||
{
|
||||
return 'BLOB';
|
||||
}
|
||||
|
||||
}
|
||||
402
laravel/database/schema/grammars/sqlserver.php
Normal file
402
laravel/database/schema/grammars/sqlserver.php
Normal file
@@ -0,0 +1,402 @@
|
||||
<?php namespace Laravel\Database\Schema\Grammars;
|
||||
|
||||
use Laravel\Fluent;
|
||||
use Laravel\Database\Schema\Table;
|
||||
|
||||
class SQLServer extends Grammar {
|
||||
|
||||
/**
|
||||
* The keyword identifier for the database system.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $wrapper = '[%s]';
|
||||
|
||||
/**
|
||||
* Generate the SQL statements for a table creation command.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $command
|
||||
* @return array
|
||||
*/
|
||||
public function create(Table $table, Fluent $command)
|
||||
{
|
||||
$columns = implode(', ', $this->columns($table));
|
||||
|
||||
// First we will generate the base table creation statement. Other than
|
||||
// auto-incrementing keys, no indexes will be created during the first
|
||||
// creation of the table. They will be added in separate commands.
|
||||
$sql = 'CREATE TABLE '.$this->wrap($table).' ('.$columns.')';
|
||||
|
||||
return $sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Geenrate the SQL statements for a table modification command.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $command
|
||||
* @return array
|
||||
*/
|
||||
public function add(Table $table, Fluent $command)
|
||||
{
|
||||
$columns = $this->columns($table);
|
||||
|
||||
// Once we the array of column definitions, we need to add "add"
|
||||
// to the front of each definition, then we'll concatenate the
|
||||
// definitions using commas like normal and generate the SQL.
|
||||
$columns = implode(', ', array_map(function($column)
|
||||
{
|
||||
return 'ADD '.$column;
|
||||
|
||||
}, $columns));
|
||||
|
||||
return 'ALTER TABLE '.$this->wrap($table).' '.$columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the individual column definitions for the table.
|
||||
*
|
||||
* @param Table $table
|
||||
* @return array
|
||||
*/
|
||||
protected function columns(Table $table)
|
||||
{
|
||||
$columns = array();
|
||||
|
||||
foreach ($table->columns as $column)
|
||||
{
|
||||
// Each of the data type's have their own definition creation method,
|
||||
// which is responsible for creating the SQL for the type. This lets
|
||||
// us to keep the syntax easy and fluent, while translating the
|
||||
// types to the types used by the database.
|
||||
$sql = $this->wrap($column).' '.$this->type($column);
|
||||
|
||||
$elements = array('incrementer', 'nullable', 'defaults');
|
||||
|
||||
foreach ($elements as $element)
|
||||
{
|
||||
$sql .= $this->$element($table, $column);
|
||||
}
|
||||
|
||||
$columns[] = $sql;
|
||||
}
|
||||
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the SQL syntax for indicating if a column is nullable.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $column
|
||||
* @return string
|
||||
*/
|
||||
protected function nullable(Table $table, Fluent $column)
|
||||
{
|
||||
return ($column->nullable) ? ' NULL' : ' NOT NULL';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the SQL syntax for specifying a default value on a column.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $column
|
||||
* @return string
|
||||
*/
|
||||
protected function defaults(Table $table, Fluent $column)
|
||||
{
|
||||
if ( ! is_null($column->default))
|
||||
{
|
||||
return " DEFAULT '".$column->default."'";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the SQL syntax for defining an auto-incrementing column.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $column
|
||||
* @return string
|
||||
*/
|
||||
protected function incrementer(Table $table, Fluent $column)
|
||||
{
|
||||
if ($column->type == 'integer' and $column->increment)
|
||||
{
|
||||
return ' IDENTITY PRIMARY KEY';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the SQL statement for creating a primary key.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $command
|
||||
* @return string
|
||||
*/
|
||||
public function primary(Table $table, Fluent $command)
|
||||
{
|
||||
$name = $command->name;
|
||||
|
||||
$columns = $this->columnize($columns);
|
||||
|
||||
return 'ALTER TABLE '.$this->wrap($table)." ADD CONSTRAINT {$name} PRIMARY KEY ({$columns})";
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the SQL statement for creating a unique index.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $command
|
||||
* @return string
|
||||
*/
|
||||
public function unique(Table $table, Fluent $command)
|
||||
{
|
||||
return $this->key($table, $command, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the SQL statement for creating a full-text index.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $command
|
||||
* @return string
|
||||
*/
|
||||
public function fulltext(Table $table, Fluent $command)
|
||||
{
|
||||
$columns = $this->columnize($command->columns);
|
||||
|
||||
// SQL Server requires the creation of a full-text "catalog" before
|
||||
// creating a full-text index, so we'll first create the catalog
|
||||
// then add another statement for the index. The catalog will
|
||||
// be updated automatically by the server.
|
||||
$sql[] = "CREATE FULLTEXT CATALOG {$command->catalog}";
|
||||
|
||||
$create = "CREATE FULLTEXT INDEX ON ".$this->wrap($table)." ({$columns}) ";
|
||||
|
||||
// Full-text indexes must specify a unique, non-nullable column as
|
||||
// the index "key" and this should have been created manually by
|
||||
// the developer in a separate column addition command, so we
|
||||
// can just specify it in this statement.
|
||||
$sql[] = $create .= "KEY INDEX {$command->key} ON {$command->catalog}";
|
||||
|
||||
return $sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the SQL statement for creating a regular index.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $command
|
||||
* @return string
|
||||
*/
|
||||
public function index(Table $table, Fluent $command)
|
||||
{
|
||||
return $this->key($table, $command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the SQL statement for creating a new index.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $command
|
||||
* @param bool $unique
|
||||
* @return string
|
||||
*/
|
||||
protected function key(Table $table, Fluent $command, $unique = false)
|
||||
{
|
||||
$columns = $this->columnize($command->columns);
|
||||
|
||||
$create = ($unique) ? 'CREATE UNIQUE' : 'CREATE';
|
||||
|
||||
return $create." INDEX {$command->name} ON ".$this->wrap($table)." ({$columns})";
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the SQL statement for a drop table command.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $command
|
||||
* @return string
|
||||
*/
|
||||
public function drop(Table $table, Fluent $command)
|
||||
{
|
||||
return 'DROP TABLE '.$this->wrap($table);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the SQL statement for a drop column command.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $command
|
||||
* @return string
|
||||
*/
|
||||
public function drop_column(Table $table, Fluent $command)
|
||||
{
|
||||
$columns = array_map(array($this, 'wrap'), $command->columns);
|
||||
|
||||
// Once we the array of column names, we need to add "drop" to the
|
||||
// front of each column, then we'll concatenate the columns using
|
||||
// commas and generate the alter statement SQL.
|
||||
$columns = implode(', ', array_map(function($column)
|
||||
{
|
||||
return 'DROP '.$column;
|
||||
|
||||
}, $columns));
|
||||
|
||||
return 'ALTER TABLE '.$this->wrap($table).' '.$columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the SQL statement for a drop primary key command.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $command
|
||||
* @return string
|
||||
*/
|
||||
public function drop_primary(Table $table, Fluent $command)
|
||||
{
|
||||
return 'ALTER TABLE '.$this->wrap($table).' DROP CONSTRAINT '.$command->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the SQL statement for a drop unqiue key command.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $command
|
||||
* @return string
|
||||
*/
|
||||
public function drop_unique(Table $table, Fluent $command)
|
||||
{
|
||||
return $this->drop_key($table, $command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the SQL statement for a drop full-text key command.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $command
|
||||
* @return string
|
||||
*/
|
||||
public function drop_fulltext(Table $table, Fluent $command)
|
||||
{
|
||||
$sql[] = "DROP FULLTEXT INDEX ".$command->name;
|
||||
|
||||
$sql[] = "DROP FULLTEXT CATALOG ".$command->catalog;
|
||||
|
||||
return $sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the SQL statement for a drop index command.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $command
|
||||
* @return string
|
||||
*/
|
||||
public function drop_index(Table $table, Fluent $command)
|
||||
{
|
||||
return $this->drop_key($table, $command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the SQL statement for a drop key command.
|
||||
*
|
||||
* @param Table $table
|
||||
* @param Fluent $command
|
||||
* @return string
|
||||
*/
|
||||
protected function drop_key(Table $table, Fluent $command)
|
||||
{
|
||||
return "DROP INDEX {$command->name} ON ".$this->wrap($table);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the data-type definition for a string.
|
||||
*
|
||||
* @param Fluent $column
|
||||
* @return string
|
||||
*/
|
||||
protected function type_string(Fluent $column)
|
||||
{
|
||||
return 'NVARCHAR('.$column->length.')';
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the data-type definition for an integer.
|
||||
*
|
||||
* @param Fluent $column
|
||||
* @return string
|
||||
*/
|
||||
protected function type_integer(Fluent $column)
|
||||
{
|
||||
return 'INT';
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the data-type definition for an integer.
|
||||
*
|
||||
* @param Fluent $column
|
||||
* @return string
|
||||
*/
|
||||
protected function type_float(Fluent $column)
|
||||
{
|
||||
return 'FLOAT';
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the data-type definition for a boolean.
|
||||
*
|
||||
* @param Fluent $column
|
||||
* @return string
|
||||
*/
|
||||
protected function type_boolean(Fluent $column)
|
||||
{
|
||||
return 'TINYINT';
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the data-type definition for a date.
|
||||
*
|
||||
* @param Fluent $column
|
||||
* @return string
|
||||
*/
|
||||
protected function type_date(Fluent $column)
|
||||
{
|
||||
return 'DATETIME';
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the data-type definition for a timestamp.
|
||||
*
|
||||
* @param Fluent $column
|
||||
* @return string
|
||||
*/
|
||||
protected function type_timestamp(Fluent $column)
|
||||
{
|
||||
return 'TIMESTAMP';
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the data-type definition for a text column.
|
||||
*
|
||||
* @param Fluent $column
|
||||
* @return string
|
||||
*/
|
||||
protected function type_text(Fluent $column)
|
||||
{
|
||||
return 'NVARCHAR(MAX)';
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the data-type definition for a blob.
|
||||
*
|
||||
* @param Fluent $column
|
||||
* @return string
|
||||
*/
|
||||
protected function type_blob(Fluent $column)
|
||||
{
|
||||
return 'VARBINARY(MAX)';
|
||||
}
|
||||
|
||||
}
|
||||
371
laravel/database/schema/table.php
Normal file
371
laravel/database/schema/table.php
Normal file
@@ -0,0 +1,371 @@
|
||||
<?php namespace Laravel\Database\Schema;
|
||||
|
||||
use Laravel\Fluent;
|
||||
|
||||
class Table {
|
||||
|
||||
/**
|
||||
* The database table name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $name;
|
||||
|
||||
/**
|
||||
* The database connection that should be used.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $connection;
|
||||
|
||||
/**
|
||||
* The engine that should be used for the table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $engine;
|
||||
|
||||
/**
|
||||
* The columns that should be added to the table.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $columns = array();
|
||||
|
||||
/**
|
||||
* The commands that should be executed on the table.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $commands = array();
|
||||
|
||||
/**
|
||||
* Create a new schema table instance.
|
||||
*
|
||||
* @param string $name
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that the table should be created.
|
||||
*
|
||||
* @return Fluent
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
return $this->command(__FUNCTION__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new primary key on the table.
|
||||
*
|
||||
* @param string|array $columns
|
||||
* @param string $name
|
||||
* @return Fluent
|
||||
*/
|
||||
public function primary($columns, $name = null)
|
||||
{
|
||||
return $this->key(__FUNCTION__, $columns, $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new unique index on the table.
|
||||
*
|
||||
* @param string|array $columns
|
||||
* @param string $name
|
||||
* @return Fluent
|
||||
*/
|
||||
public function unique($columns, $name = null)
|
||||
{
|
||||
return $this->key(__FUNCTION__, $columns, $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new full-text index on the table.
|
||||
*
|
||||
* @param string|array $columns
|
||||
* @param string $name
|
||||
* @return Fluent
|
||||
*/
|
||||
public function fulltext($columns, $name = null)
|
||||
{
|
||||
return $this->key(__FUNCTION__, $columns, $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new index on the table.
|
||||
*
|
||||
* @param string|array
|
||||
*/
|
||||
public function index($columns, $name = null)
|
||||
{
|
||||
return $this->key(__FUNCTION__, $columns, $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a command for creating any index.
|
||||
*
|
||||
* @param string $type
|
||||
* @param string|array $columns
|
||||
* @param string $name
|
||||
* @return Fluent
|
||||
*/
|
||||
public function key($type, $columns, $name = null)
|
||||
{
|
||||
$parameters = array('name' => $name, 'columns' => (array) $columns);
|
||||
|
||||
return $this->command($type, $parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop the database table.
|
||||
*
|
||||
* @return Fluent
|
||||
*/
|
||||
public function drop()
|
||||
{
|
||||
return $this->command(__FUNCTION__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop a column from the table.
|
||||
*
|
||||
* @param string|array $columns
|
||||
* @return void
|
||||
*/
|
||||
public function drop_column($columns)
|
||||
{
|
||||
return $this->command(__FUNCTION__, array('columns' => (array) $columns));
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop a primary key from the table.
|
||||
*
|
||||
* @param string $name
|
||||
* @return void
|
||||
*/
|
||||
public function drop_primary($name)
|
||||
{
|
||||
return $this->drop_key(__FUNCTION__, $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop a unique index from the table.
|
||||
*
|
||||
* @param string $name
|
||||
* @return void
|
||||
*/
|
||||
public function drop_unique($name)
|
||||
{
|
||||
return $this->drop_key(__FUNCTION__, $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop a full-text index from the table.
|
||||
*
|
||||
* @param string $name
|
||||
* @return void
|
||||
*/
|
||||
public function drop_fulltext($name)
|
||||
{
|
||||
return $this->drop_key(__FUNCTION__, $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop an index from the table.
|
||||
*
|
||||
* @param string $name
|
||||
* @return void
|
||||
*/
|
||||
public function drop_index($name)
|
||||
{
|
||||
return $this->drop_key(__FUNCTION__, $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a command to drop any type of index.
|
||||
*
|
||||
* @param string $type
|
||||
* @param string $name
|
||||
* @return Fluent
|
||||
*/
|
||||
protected function drop_key($type, $name)
|
||||
{
|
||||
return $this->command($type, array('name' => $name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an auto-incrementing integer to the table.
|
||||
*
|
||||
* @param string $name
|
||||
* @return Fluent
|
||||
*/
|
||||
public function increments($name)
|
||||
{
|
||||
return $this->integer($name, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a string column to the table.
|
||||
*
|
||||
* @param string $name
|
||||
* @param int $length
|
||||
* @return Fluent
|
||||
*/
|
||||
public function string($name, $length = 200)
|
||||
{
|
||||
return $this->column(__FUNCTION__, compact('name', 'length'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an integer column to the table.
|
||||
*
|
||||
* @param string $name
|
||||
* @param bool $increment
|
||||
* @return Fluent
|
||||
*/
|
||||
public function integer($name, $increment = false)
|
||||
{
|
||||
return $this->column(__FUNCTION__, compact('name', 'increment'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a float column to the table.
|
||||
*
|
||||
* @param string $name
|
||||
* @param bool $increment
|
||||
* @return Fluent
|
||||
*/
|
||||
public function float($name)
|
||||
{
|
||||
return $this->column(__FUNCTION__, compact('name'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a boolean column to the table.
|
||||
*
|
||||
* @param string $name
|
||||
* @return Fluent
|
||||
*/
|
||||
public function boolean($name)
|
||||
{
|
||||
return $this->column(__FUNCTION__, compact('name'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create date-time columns for creation and update timestamps.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function timestamps()
|
||||
{
|
||||
$this->date('created_at');
|
||||
|
||||
$this->date('updated_at');
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a date-time column to the table.
|
||||
*
|
||||
* @param string $name
|
||||
* @return Fluent
|
||||
*/
|
||||
public function date($name)
|
||||
{
|
||||
return $this->column(__FUNCTION__, compact('name'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a timestamp column to the table.
|
||||
*
|
||||
* @param string $name
|
||||
* @return Fluent
|
||||
*/
|
||||
public function timestamp($name)
|
||||
{
|
||||
return $this->column(__FUNCTION__, compact('name'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a text column to the table.
|
||||
*
|
||||
* @param string $name
|
||||
* @return Fluent
|
||||
*/
|
||||
public function text($name)
|
||||
{
|
||||
return $this->column(__FUNCTION__, compact('name'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a blob column to the table.
|
||||
*
|
||||
* @param string $name
|
||||
* @return Fluent
|
||||
*/
|
||||
public function blob($name)
|
||||
{
|
||||
return $this->column(__FUNCTION__, compact('name'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the database connection for the table operation.
|
||||
*
|
||||
* @param string $connection
|
||||
* @return void
|
||||
*/
|
||||
public function on($connection)
|
||||
{
|
||||
$this->connection = $connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the schema table has a creation command.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function creating()
|
||||
{
|
||||
return ! is_null(array_first($this->commands, function($key, $value)
|
||||
{
|
||||
return $value->type == 'create';
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new fluent command instance.
|
||||
*
|
||||
* @param string $type
|
||||
* @param array $parameters
|
||||
* @return Fluent
|
||||
*/
|
||||
protected function command($type, $parameters = array())
|
||||
{
|
||||
$parameters = array_merge(compact('type'), $parameters);
|
||||
|
||||
$this->commands[] = new Fluent($parameters);
|
||||
|
||||
return end($this->commands);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new fluent column instance.
|
||||
*
|
||||
* @param string $type
|
||||
* @param array $parameters
|
||||
* @return Fluent
|
||||
*/
|
||||
protected function column($type, $parameters = array())
|
||||
{
|
||||
$parameters = array_merge(compact('type'), $parameters);
|
||||
|
||||
$this->columns[] = new Fluent($parameters);
|
||||
|
||||
return end($this->columns);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user