SeedServiceProvider.php 0000666 00000002046 13436755161 0011212 0 ustar 00 app->singleton('seeder', function () {
return new Seeder;
});
$this->registerSeedCommand();
$this->commands('command.seed');
}
/**
* Register the seed console command.
*
* @return void
*/
protected function registerSeedCommand()
{
$this->app->singleton('command.seed', function ($app) {
return new SeedCommand($app['db']);
});
}
/**
* Get the services provided by the provider.
*
* @return array
*/
public function provides()
{
return ['seeder', 'command.seed'];
}
}
Schema/Blueprint.php 0000666 00000064402 13436755161 0010446 0 ustar 00 table = $table;
if (! is_null($callback)) {
$callback($this);
}
}
/**
* Execute the blueprint against the database.
*
* @param \Illuminate\Database\Connection $connection
* @param \Illuminate\Database\Schema\Grammars\Grammar $grammar
* @return void
*/
public function build(Connection $connection, Grammar $grammar)
{
foreach ($this->toSql($connection, $grammar) as $statement) {
$connection->statement($statement);
}
}
/**
* Get the raw SQL statements for the blueprint.
*
* @param \Illuminate\Database\Connection $connection
* @param \Illuminate\Database\Schema\Grammars\Grammar $grammar
* @return array
*/
public function toSql(Connection $connection, Grammar $grammar)
{
$this->addImpliedCommands();
$statements = [];
// Each type of command has a corresponding compiler function on the schema
// grammar which is used to build the necessary SQL statements to build
// the blueprint element, so we'll just call that compilers function.
foreach ($this->commands as $command) {
$method = 'compile'.ucfirst($command->name);
if (method_exists($grammar, $method)) {
if (! is_null($sql = $grammar->$method($this, $command, $connection))) {
$statements = array_merge($statements, (array) $sql);
}
}
}
return $statements;
}
/**
* Add the commands that are implied by the blueprint.
*
* @return void
*/
protected function addImpliedCommands()
{
if (count($this->getAddedColumns()) > 0 && ! $this->creating()) {
array_unshift($this->commands, $this->createCommand('add'));
}
if (count($this->getChangedColumns()) > 0 && ! $this->creating()) {
array_unshift($this->commands, $this->createCommand('change'));
}
$this->addFluentIndexes();
}
/**
* Add the index commands fluently specified on columns.
*
* @return void
*/
protected function addFluentIndexes()
{
foreach ($this->columns as $column) {
foreach (['primary', 'unique', 'index'] as $index) {
// If the index has been specified on the given column, but is simply
// equal to "true" (boolean), no name has been specified for this
// index, so we will simply call the index methods without one.
if ($column->$index === true) {
$this->$index($column->name);
continue 2;
}
// If the index has been specified on the column and it is something
// other than boolean true, we will assume a name was provided on
// the index specification, and pass in the name to the method.
elseif (isset($column->$index)) {
$this->$index($column->name, $column->$index);
continue 2;
}
}
}
}
/**
* Determine if the blueprint has a create command.
*
* @return bool
*/
protected function creating()
{
foreach ($this->commands as $command) {
if ($command->name == 'create') {
return true;
}
}
return false;
}
/**
* Indicate that the table needs to be created.
*
* @return \Illuminate\Support\Fluent
*/
public function create()
{
return $this->addCommand('create');
}
/**
* Indicate that the table needs to be temporary.
*
* @return void
*/
public function temporary()
{
$this->temporary = true;
}
/**
* Indicate that the table should be dropped.
*
* @return \Illuminate\Support\Fluent
*/
public function drop()
{
return $this->addCommand('drop');
}
/**
* Indicate that the table should be dropped if it exists.
*
* @return \Illuminate\Support\Fluent
*/
public function dropIfExists()
{
return $this->addCommand('dropIfExists');
}
/**
* Indicate that the given columns should be dropped.
*
* @param array|mixed $columns
* @return \Illuminate\Support\Fluent
*/
public function dropColumn($columns)
{
$columns = is_array($columns) ? $columns : (array) func_get_args();
return $this->addCommand('dropColumn', compact('columns'));
}
/**
* Indicate that the given columns should be renamed.
*
* @param string $from
* @param string $to
* @return \Illuminate\Support\Fluent
*/
public function renameColumn($from, $to)
{
return $this->addCommand('renameColumn', compact('from', 'to'));
}
/**
* Indicate that the given primary key should be dropped.
*
* @param string|array $index
* @return \Illuminate\Support\Fluent
*/
public function dropPrimary($index = null)
{
return $this->dropIndexCommand('dropPrimary', 'primary', $index);
}
/**
* Indicate that the given unique key should be dropped.
*
* @param string|array $index
* @return \Illuminate\Support\Fluent
*/
public function dropUnique($index)
{
return $this->dropIndexCommand('dropUnique', 'unique', $index);
}
/**
* Indicate that the given index should be dropped.
*
* @param string|array $index
* @return \Illuminate\Support\Fluent
*/
public function dropIndex($index)
{
return $this->dropIndexCommand('dropIndex', 'index', $index);
}
/**
* Indicate that the given foreign key should be dropped.
*
* @param string|array $index
* @return \Illuminate\Support\Fluent
*/
public function dropForeign($index)
{
return $this->dropIndexCommand('dropForeign', 'foreign', $index);
}
/**
* Indicate that the timestamp columns should be dropped.
*
* @return void
*/
public function dropTimestamps()
{
$this->dropColumn('created_at', 'updated_at');
}
/**
* Indicate that the timestamp columns should be dropped.
*
* @return void
*/
public function dropTimestampsTz()
{
$this->dropTimestamps();
}
/**
* Indicate that the soft delete column should be dropped.
*
* @return void
*/
public function dropSoftDeletes()
{
$this->dropColumn('deleted_at');
}
/**
* Indicate that the remember token column should be dropped.
*
* @return void
*/
public function dropRememberToken()
{
$this->dropColumn('remember_token');
}
/**
* Rename the table to a given name.
*
* @param string $to
* @return \Illuminate\Support\Fluent
*/
public function rename($to)
{
return $this->addCommand('rename', compact('to'));
}
/**
* Specify the primary key(s) for the table.
*
* @param string|array $columns
* @param string $name
* @return \Illuminate\Support\Fluent
*/
public function primary($columns, $name = null)
{
return $this->indexCommand('primary', $columns, $name);
}
/**
* Specify a unique index for the table.
*
* @param string|array $columns
* @param string $name
* @return \Illuminate\Support\Fluent
*/
public function unique($columns, $name = null)
{
return $this->indexCommand('unique', $columns, $name);
}
/**
* Specify an index for the table.
*
* @param string|array $columns
* @param string $name
* @return \Illuminate\Support\Fluent
*/
public function index($columns, $name = null)
{
return $this->indexCommand('index', $columns, $name);
}
/**
* Specify a foreign key for the table.
*
* @param string|array $columns
* @param string $name
* @return \Illuminate\Support\Fluent
*/
public function foreign($columns, $name = null)
{
return $this->indexCommand('foreign', $columns, $name);
}
/**
* Create a new auto-incrementing integer (4-byte) column on the table.
*
* @param string $column
* @return \Illuminate\Support\Fluent
*/
public function increments($column)
{
return $this->unsignedInteger($column, true);
}
/**
* Create a new auto-incrementing small integer (2-byte) column on the table.
*
* @param string $column
* @return \Illuminate\Support\Fluent
*/
public function smallIncrements($column)
{
return $this->unsignedSmallInteger($column, true);
}
/**
* Create a new auto-incrementing medium integer (3-byte) column on the table.
*
* @param string $column
* @return \Illuminate\Support\Fluent
*/
public function mediumIncrements($column)
{
return $this->unsignedMediumInteger($column, true);
}
/**
* Create a new auto-incrementing big integer (8-byte) column on the table.
*
* @param string $column
* @return \Illuminate\Support\Fluent
*/
public function bigIncrements($column)
{
return $this->unsignedBigInteger($column, true);
}
/**
* Create a new char column on the table.
*
* @param string $column
* @param int $length
* @return \Illuminate\Support\Fluent
*/
public function char($column, $length = 255)
{
return $this->addColumn('char', $column, compact('length'));
}
/**
* Create a new string column on the table.
*
* @param string $column
* @param int $length
* @return \Illuminate\Support\Fluent
*/
public function string($column, $length = 255)
{
return $this->addColumn('string', $column, compact('length'));
}
/**
* Create a new text column on the table.
*
* @param string $column
* @return \Illuminate\Support\Fluent
*/
public function text($column)
{
return $this->addColumn('text', $column);
}
/**
* Create a new medium text column on the table.
*
* @param string $column
* @return \Illuminate\Support\Fluent
*/
public function mediumText($column)
{
return $this->addColumn('mediumText', $column);
}
/**
* Create a new long text column on the table.
*
* @param string $column
* @return \Illuminate\Support\Fluent
*/
public function longText($column)
{
return $this->addColumn('longText', $column);
}
/**
* Create a new integer (4-byte) column on the table.
*
* @param string $column
* @param bool $autoIncrement
* @param bool $unsigned
* @return \Illuminate\Support\Fluent
*/
public function integer($column, $autoIncrement = false, $unsigned = false)
{
return $this->addColumn('integer', $column, compact('autoIncrement', 'unsigned'));
}
/**
* Create a new tiny integer (1-byte) column on the table.
*
* @param string $column
* @param bool $autoIncrement
* @param bool $unsigned
* @return \Illuminate\Support\Fluent
*/
public function tinyInteger($column, $autoIncrement = false, $unsigned = false)
{
return $this->addColumn('tinyInteger', $column, compact('autoIncrement', 'unsigned'));
}
/**
* Create a new small integer (2-byte) column on the table.
*
* @param string $column
* @param bool $autoIncrement
* @param bool $unsigned
* @return \Illuminate\Support\Fluent
*/
public function smallInteger($column, $autoIncrement = false, $unsigned = false)
{
return $this->addColumn('smallInteger', $column, compact('autoIncrement', 'unsigned'));
}
/**
* Create a new medium integer (3-byte) column on the table.
*
* @param string $column
* @param bool $autoIncrement
* @param bool $unsigned
* @return \Illuminate\Support\Fluent
*/
public function mediumInteger($column, $autoIncrement = false, $unsigned = false)
{
return $this->addColumn('mediumInteger', $column, compact('autoIncrement', 'unsigned'));
}
/**
* Create a new big integer (8-byte) column on the table.
*
* @param string $column
* @param bool $autoIncrement
* @param bool $unsigned
* @return \Illuminate\Support\Fluent
*/
public function bigInteger($column, $autoIncrement = false, $unsigned = false)
{
return $this->addColumn('bigInteger', $column, compact('autoIncrement', 'unsigned'));
}
/**
* Create a new unsigned tiny integer (1-byte) column on the table.
*
* @param string $column
* @param bool $autoIncrement
* @return \Illuminate\Support\Fluent
*/
public function unsignedTinyInteger($column, $autoIncrement = false)
{
return $this->tinyInteger($column, $autoIncrement, true);
}
/**
* Create a new unsigned small integer (2-byte) column on the table.
*
* @param string $column
* @param bool $autoIncrement
* @return \Illuminate\Support\Fluent
*/
public function unsignedSmallInteger($column, $autoIncrement = false)
{
return $this->smallInteger($column, $autoIncrement, true);
}
/**
* Create a new unsigned medium integer (3-byte) column on the table.
*
* @param string $column
* @param bool $autoIncrement
* @return \Illuminate\Support\Fluent
*/
public function unsignedMediumInteger($column, $autoIncrement = false)
{
return $this->mediumInteger($column, $autoIncrement, true);
}
/**
* Create a new unsigned integer (4-byte) column on the table.
*
* @param string $column
* @param bool $autoIncrement
* @return \Illuminate\Support\Fluent
*/
public function unsignedInteger($column, $autoIncrement = false)
{
return $this->integer($column, $autoIncrement, true);
}
/**
* Create a new unsigned big integer (8-byte) column on the table.
*
* @param string $column
* @param bool $autoIncrement
* @return \Illuminate\Support\Fluent
*/
public function unsignedBigInteger($column, $autoIncrement = false)
{
return $this->bigInteger($column, $autoIncrement, true);
}
/**
* Create a new float column on the table.
*
* @param string $column
* @param int $total
* @param int $places
* @return \Illuminate\Support\Fluent
*/
public function float($column, $total = 8, $places = 2)
{
return $this->addColumn('float', $column, compact('total', 'places'));
}
/**
* Create a new double column on the table.
*
* @param string $column
* @param int|null $total
* @param int|null $places
* @return \Illuminate\Support\Fluent
*/
public function double($column, $total = null, $places = null)
{
return $this->addColumn('double', $column, compact('total', 'places'));
}
/**
* Create a new decimal column on the table.
*
* @param string $column
* @param int $total
* @param int $places
* @return \Illuminate\Support\Fluent
*/
public function decimal($column, $total = 8, $places = 2)
{
return $this->addColumn('decimal', $column, compact('total', 'places'));
}
/**
* Create a new boolean column on the table.
*
* @param string $column
* @return \Illuminate\Support\Fluent
*/
public function boolean($column)
{
return $this->addColumn('boolean', $column);
}
/**
* Create a new enum column on the table.
*
* @param string $column
* @param array $allowed
* @return \Illuminate\Support\Fluent
*/
public function enum($column, array $allowed)
{
return $this->addColumn('enum', $column, compact('allowed'));
}
/**
* Create a new json column on the table.
*
* @param string $column
* @return \Illuminate\Support\Fluent
*/
public function json($column)
{
return $this->addColumn('json', $column);
}
/**
* Create a new jsonb column on the table.
*
* @param string $column
* @return \Illuminate\Support\Fluent
*/
public function jsonb($column)
{
return $this->addColumn('jsonb', $column);
}
/**
* Create a new date column on the table.
*
* @param string $column
* @return \Illuminate\Support\Fluent
*/
public function date($column)
{
return $this->addColumn('date', $column);
}
/**
* Create a new date-time column on the table.
*
* @param string $column
* @return \Illuminate\Support\Fluent
*/
public function dateTime($column)
{
return $this->addColumn('dateTime', $column);
}
/**
* Create a new date-time column (with time zone) on the table.
*
* @param string $column
* @return \Illuminate\Support\Fluent
*/
public function dateTimeTz($column)
{
return $this->addColumn('dateTimeTz', $column);
}
/**
* Create a new time column on the table.
*
* @param string $column
* @return \Illuminate\Support\Fluent
*/
public function time($column)
{
return $this->addColumn('time', $column);
}
/**
* Create a new time column (with time zone) on the table.
*
* @param string $column
* @return \Illuminate\Support\Fluent
*/
public function timeTz($column)
{
return $this->addColumn('timeTz', $column);
}
/**
* Create a new timestamp column on the table.
*
* @param string $column
* @return \Illuminate\Support\Fluent
*/
public function timestamp($column)
{
return $this->addColumn('timestamp', $column);
}
/**
* Create a new timestamp (with time zone) column on the table.
*
* @param string $column
* @return \Illuminate\Support\Fluent
*/
public function timestampTz($column)
{
return $this->addColumn('timestampTz', $column);
}
/**
* Add nullable creation and update timestamps to the table.
*
* Alias for self::timestamps().
*
* @return void
*/
public function nullableTimestamps()
{
$this->timestamps();
}
/**
* Add nullable creation and update timestamps to the table.
*
* @return void
*/
public function timestamps()
{
$this->timestamp('created_at')->nullable();
$this->timestamp('updated_at')->nullable();
}
/**
* Add creation and update timestampTz columns to the table.
*
* @return void
*/
public function timestampsTz()
{
$this->timestampTz('created_at')->nullable();
$this->timestampTz('updated_at')->nullable();
}
/**
* Add a "deleted at" timestamp for the table.
*
* @return \Illuminate\Support\Fluent
*/
public function softDeletes()
{
return $this->timestamp('deleted_at')->nullable();
}
/**
* Create a new binary column on the table.
*
* @param string $column
* @return \Illuminate\Support\Fluent
*/
public function binary($column)
{
return $this->addColumn('binary', $column);
}
/**
* Create a new uuid column on the table.
*
* @param string $column
* @return \Illuminate\Support\Fluent
*/
public function uuid($column)
{
return $this->addColumn('uuid', $column);
}
/**
* Create a new IP address column on the table.
*
* @param string $column
* @return \Illuminate\Support\Fluent
*/
public function ipAddress($column)
{
return $this->addColumn('ipAddress', $column);
}
/**
* Create a new MAC address column on the table.
*
* @param string $column
* @return \Illuminate\Support\Fluent
*/
public function macAddress($column)
{
return $this->addColumn('macAddress', $column);
}
/**
* Add the proper columns for a polymorphic table.
*
* @param string $name
* @param string|null $indexName
* @return void
*/
public function morphs($name, $indexName = null)
{
$this->unsignedInteger("{$name}_id");
$this->string("{$name}_type");
$this->index(["{$name}_id", "{$name}_type"], $indexName);
}
/**
* Adds the `remember_token` column to the table.
*
* @return \Illuminate\Support\Fluent
*/
public function rememberToken()
{
return $this->string('remember_token', 100)->nullable();
}
/**
* Create a new drop index command on the blueprint.
*
* @param string $command
* @param string $type
* @param string|array $index
* @return \Illuminate\Support\Fluent
*/
protected function dropIndexCommand($command, $type, $index)
{
$columns = [];
// If the given "index" is actually an array of columns, the developer means
// to drop an index merely by specifying the columns involved without the
// conventional name, so we will build the index name from the columns.
if (is_array($index)) {
$columns = $index;
$index = $this->createIndexName($type, $columns);
}
return $this->indexCommand($command, $columns, $index);
}
/**
* Add a new index command to the blueprint.
*
* @param string $type
* @param string|array $columns
* @param string $index
* @return \Illuminate\Support\Fluent
*/
protected function indexCommand($type, $columns, $index)
{
$columns = (array) $columns;
// If no name was specified for this index, we will create one using a basic
// convention of the table name, followed by the columns, followed by an
// index type, such as primary or index, which makes the index unique.
if (is_null($index)) {
$index = $this->createIndexName($type, $columns);
}
return $this->addCommand($type, compact('index', 'columns'));
}
/**
* Create a default index name for the table.
*
* @param string $type
* @param array $columns
* @return string
*/
protected function createIndexName($type, array $columns)
{
$index = strtolower($this->table.'_'.implode('_', $columns).'_'.$type);
return str_replace(['-', '.'], '_', $index);
}
/**
* Add a new column to the blueprint.
*
* @param string $type
* @param string $name
* @param array $parameters
* @return \Illuminate\Support\Fluent
*/
public function addColumn($type, $name, array $parameters = [])
{
$attributes = array_merge(compact('type', 'name'), $parameters);
$this->columns[] = $column = new Fluent($attributes);
return $column;
}
/**
* Remove a column from the schema blueprint.
*
* @param string $name
* @return $this
*/
public function removeColumn($name)
{
$this->columns = array_values(array_filter($this->columns, function ($c) use ($name) {
return $c['attributes']['name'] != $name;
}));
return $this;
}
/**
* Add a new command to the blueprint.
*
* @param string $name
* @param array $parameters
* @return \Illuminate\Support\Fluent
*/
protected function addCommand($name, array $parameters = [])
{
$this->commands[] = $command = $this->createCommand($name, $parameters);
return $command;
}
/**
* Create a new Fluent command.
*
* @param string $name
* @param array $parameters
* @return \Illuminate\Support\Fluent
*/
protected function createCommand($name, array $parameters = [])
{
return new Fluent(array_merge(compact('name'), $parameters));
}
/**
* Get the table the blueprint describes.
*
* @return string
*/
public function getTable()
{
return $this->table;
}
/**
* Get the columns on the blueprint.
*
* @return array
*/
public function getColumns()
{
return $this->columns;
}
/**
* Get the commands on the blueprint.
*
* @return array
*/
public function getCommands()
{
return $this->commands;
}
/**
* Get the columns on the blueprint that should be added.
*
* @return array
*/
public function getAddedColumns()
{
return array_filter($this->columns, function ($column) {
return ! $column->change;
});
}
/**
* Get the columns on the blueprint that should be changed.
*
* @return array
*/
public function getChangedColumns()
{
return array_filter($this->columns, function ($column) {
return (bool) $column->change;
});
}
}
Schema/PostgresBuilder.php 0000666 00000000773 13436755161 0011620 0 ustar 00 grammar->compileTableExists();
$schema = $this->connection->getConfig('schema');
$table = $this->connection->getTablePrefix().$table;
return count($this->connection->select($sql, [$schema, $table])) > 0;
}
}
Schema/Builder.php 0000666 00000014544 13436755161 0010072 0 ustar 00 connection = $connection;
$this->grammar = $connection->getSchemaGrammar();
}
/**
* Determine if the given table exists.
*
* @param string $table
* @return bool
*/
public function hasTable($table)
{
$sql = $this->grammar->compileTableExists();
$table = $this->connection->getTablePrefix().$table;
return count($this->connection->select($sql, [$table])) > 0;
}
/**
* Determine if the given table has a given column.
*
* @param string $table
* @param string $column
* @return bool
*/
public function hasColumn($table, $column)
{
$column = strtolower($column);
return in_array($column, array_map('strtolower', $this->getColumnListing($table)));
}
/**
* Determine if the given table has given columns.
*
* @param string $table
* @param array $columns
* @return bool
*/
public function hasColumns($table, array $columns)
{
$tableColumns = array_map('strtolower', $this->getColumnListing($table));
foreach ($columns as $column) {
if (! in_array(strtolower($column), $tableColumns)) {
return false;
}
}
return true;
}
/**
* Get the data type for the given column name.
*
* @param string $table
* @param string $column
* @return string
*/
public function getColumnType($table, $column)
{
$table = $this->connection->getTablePrefix().$table;
return $this->connection->getDoctrineColumn($table, $column)->getType()->getName();
}
/**
* Get the column listing for a given table.
*
* @param string $table
* @return array
*/
public function getColumnListing($table)
{
$table = $this->connection->getTablePrefix().$table;
$results = $this->connection->select($this->grammar->compileColumnExists($table));
return $this->connection->getPostProcessor()->processColumnListing($results);
}
/**
* Modify a table on the schema.
*
* @param string $table
* @param \Closure $callback
* @return \Illuminate\Database\Schema\Blueprint
*/
public function table($table, Closure $callback)
{
$this->build($this->createBlueprint($table, $callback));
}
/**
* Create a new table on the schema.
*
* @param string $table
* @param \Closure $callback
* @return \Illuminate\Database\Schema\Blueprint
*/
public function create($table, Closure $callback)
{
$blueprint = $this->createBlueprint($table);
$blueprint->create();
$callback($blueprint);
$this->build($blueprint);
}
/**
* Drop a table from the schema.
*
* @param string $table
* @return \Illuminate\Database\Schema\Blueprint
*/
public function drop($table)
{
$blueprint = $this->createBlueprint($table);
$blueprint->drop();
$this->build($blueprint);
}
/**
* Drop a table from the schema if it exists.
*
* @param string $table
* @return \Illuminate\Database\Schema\Blueprint
*/
public function dropIfExists($table)
{
$blueprint = $this->createBlueprint($table);
$blueprint->dropIfExists();
$this->build($blueprint);
}
/**
* Rename a table on the schema.
*
* @param string $from
* @param string $to
* @return \Illuminate\Database\Schema\Blueprint
*/
public function rename($from, $to)
{
$blueprint = $this->createBlueprint($from);
$blueprint->rename($to);
$this->build($blueprint);
}
/**
* Enable foreign key constraints.
*
* @return bool
*/
public function enableForeignKeyConstraints()
{
return $this->connection->statement(
$this->grammar->compileEnableForeignKeyConstraints()
);
}
/**
* Disable foreign key constraints.
*
* @return bool
*/
public function disableForeignKeyConstraints()
{
return $this->connection->statement(
$this->grammar->compileDisableForeignKeyConstraints()
);
}
/**
* Execute the blueprint to build / modify the table.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @return void
*/
protected function build(Blueprint $blueprint)
{
$blueprint->build($this->connection, $this->grammar);
}
/**
* Create a new command set with a Closure.
*
* @param string $table
* @param \Closure|null $callback
* @return \Illuminate\Database\Schema\Blueprint
*/
protected function createBlueprint($table, Closure $callback = null)
{
if (isset($this->resolver)) {
return call_user_func($this->resolver, $table, $callback);
}
return new Blueprint($table, $callback);
}
/**
* Get the database connection instance.
*
* @return \Illuminate\Database\Connection
*/
public function getConnection()
{
return $this->connection;
}
/**
* Set the database connection instance.
*
* @param \Illuminate\Database\Connection $connection
* @return $this
*/
public function setConnection(Connection $connection)
{
$this->connection = $connection;
return $this;
}
/**
* Set the Schema Blueprint resolver callback.
*
* @param \Closure $resolver
* @return void
*/
public function blueprintResolver(Closure $resolver)
{
$this->resolver = $resolver;
}
}
Schema/MySqlBuilder.php 0000666 00000001777 13436755161 0011064 0 ustar 00 grammar->compileTableExists();
$database = $this->connection->getDatabaseName();
$table = $this->connection->getTablePrefix().$table;
return count($this->connection->select($sql, [$database, $table])) > 0;
}
/**
* Get the column listing for a given table.
*
* @param string $table
* @return array
*/
public function getColumnListing($table)
{
$sql = $this->grammar->compileColumnExists();
$database = $this->connection->getDatabaseName();
$table = $this->connection->getTablePrefix().$table;
$results = $this->connection->select($sql, [$database, $table]);
return $this->connection->getPostProcessor()->processColumnListing($results);
}
}
Schema/Grammars/SQLiteGrammar.php 0000666 00000042137 13436755161 0012724 0 ustar 00 getColumns($blueprint));
$sql = $blueprint->temporary ? 'create temporary' : 'create';
$sql .= ' table '.$this->wrapTable($blueprint)." ($columns";
// SQLite forces primary keys to be added when the table is initially created
// so we will need to check for a primary key commands and add the columns
// to the table's declaration here so they can be created on the tables.
$sql .= (string) $this->addForeignKeys($blueprint);
$sql .= (string) $this->addPrimaryKeys($blueprint);
return $sql.')';
}
/**
* Get the foreign key syntax for a table creation statement.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @return string|null
*/
protected function addForeignKeys(Blueprint $blueprint)
{
$sql = '';
$foreigns = $this->getCommandsByName($blueprint, 'foreign');
// Once we have all the foreign key commands for the table creation statement
// we'll loop through each of them and add them to the create table SQL we
// are building, since SQLite needs foreign keys on the tables creation.
foreach ($foreigns as $foreign) {
$sql .= $this->getForeignKey($foreign);
if (! is_null($foreign->onDelete)) {
$sql .= " on delete {$foreign->onDelete}";
}
if (! is_null($foreign->onUpdate)) {
$sql .= " on update {$foreign->onUpdate}";
}
}
return $sql;
}
/**
* Get the SQL for the foreign key.
*
* @param \Illuminate\Support\Fluent $foreign
* @return string
*/
protected function getForeignKey($foreign)
{
$on = $this->wrapTable($foreign->on);
// We need to columnize the columns that the foreign key is being defined for
// so that it is a properly formatted list. Once we have done this, we can
// return the foreign key SQL declaration to the calling method for use.
$columns = $this->columnize($foreign->columns);
$onColumns = $this->columnize((array) $foreign->references);
return ", foreign key($columns) references $on($onColumns)";
}
/**
* Get the primary key syntax for a table creation statement.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @return string|null
*/
protected function addPrimaryKeys(Blueprint $blueprint)
{
$primary = $this->getCommandByName($blueprint, 'primary');
if (! is_null($primary)) {
$columns = $this->columnize($primary->columns);
return ", primary key ({$columns})";
}
}
/**
* Compile alter table commands for adding columns.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @return array
*/
public function compileAdd(Blueprint $blueprint, Fluent $command)
{
$table = $this->wrapTable($blueprint);
$columns = $this->prefixArray('add column', $this->getColumns($blueprint));
$statements = [];
foreach ($columns as $column) {
$statements[] = 'alter table '.$table.' '.$column;
}
return $statements;
}
/**
* Compile a unique key command.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @return string
*/
public function compileUnique(Blueprint $blueprint, Fluent $command)
{
$columns = $this->columnize($command->columns);
$table = $this->wrapTable($blueprint);
$index = $this->wrap($command->index);
return "create unique index {$index} on {$table} ({$columns})";
}
/**
* Compile a plain index key command.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @return string
*/
public function compileIndex(Blueprint $blueprint, Fluent $command)
{
$columns = $this->columnize($command->columns);
$table = $this->wrapTable($blueprint);
$index = $this->wrap($command->index);
return "create index {$index} on {$table} ({$columns})";
}
/**
* Compile a foreign key command.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @return string
*/
public function compileForeign(Blueprint $blueprint, Fluent $command)
{
// Handled on table creation...
}
/**
* Compile a drop table command.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @return string
*/
public function compileDrop(Blueprint $blueprint, Fluent $command)
{
return 'drop table '.$this->wrapTable($blueprint);
}
/**
* Compile a drop table (if exists) command.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @return string
*/
public function compileDropIfExists(Blueprint $blueprint, Fluent $command)
{
return 'drop table if exists '.$this->wrapTable($blueprint);
}
/**
* Compile a drop column command.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @param \Illuminate\Database\Connection $connection
* @return array
*/
public function compileDropColumn(Blueprint $blueprint, Fluent $command, Connection $connection)
{
$schema = $connection->getDoctrineSchemaManager();
$tableDiff = $this->getDoctrineTableDiff($blueprint, $schema);
foreach ($command->columns as $name) {
$column = $connection->getDoctrineColumn($blueprint->getTable(), $name);
$tableDiff->removedColumns[$name] = $column;
}
return (array) $schema->getDatabasePlatform()->getAlterTableSQL($tableDiff);
}
/**
* Compile a drop unique key command.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @return string
*/
public function compileDropUnique(Blueprint $blueprint, Fluent $command)
{
$index = $this->wrap($command->index);
return "drop index {$index}";
}
/**
* Compile a drop index command.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @return string
*/
public function compileDropIndex(Blueprint $blueprint, Fluent $command)
{
$index = $this->wrap($command->index);
return "drop index {$index}";
}
/**
* Compile a rename table command.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @return string
*/
public function compileRename(Blueprint $blueprint, Fluent $command)
{
$from = $this->wrapTable($blueprint);
return "alter table {$from} rename to ".$this->wrapTable($command->to);
}
/**
* Compile the command to enable foreign key constraints.
*
* @return string
*/
public function compileEnableForeignKeyConstraints()
{
return 'PRAGMA foreign_keys = ON;';
}
/**
* Compile the command to disable foreign key constraints.
*
* @return string
*/
public function compileDisableForeignKeyConstraints()
{
return 'PRAGMA foreign_keys = OFF;';
}
/**
* Create the column definition for a char type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeChar(Fluent $column)
{
return 'varchar';
}
/**
* Create the column definition for a string type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeString(Fluent $column)
{
return 'varchar';
}
/**
* Create the column definition for a text type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeText(Fluent $column)
{
return 'text';
}
/**
* Create the column definition for a medium text type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeMediumText(Fluent $column)
{
return 'text';
}
/**
* Create the column definition for a long text type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeLongText(Fluent $column)
{
return 'text';
}
/**
* Create the column definition for a integer type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeInteger(Fluent $column)
{
return 'integer';
}
/**
* Create the column definition for a big integer type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeBigInteger(Fluent $column)
{
return 'integer';
}
/**
* Create the column definition for a medium integer type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeMediumInteger(Fluent $column)
{
return 'integer';
}
/**
* Create the column definition for a tiny integer type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeTinyInteger(Fluent $column)
{
return 'integer';
}
/**
* Create the column definition for a small integer type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeSmallInteger(Fluent $column)
{
return 'integer';
}
/**
* Create the column definition for a float type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeFloat(Fluent $column)
{
return 'float';
}
/**
* Create the column definition for a double type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeDouble(Fluent $column)
{
return 'float';
}
/**
* Create the column definition for a decimal type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeDecimal(Fluent $column)
{
return 'numeric';
}
/**
* Create the column definition for a boolean type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeBoolean(Fluent $column)
{
return 'tinyint(1)';
}
/**
* Create the column definition for an enum type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeEnum(Fluent $column)
{
return 'varchar';
}
/**
* Create the column definition for a json type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeJson(Fluent $column)
{
return 'text';
}
/**
* Create the column definition for a jsonb type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeJsonb(Fluent $column)
{
return 'text';
}
/**
* Create the column definition for a date type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeDate(Fluent $column)
{
return 'date';
}
/**
* Create the column definition for a date-time type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeDateTime(Fluent $column)
{
return 'datetime';
}
/**
* Create the column definition for a date-time type.
*
* Note: "SQLite does not have a storage class set aside for storing dates and/or times."
* @link https://www.sqlite.org/datatype3.html
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeDateTimeTz(Fluent $column)
{
return 'datetime';
}
/**
* Create the column definition for a time type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeTime(Fluent $column)
{
return 'time';
}
/**
* Create the column definition for a time type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeTimeTz(Fluent $column)
{
return 'time';
}
/**
* Create the column definition for a timestamp type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeTimestamp(Fluent $column)
{
if ($column->useCurrent) {
return 'datetime default CURRENT_TIMESTAMP';
}
return 'datetime';
}
/**
* Create the column definition for a timestamp type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeTimestampTz(Fluent $column)
{
if ($column->useCurrent) {
return 'datetime default CURRENT_TIMESTAMP';
}
return 'datetime';
}
/**
* Create the column definition for a binary type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeBinary(Fluent $column)
{
return 'blob';
}
/**
* Create the column definition for a uuid type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeUuid(Fluent $column)
{
return 'varchar';
}
/**
* Create the column definition for an IP address type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeIpAddress(Fluent $column)
{
return 'varchar';
}
/**
* Create the column definition for a MAC address type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeMacAddress(Fluent $column)
{
return 'varchar';
}
/**
* Get the SQL for a nullable column modifier.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $column
* @return string|null
*/
protected function modifyNullable(Blueprint $blueprint, Fluent $column)
{
return $column->nullable ? ' null' : ' not null';
}
/**
* Get the SQL for a default column modifier.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $column
* @return string|null
*/
protected function modifyDefault(Blueprint $blueprint, Fluent $column)
{
if (! is_null($column->default)) {
return ' default '.$this->getDefaultValue($column->default);
}
}
/**
* Get the SQL for an auto-increment column modifier.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $column
* @return string|null
*/
protected function modifyIncrement(Blueprint $blueprint, Fluent $column)
{
if (in_array($column->type, $this->serials) && $column->autoIncrement) {
return ' primary key autoincrement';
}
}
}
Schema/Grammars/MySqlGrammar.php 0000666 00000051254 13436755161 0012630 0 ustar 00 getColumns($blueprint));
$sql = $blueprint->temporary ? 'create temporary' : 'create';
$sql .= ' table '.$this->wrapTable($blueprint)." ($columns)";
// Once we have the primary SQL, we can add the encoding option to the SQL for
// the table. Then, we can check if a storage engine has been supplied for
// the table. If so, we will add the engine declaration to the SQL query.
$sql = $this->compileCreateEncoding($sql, $connection, $blueprint);
if (isset($blueprint->engine)) {
$sql .= ' engine = '.$blueprint->engine;
} elseif (! is_null($engine = $connection->getConfig('engine'))) {
$sql .= ' engine = '.$engine;
}
return $sql;
}
/**
* Append the character set specifications to a command.
*
* @param string $sql
* @param \Illuminate\Database\Connection $connection
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @return string
*/
protected function compileCreateEncoding($sql, Connection $connection, Blueprint $blueprint)
{
if (isset($blueprint->charset)) {
$sql .= ' default character set '.$blueprint->charset;
} elseif (! is_null($charset = $connection->getConfig('charset'))) {
$sql .= ' default character set '.$charset;
}
if (isset($blueprint->collation)) {
$sql .= ' collate '.$blueprint->collation;
} elseif (! is_null($collation = $connection->getConfig('collation'))) {
$sql .= ' collate '.$collation;
}
return $sql;
}
/**
* Compile an add column command.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @return string
*/
public function compileAdd(Blueprint $blueprint, Fluent $command)
{
$table = $this->wrapTable($blueprint);
$columns = $this->prefixArray('add', $this->getColumns($blueprint));
return 'alter table '.$table.' '.implode(', ', $columns);
}
/**
* Compile a primary key command.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @return string
*/
public function compilePrimary(Blueprint $blueprint, Fluent $command)
{
$command->name(null);
return $this->compileKey($blueprint, $command, 'primary key');
}
/**
* Compile a unique key command.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @return string
*/
public function compileUnique(Blueprint $blueprint, Fluent $command)
{
return $this->compileKey($blueprint, $command, 'unique');
}
/**
* Compile a plain index key command.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @return string
*/
public function compileIndex(Blueprint $blueprint, Fluent $command)
{
return $this->compileKey($blueprint, $command, 'index');
}
/**
* Compile an index creation command.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @param string $type
* @return string
*/
protected function compileKey(Blueprint $blueprint, Fluent $command, $type)
{
$columns = $this->columnize($command->columns);
$table = $this->wrapTable($blueprint);
$index = $this->wrap($command->index);
return "alter table {$table} add {$type} {$index}($columns)";
}
/**
* Compile a drop table command.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @return string
*/
public function compileDrop(Blueprint $blueprint, Fluent $command)
{
return 'drop table '.$this->wrapTable($blueprint);
}
/**
* Compile a drop table (if exists) command.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @return string
*/
public function compileDropIfExists(Blueprint $blueprint, Fluent $command)
{
return 'drop table if exists '.$this->wrapTable($blueprint);
}
/**
* Compile a drop column command.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @return string
*/
public function compileDropColumn(Blueprint $blueprint, Fluent $command)
{
$columns = $this->prefixArray('drop', $this->wrapArray($command->columns));
$table = $this->wrapTable($blueprint);
return 'alter table '.$table.' '.implode(', ', $columns);
}
/**
* Compile a drop primary key command.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @return string
*/
public function compileDropPrimary(Blueprint $blueprint, Fluent $command)
{
return 'alter table '.$this->wrapTable($blueprint).' drop primary key';
}
/**
* Compile a drop unique key command.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @return string
*/
public function compileDropUnique(Blueprint $blueprint, Fluent $command)
{
$table = $this->wrapTable($blueprint);
$index = $this->wrap($command->index);
return "alter table {$table} drop index {$index}";
}
/**
* Compile a drop index command.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @return string
*/
public function compileDropIndex(Blueprint $blueprint, Fluent $command)
{
$table = $this->wrapTable($blueprint);
$index = $this->wrap($command->index);
return "alter table {$table} drop index {$index}";
}
/**
* Compile a drop foreign key command.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @return string
*/
public function compileDropForeign(Blueprint $blueprint, Fluent $command)
{
$table = $this->wrapTable($blueprint);
$index = $this->wrap($command->index);
return "alter table {$table} drop foreign key {$index}";
}
/**
* Compile a rename table command.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @return string
*/
public function compileRename(Blueprint $blueprint, Fluent $command)
{
$from = $this->wrapTable($blueprint);
return "rename table {$from} to ".$this->wrapTable($command->to);
}
/**
* Compile the command to enable foreign key constraints.
*
* @return string
*/
public function compileEnableForeignKeyConstraints()
{
return 'SET FOREIGN_KEY_CHECKS=1;';
}
/**
* Compile the command to disable foreign key constraints.
*
* @return string
*/
public function compileDisableForeignKeyConstraints()
{
return 'SET FOREIGN_KEY_CHECKS=0;';
}
/**
* Create the column definition for a char type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeChar(Fluent $column)
{
return "char({$column->length})";
}
/**
* Create the column definition for a string type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeString(Fluent $column)
{
return "varchar({$column->length})";
}
/**
* Create the column definition for a text type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeText(Fluent $column)
{
return 'text';
}
/**
* Create the column definition for a medium text type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeMediumText(Fluent $column)
{
return 'mediumtext';
}
/**
* Create the column definition for a long text type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeLongText(Fluent $column)
{
return 'longtext';
}
/**
* Create the column definition for a big integer type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeBigInteger(Fluent $column)
{
return 'bigint';
}
/**
* Create the column definition for a integer type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeInteger(Fluent $column)
{
return 'int';
}
/**
* Create the column definition for a medium integer type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeMediumInteger(Fluent $column)
{
return 'mediumint';
}
/**
* Create the column definition for a tiny integer type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeTinyInteger(Fluent $column)
{
return 'tinyint';
}
/**
* Create the column definition for a small integer type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeSmallInteger(Fluent $column)
{
return 'smallint';
}
/**
* Create the column definition for a float type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeFloat(Fluent $column)
{
return $this->typeDouble($column);
}
/**
* Create the column definition for a double type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeDouble(Fluent $column)
{
if ($column->total && $column->places) {
return "double({$column->total}, {$column->places})";
}
return 'double';
}
/**
* Create the column definition for a decimal type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeDecimal(Fluent $column)
{
return "decimal({$column->total}, {$column->places})";
}
/**
* Create the column definition for a boolean type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeBoolean(Fluent $column)
{
return 'tinyint(1)';
}
/**
* Create the column definition for an enum type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeEnum(Fluent $column)
{
return "enum('".implode("', '", $column->allowed)."')";
}
/**
* Create the column definition for a json type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeJson(Fluent $column)
{
return 'json';
}
/**
* Create the column definition for a jsonb type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeJsonb(Fluent $column)
{
return 'json';
}
/**
* Create the column definition for a date type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeDate(Fluent $column)
{
return 'date';
}
/**
* Create the column definition for a date-time type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeDateTime(Fluent $column)
{
return 'datetime';
}
/**
* Create the column definition for a date-time type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeDateTimeTz(Fluent $column)
{
return 'datetime';
}
/**
* Create the column definition for a time type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeTime(Fluent $column)
{
return 'time';
}
/**
* Create the column definition for a time type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeTimeTz(Fluent $column)
{
return 'time';
}
/**
* Create the column definition for a timestamp type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeTimestamp(Fluent $column)
{
if ($column->useCurrent) {
return 'timestamp default CURRENT_TIMESTAMP';
}
return 'timestamp';
}
/**
* Create the column definition for a timestamp type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeTimestampTz(Fluent $column)
{
if ($column->useCurrent) {
return 'timestamp default CURRENT_TIMESTAMP';
}
return 'timestamp';
}
/**
* Create the column definition for a binary type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeBinary(Fluent $column)
{
return 'blob';
}
/**
* Create the column definition for a uuid type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeUuid(Fluent $column)
{
return 'char(36)';
}
/**
* Create the column definition for an IP address type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeIpAddress(Fluent $column)
{
return 'varchar(45)';
}
/**
* Create the column definition for a MAC address type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeMacAddress(Fluent $column)
{
return 'varchar(17)';
}
/**
* Get the SQL for a generated virtual column modifier.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $column
* @return string|null
*/
protected function modifyVirtualAs(Blueprint $blueprint, Fluent $column)
{
if (! is_null($column->virtualAs)) {
return " as ({$column->virtualAs})";
}
}
/**
* Get the SQL for a generated stored column modifier.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $column
* @return string|null
*/
protected function modifyStoredAs(Blueprint $blueprint, Fluent $column)
{
if (! is_null($column->storedAs)) {
return " as ({$column->storedAs}) stored";
}
}
/**
* Get the SQL for an unsigned column modifier.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $column
* @return string|null
*/
protected function modifyUnsigned(Blueprint $blueprint, Fluent $column)
{
if ($column->unsigned) {
return ' unsigned';
}
}
/**
* Get the SQL for a character set column modifier.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $column
* @return string|null
*/
protected function modifyCharset(Blueprint $blueprint, Fluent $column)
{
if (! is_null($column->charset)) {
return ' character set '.$column->charset;
}
}
/**
* Get the SQL for a collation column modifier.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $column
* @return string|null
*/
protected function modifyCollate(Blueprint $blueprint, Fluent $column)
{
if (! is_null($column->collation)) {
return ' collate '.$column->collation;
}
}
/**
* Get the SQL for a nullable column modifier.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $column
* @return string|null
*/
protected function modifyNullable(Blueprint $blueprint, Fluent $column)
{
return $column->nullable ? ' null' : ' not null';
}
/**
* Get the SQL for a default column modifier.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $column
* @return string|null
*/
protected function modifyDefault(Blueprint $blueprint, Fluent $column)
{
if (! is_null($column->default)) {
return ' default '.$this->getDefaultValue($column->default);
}
}
/**
* Get the SQL for an auto-increment column modifier.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $column
* @return string|null
*/
protected function modifyIncrement(Blueprint $blueprint, Fluent $column)
{
if (in_array($column->type, $this->serials) && $column->autoIncrement) {
return ' auto_increment primary key';
}
}
/**
* Get the SQL for a "first" column modifier.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $column
* @return string|null
*/
protected function modifyFirst(Blueprint $blueprint, Fluent $column)
{
if (! is_null($column->first)) {
return ' first';
}
}
/**
* Get the SQL for an "after" column modifier.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $column
* @return string|null
*/
protected function modifyAfter(Blueprint $blueprint, Fluent $column)
{
if (! is_null($column->after)) {
return ' after '.$this->wrap($column->after);
}
}
/**
* Get the SQL for a "comment" column modifier.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $column
* @return string|null
*/
protected function modifyComment(Blueprint $blueprint, Fluent $column)
{
if (! is_null($column->comment)) {
return ' comment "'.$column->comment.'"';
}
}
/**
* Wrap a single string in keyword identifiers.
*
* @param string $value
* @return string
*/
protected function wrapValue($value)
{
if ($value === '*') {
return $value;
}
return '`'.str_replace('`', '``', $value).'`';
}
}
Schema/Grammars/PostgresGrammar.php 0000666 00000037443 13436755161 0013375 0 ustar 00 getColumns($blueprint));
$sql = $blueprint->temporary ? 'create temporary' : 'create';
$sql .= ' table '.$this->wrapTable($blueprint)." ($columns)";
return $sql;
}
/**
* Compile a column addition command.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @return string
*/
public function compileAdd(Blueprint $blueprint, Fluent $command)
{
$table = $this->wrapTable($blueprint);
$columns = $this->prefixArray('add column', $this->getColumns($blueprint));
return 'alter table '.$table.' '.implode(', ', $columns);
}
/**
* Compile a primary key command.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @return string
*/
public function compilePrimary(Blueprint $blueprint, Fluent $command)
{
$columns = $this->columnize($command->columns);
return 'alter table '.$this->wrapTable($blueprint)." add primary key ({$columns})";
}
/**
* Compile a unique key command.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @return string
*/
public function compileUnique(Blueprint $blueprint, Fluent $command)
{
$table = $this->wrapTable($blueprint);
$index = $this->wrap($command->index);
$columns = $this->columnize($command->columns);
return "alter table $table add constraint {$index} unique ($columns)";
}
/**
* Compile a plain index key command.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @return string
*/
public function compileIndex(Blueprint $blueprint, Fluent $command)
{
$columns = $this->columnize($command->columns);
$index = $this->wrap($command->index);
return "create index {$index} on ".$this->wrapTable($blueprint)." ({$columns})";
}
/**
* Compile a drop table command.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @return string
*/
public function compileDrop(Blueprint $blueprint, Fluent $command)
{
return 'drop table '.$this->wrapTable($blueprint);
}
/**
* Compile a drop table (if exists) command.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @return string
*/
public function compileDropIfExists(Blueprint $blueprint, Fluent $command)
{
return 'drop table if exists '.$this->wrapTable($blueprint);
}
/**
* Compile a drop column command.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @return string
*/
public function compileDropColumn(Blueprint $blueprint, Fluent $command)
{
$columns = $this->prefixArray('drop column', $this->wrapArray($command->columns));
$table = $this->wrapTable($blueprint);
return 'alter table '.$table.' '.implode(', ', $columns);
}
/**
* Compile a drop primary key command.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @return string
*/
public function compileDropPrimary(Blueprint $blueprint, Fluent $command)
{
$table = $blueprint->getTable();
$index = $this->wrap("{$table}_pkey");
return 'alter table '.$this->wrapTable($blueprint)." drop constraint {$index}";
}
/**
* Compile a drop unique key command.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @return string
*/
public function compileDropUnique(Blueprint $blueprint, Fluent $command)
{
$table = $this->wrapTable($blueprint);
$index = $this->wrap($command->index);
return "alter table {$table} drop constraint {$index}";
}
/**
* Compile a drop index command.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @return string
*/
public function compileDropIndex(Blueprint $blueprint, Fluent $command)
{
$index = $this->wrap($command->index);
return "drop index {$index}";
}
/**
* Compile a drop foreign key command.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @return string
*/
public function compileDropForeign(Blueprint $blueprint, Fluent $command)
{
$table = $this->wrapTable($blueprint);
$index = $this->wrap($command->index);
return "alter table {$table} drop constraint {$index}";
}
/**
* Compile the command to enable foreign key constraints.
*
* @return string
*/
public function compileEnableForeignKeyConstraints()
{
return 'SET CONSTRAINTS ALL IMMEDIATE;';
}
/**
* Compile the command to disable foreign key constraints.
*
* @return string
*/
public function compileDisableForeignKeyConstraints()
{
return 'SET CONSTRAINTS ALL DEFERRED;';
}
/**
* Compile a rename table command.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @return string
*/
public function compileRename(Blueprint $blueprint, Fluent $command)
{
$from = $this->wrapTable($blueprint);
return "alter table {$from} rename to ".$this->wrapTable($command->to);
}
/**
* Create the column definition for a char type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeChar(Fluent $column)
{
return "char({$column->length})";
}
/**
* Create the column definition for a string type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeString(Fluent $column)
{
return "varchar({$column->length})";
}
/**
* Create the column definition for a text type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeText(Fluent $column)
{
return 'text';
}
/**
* Create the column definition for a medium text type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeMediumText(Fluent $column)
{
return 'text';
}
/**
* Create the column definition for a long text type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeLongText(Fluent $column)
{
return 'text';
}
/**
* Create the column definition for a integer type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeInteger(Fluent $column)
{
return $column->autoIncrement ? 'serial' : 'integer';
}
/**
* Create the column definition for a big integer type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeBigInteger(Fluent $column)
{
return $column->autoIncrement ? 'bigserial' : 'bigint';
}
/**
* Create the column definition for a medium integer type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeMediumInteger(Fluent $column)
{
return $column->autoIncrement ? 'serial' : 'integer';
}
/**
* Create the column definition for a tiny integer type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeTinyInteger(Fluent $column)
{
return $column->autoIncrement ? 'smallserial' : 'smallint';
}
/**
* Create the column definition for a small integer type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeSmallInteger(Fluent $column)
{
return $column->autoIncrement ? 'smallserial' : 'smallint';
}
/**
* Create the column definition for a float type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeFloat(Fluent $column)
{
return $this->typeDouble($column);
}
/**
* Create the column definition for a double type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeDouble(Fluent $column)
{
return 'double precision';
}
/**
* Create the column definition for a decimal type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeDecimal(Fluent $column)
{
return "decimal({$column->total}, {$column->places})";
}
/**
* Create the column definition for a boolean type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeBoolean(Fluent $column)
{
return 'boolean';
}
/**
* Create the column definition for an enum type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeEnum(Fluent $column)
{
$allowed = array_map(function ($a) {
return "'".$a."'";
}, $column->allowed);
return "varchar(255) check (\"{$column->name}\" in (".implode(', ', $allowed).'))';
}
/**
* Create the column definition for a json type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeJson(Fluent $column)
{
return 'json';
}
/**
* Create the column definition for a jsonb type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeJsonb(Fluent $column)
{
return 'jsonb';
}
/**
* Create the column definition for a date type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeDate(Fluent $column)
{
return 'date';
}
/**
* Create the column definition for a date-time type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeDateTime(Fluent $column)
{
return 'timestamp(0) without time zone';
}
/**
* Create the column definition for a date-time type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeDateTimeTz(Fluent $column)
{
return 'timestamp(0) with time zone';
}
/**
* Create the column definition for a time type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeTime(Fluent $column)
{
return 'time(0) without time zone';
}
/**
* Create the column definition for a time type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeTimeTz(Fluent $column)
{
return 'time(0) with time zone';
}
/**
* Create the column definition for a timestamp type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeTimestamp(Fluent $column)
{
if ($column->useCurrent) {
return 'timestamp(0) without time zone default CURRENT_TIMESTAMP(0)';
}
return 'timestamp(0) without time zone';
}
/**
* Create the column definition for a timestamp type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeTimestampTz(Fluent $column)
{
if ($column->useCurrent) {
return 'timestamp(0) with time zone default CURRENT_TIMESTAMP(0)';
}
return 'timestamp(0) with time zone';
}
/**
* Create the column definition for a binary type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeBinary(Fluent $column)
{
return 'bytea';
}
/**
* Create the column definition for a uuid type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeUuid(Fluent $column)
{
return 'uuid';
}
/**
* Create the column definition for an IP address type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeIpAddress(Fluent $column)
{
return 'inet';
}
/**
* Create the column definition for a MAC address type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeMacAddress(Fluent $column)
{
return 'macaddr';
}
/**
* Get the SQL for a nullable column modifier.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $column
* @return string|null
*/
protected function modifyNullable(Blueprint $blueprint, Fluent $column)
{
return $column->nullable ? ' null' : ' not null';
}
/**
* Get the SQL for a default column modifier.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $column
* @return string|null
*/
protected function modifyDefault(Blueprint $blueprint, Fluent $column)
{
if (! is_null($column->default)) {
return ' default '.$this->getDefaultValue($column->default);
}
}
/**
* Get the SQL for an auto-increment column modifier.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $column
* @return string|null
*/
protected function modifyIncrement(Blueprint $blueprint, Fluent $column)
{
if (in_array($column->type, $this->serials) && $column->autoIncrement) {
return ' primary key';
}
}
}
Schema/Grammars/SqlServerGrammar.php 0000666 00000037266 13436755161 0013520 0 ustar 00 getColumns($blueprint));
return 'create table '.$this->wrapTable($blueprint)." ($columns)";
}
/**
* Compile a column addition table command.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @return string
*/
public function compileAdd(Blueprint $blueprint, Fluent $command)
{
$table = $this->wrapTable($blueprint);
$columns = $this->getColumns($blueprint);
return 'alter table '.$table.' add '.implode(', ', $columns);
}
/**
* Compile a primary key command.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @return string
*/
public function compilePrimary(Blueprint $blueprint, Fluent $command)
{
$columns = $this->columnize($command->columns);
$table = $this->wrapTable($blueprint);
$index = $this->wrap($command->index);
return "alter table {$table} add constraint {$index} primary key ({$columns})";
}
/**
* Compile a unique key command.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @return string
*/
public function compileUnique(Blueprint $blueprint, Fluent $command)
{
$columns = $this->columnize($command->columns);
$table = $this->wrapTable($blueprint);
$index = $this->wrap($command->index);
return "create unique index {$index} on {$table} ({$columns})";
}
/**
* Compile a plain index key command.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @return string
*/
public function compileIndex(Blueprint $blueprint, Fluent $command)
{
$columns = $this->columnize($command->columns);
$table = $this->wrapTable($blueprint);
$index = $this->wrap($command->index);
return "create index {$index} on {$table} ({$columns})";
}
/**
* Compile a drop table command.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @return string
*/
public function compileDrop(Blueprint $blueprint, Fluent $command)
{
return 'drop table '.$this->wrapTable($blueprint);
}
/**
* Compile a drop table (if exists) command.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @return string
*/
public function compileDropIfExists(Blueprint $blueprint, Fluent $command)
{
return 'if exists (select * from INFORMATION_SCHEMA.TABLES where TABLE_NAME = \''.$blueprint->getTable().'\') drop table ['.$blueprint->getTable().']';
}
/**
* Compile a drop column command.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @return string
*/
public function compileDropColumn(Blueprint $blueprint, Fluent $command)
{
$columns = $this->wrapArray($command->columns);
$table = $this->wrapTable($blueprint);
return 'alter table '.$table.' drop column '.implode(', ', $columns);
}
/**
* Compile a drop primary key command.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @return string
*/
public function compileDropPrimary(Blueprint $blueprint, Fluent $command)
{
$table = $this->wrapTable($blueprint);
$index = $this->wrap($command->index);
return "alter table {$table} drop constraint {$index}";
}
/**
* Compile a drop unique key command.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @return string
*/
public function compileDropUnique(Blueprint $blueprint, Fluent $command)
{
$table = $this->wrapTable($blueprint);
$index = $this->wrap($command->index);
return "drop index {$index} on {$table}";
}
/**
* Compile a drop index command.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @return string
*/
public function compileDropIndex(Blueprint $blueprint, Fluent $command)
{
$table = $this->wrapTable($blueprint);
$index = $this->wrap($command->index);
return "drop index {$index} on {$table}";
}
/**
* Compile a drop foreign key command.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @return string
*/
public function compileDropForeign(Blueprint $blueprint, Fluent $command)
{
$table = $this->wrapTable($blueprint);
$index = $this->wrap($command->index);
return "alter table {$table} drop constraint {$index}";
}
/**
* Compile a rename table command.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @return string
*/
public function compileRename(Blueprint $blueprint, Fluent $command)
{
$from = $this->wrapTable($blueprint);
return "sp_rename {$from}, ".$this->wrapTable($command->to);
}
/**
* Compile the command to enable foreign key constraints.
*
* @return string
*/
public function compileEnableForeignKeyConstraints()
{
return 'EXEC sp_msforeachtable @command1="print \'?\'", @command2="ALTER TABLE ? WITH CHECK CHECK CONSTRAINT all";';
}
/**
* Compile the command to disable foreign key constraints.
*
* @return string
*/
public function compileDisableForeignKeyConstraints()
{
return 'EXEC sp_msforeachtable "ALTER TABLE ? NOCHECK CONSTRAINT all";';
}
/**
* Create the column definition for a char type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeChar(Fluent $column)
{
return "nchar({$column->length})";
}
/**
* Create the column definition for a string type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeString(Fluent $column)
{
return "nvarchar({$column->length})";
}
/**
* Create the column definition for a text type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeText(Fluent $column)
{
return 'nvarchar(max)';
}
/**
* Create the column definition for a medium text type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeMediumText(Fluent $column)
{
return 'nvarchar(max)';
}
/**
* Create the column definition for a long text type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeLongText(Fluent $column)
{
return 'nvarchar(max)';
}
/**
* Create the column definition for a integer type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeInteger(Fluent $column)
{
return 'int';
}
/**
* Create the column definition for a big integer type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeBigInteger(Fluent $column)
{
return 'bigint';
}
/**
* Create the column definition for a medium integer type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeMediumInteger(Fluent $column)
{
return 'int';
}
/**
* Create the column definition for a tiny integer type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeTinyInteger(Fluent $column)
{
return 'tinyint';
}
/**
* Create the column definition for a small integer type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeSmallInteger(Fluent $column)
{
return 'smallint';
}
/**
* Create the column definition for a float type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeFloat(Fluent $column)
{
return 'float';
}
/**
* Create the column definition for a double type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeDouble(Fluent $column)
{
return 'float';
}
/**
* Create the column definition for a decimal type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeDecimal(Fluent $column)
{
return "decimal({$column->total}, {$column->places})";
}
/**
* Create the column definition for a boolean type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeBoolean(Fluent $column)
{
return 'bit';
}
/**
* Create the column definition for an enum type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeEnum(Fluent $column)
{
return 'nvarchar(255)';
}
/**
* Create the column definition for a json type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeJson(Fluent $column)
{
return 'nvarchar(max)';
}
/**
* Create the column definition for a jsonb type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeJsonb(Fluent $column)
{
return 'nvarchar(max)';
}
/**
* Create the column definition for a date type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeDate(Fluent $column)
{
return 'date';
}
/**
* Create the column definition for a date-time type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeDateTime(Fluent $column)
{
return 'datetime';
}
/**
* Create the column definition for a date-time type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeDateTimeTz(Fluent $column)
{
return 'datetimeoffset(0)';
}
/**
* Create the column definition for a time type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeTime(Fluent $column)
{
return 'time';
}
/**
* Create the column definition for a time type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeTimeTz(Fluent $column)
{
return 'time';
}
/**
* Create the column definition for a timestamp type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeTimestamp(Fluent $column)
{
if ($column->useCurrent) {
return 'datetime default CURRENT_TIMESTAMP';
}
return 'datetime';
}
/**
* Create the column definition for a timestamp type.
*
* @link https://msdn.microsoft.com/en-us/library/bb630289(v=sql.120).aspx
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeTimestampTz(Fluent $column)
{
if ($column->useCurrent) {
return 'datetimeoffset(0) default CURRENT_TIMESTAMP';
}
return 'datetimeoffset(0)';
}
/**
* Create the column definition for a binary type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeBinary(Fluent $column)
{
return 'varbinary(max)';
}
/**
* Create the column definition for a uuid type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeUuid(Fluent $column)
{
return 'uniqueidentifier';
}
/**
* Create the column definition for an IP address type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeIpAddress(Fluent $column)
{
return 'nvarchar(45)';
}
/**
* Create the column definition for a MAC address type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeMacAddress(Fluent $column)
{
return 'nvarchar(17)';
}
/**
* Get the SQL for a nullable column modifier.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $column
* @return string|null
*/
protected function modifyNullable(Blueprint $blueprint, Fluent $column)
{
return $column->nullable ? ' null' : ' not null';
}
/**
* Get the SQL for a default column modifier.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $column
* @return string|null
*/
protected function modifyDefault(Blueprint $blueprint, Fluent $column)
{
if (! is_null($column->default)) {
return ' default '.$this->getDefaultValue($column->default);
}
}
/**
* Get the SQL for an auto-increment column modifier.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $column
* @return string|null
*/
protected function modifyIncrement(Blueprint $blueprint, Fluent $column)
{
if (in_array($column->type, $this->serials) && $column->autoIncrement) {
return ' identity primary key';
}
}
}
Schema/Grammars/Grammar.php 0000666 00000033347 13436755161 0011645 0 ustar 00 getDoctrineSchemaManager();
$table = $this->getTablePrefix().$blueprint->getTable();
$column = $connection->getDoctrineColumn($table, $command->from);
$tableDiff = $this->getRenamedDiff($blueprint, $command, $column, $schema);
return (array) $schema->getDatabasePlatform()->getAlterTableSQL($tableDiff);
}
/**
* Get a new column instance with the new column name.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @param \Doctrine\DBAL\Schema\Column $column
* @param \Doctrine\DBAL\Schema\AbstractSchemaManager $schema
* @return \Doctrine\DBAL\Schema\TableDiff
*/
protected function getRenamedDiff(Blueprint $blueprint, Fluent $command, Column $column, SchemaManager $schema)
{
$tableDiff = $this->getDoctrineTableDiff($blueprint, $schema);
return $this->setRenamedColumns($tableDiff, $command, $column);
}
/**
* Set the renamed columns on the table diff.
*
* @param \Doctrine\DBAL\Schema\TableDiff $tableDiff
* @param \Illuminate\Support\Fluent $command
* @param \Doctrine\DBAL\Schema\Column $column
* @return \Doctrine\DBAL\Schema\TableDiff
*/
protected function setRenamedColumns(TableDiff $tableDiff, Fluent $command, Column $column)
{
$newColumn = new Column($command->to, $column->getType(), $column->toArray());
$tableDiff->renamedColumns = [$command->from => $newColumn];
return $tableDiff;
}
/**
* Compile a foreign key command.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @return string
*/
public function compileForeign(Blueprint $blueprint, Fluent $command)
{
$table = $this->wrapTable($blueprint);
$index = $this->wrap($command->index);
$on = $this->wrapTable($command->on);
// We need to prepare several of the elements of the foreign key definition
// before we can create the SQL, such as wrapping the tables and convert
// an array of columns to comma-delimited strings for the SQL queries.
$columns = $this->columnize($command->columns);
$onColumns = $this->columnize((array) $command->references);
$sql = "alter table {$table} add constraint {$index} ";
$sql .= "foreign key ({$columns}) references {$on} ({$onColumns})";
// Once we have the basic foreign key creation statement constructed we can
// build out the syntax for what should happen on an update or delete of
// the affected columns, which will get something like "cascade", etc.
if (! is_null($command->onDelete)) {
$sql .= " on delete {$command->onDelete}";
}
if (! is_null($command->onUpdate)) {
$sql .= " on update {$command->onUpdate}";
}
return $sql;
}
/**
* Compile the blueprint's column definitions.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @return array
*/
protected function getColumns(Blueprint $blueprint)
{
$columns = [];
foreach ($blueprint->getAddedColumns() as $column) {
// Each of the column types have their own compiler functions which are tasked
// with turning the column definition into its SQL format for this platform
// used by the connection. The column's modifiers are compiled and added.
$sql = $this->wrap($column).' '.$this->getType($column);
$columns[] = $this->addModifiers($sql, $blueprint, $column);
}
return $columns;
}
/**
* Add the column modifiers to the definition.
*
* @param string $sql
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function addModifiers($sql, Blueprint $blueprint, Fluent $column)
{
foreach ($this->modifiers as $modifier) {
if (method_exists($this, $method = "modify{$modifier}")) {
$sql .= $this->{$method}($blueprint, $column);
}
}
return $sql;
}
/**
* Get the primary key command if it exists on the blueprint.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param string $name
* @return \Illuminate\Support\Fluent|null
*/
protected function getCommandByName(Blueprint $blueprint, $name)
{
$commands = $this->getCommandsByName($blueprint, $name);
if (count($commands) > 0) {
return reset($commands);
}
}
/**
* Get all of the commands with a given name.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param string $name
* @return array
*/
protected function getCommandsByName(Blueprint $blueprint, $name)
{
return array_filter($blueprint->getCommands(), function ($value) use ($name) {
return $value->name == $name;
});
}
/**
* Get the SQL for the column data type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function getType(Fluent $column)
{
return $this->{'type'.ucfirst($column->type)}($column);
}
/**
* Add a prefix to an array of values.
*
* @param string $prefix
* @param array $values
* @return array
*/
public function prefixArray($prefix, array $values)
{
return array_map(function ($value) use ($prefix) {
return $prefix.' '.$value;
}, $values);
}
/**
* Wrap a table in keyword identifiers.
*
* @param mixed $table
* @return string
*/
public function wrapTable($table)
{
if ($table instanceof Blueprint) {
$table = $table->getTable();
}
return parent::wrapTable($table);
}
/**
* {@inheritdoc}
*/
public function wrap($value, $prefixAlias = false)
{
if ($value instanceof Fluent) {
$value = $value->name;
}
return parent::wrap($value, $prefixAlias);
}
/**
* Format a value so that it can be used in "default" clauses.
*
* @param mixed $value
* @return string
*/
protected function getDefaultValue($value)
{
if ($value instanceof Expression) {
return $value;
}
if (is_bool($value)) {
return "'".(int) $value."'";
}
return "'".strval($value)."'";
}
/**
* Create an empty Doctrine DBAL TableDiff from the Blueprint.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Doctrine\DBAL\Schema\AbstractSchemaManager $schema
* @return \Doctrine\DBAL\Schema\TableDiff
*/
protected function getDoctrineTableDiff(Blueprint $blueprint, SchemaManager $schema)
{
$table = $this->getTablePrefix().$blueprint->getTable();
$tableDiff = new TableDiff($table);
$tableDiff->fromTable = $schema->listTableDetails($table);
return $tableDiff;
}
/**
* Compile a change column command into a series of SQL statements.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Illuminate\Support\Fluent $command
* @param \Illuminate\Database\Connection $connection
* @return array
*
* @throws \RuntimeException
*/
public function compileChange(Blueprint $blueprint, Fluent $command, Connection $connection)
{
if (! $connection->isDoctrineAvailable()) {
throw new RuntimeException(sprintf(
'Changing columns for table "%s" requires Doctrine DBAL; install "doctrine/dbal".',
$blueprint->getTable()
));
}
$schema = $connection->getDoctrineSchemaManager();
$tableDiff = $this->getChangedDiff($blueprint, $schema);
if ($tableDiff !== false) {
return (array) $schema->getDatabasePlatform()->getAlterTableSQL($tableDiff);
}
return [];
}
/**
* Get the Doctrine table difference for the given changes.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Doctrine\DBAL\Schema\AbstractSchemaManager $schema
* @return \Doctrine\DBAL\Schema\TableDiff|bool
*/
protected function getChangedDiff(Blueprint $blueprint, SchemaManager $schema)
{
$table = $schema->listTableDetails($this->getTablePrefix().$blueprint->getTable());
return (new Comparator)->diffTable($table, $this->getTableWithColumnChanges($blueprint, $table));
}
/**
* Get a copy of the given Doctrine table after making the column changes.
*
* @param \Illuminate\Database\Schema\Blueprint $blueprint
* @param \Doctrine\DBAL\Schema\Table $table
* @return \Doctrine\DBAL\Schema\TableDiff
*/
protected function getTableWithColumnChanges(Blueprint $blueprint, Table $table)
{
$table = clone $table;
foreach ($blueprint->getChangedColumns() as $fluent) {
$column = $this->getDoctrineColumnForChange($table, $fluent);
// Here we will spin through each fluent column definition and map it to the proper
// Doctrine column definitions - which is necessary because Laravel and Doctrine
// use some different terminology for various column attributes on the tables.
foreach ($fluent->getAttributes() as $key => $value) {
if (! is_null($option = $this->mapFluentOptionToDoctrine($key))) {
if (method_exists($column, $method = 'set'.ucfirst($option))) {
$column->{$method}($this->mapFluentValueToDoctrine($option, $value));
}
}
}
}
return $table;
}
/**
* Get the Doctrine column instance for a column change.
*
* @param \Doctrine\DBAL\Schema\Table $table
* @param \Illuminate\Support\Fluent $fluent
* @return \Doctrine\DBAL\Schema\Column
*/
protected function getDoctrineColumnForChange(Table $table, Fluent $fluent)
{
return $table->changeColumn(
$fluent['name'], $this->getDoctrineColumnChangeOptions($fluent)
)->getColumn($fluent['name']);
}
/**
* Get the Doctrine column change options.
*
* @param \Illuminate\Support\Fluent $fluent
* @return array
*/
protected function getDoctrineColumnChangeOptions(Fluent $fluent)
{
$options = ['type' => $this->getDoctrineColumnType($fluent['type'])];
if (in_array($fluent['type'], ['text', 'mediumText', 'longText'])) {
$options['length'] = $this->calculateDoctrineTextLength($fluent['type']);
}
return $options;
}
/**
* Get the doctrine column type.
*
* @param string $type
* @return \Doctrine\DBAL\Types\Type
*/
protected function getDoctrineColumnType($type)
{
$type = strtolower($type);
switch ($type) {
case 'biginteger':
$type = 'bigint';
break;
case 'smallinteger':
$type = 'smallint';
break;
case 'mediumtext':
case 'longtext':
$type = 'text';
break;
case 'binary':
$type = 'blob';
break;
}
return Type::getType($type);
}
/**
* Calculate the proper column length to force the Doctrine text type.
*
* @param string $type
* @return int
*/
protected function calculateDoctrineTextLength($type)
{
switch ($type) {
case 'mediumText':
return 65535 + 1;
case 'longText':
return 16777215 + 1;
default:
return 255 + 1;
}
}
/**
* Get the matching Doctrine option for a given Fluent attribute name.
*
* @param string $attribute
* @return string|null
*/
protected function mapFluentOptionToDoctrine($attribute)
{
switch ($attribute) {
case 'type':
case 'name':
return;
case 'nullable':
return 'notnull';
case 'total':
return 'precision';
case 'places':
return 'scale';
default:
return $attribute;
}
}
/**
* Get the matching Doctrine value for a given Fluent attribute.
*
* @param string $option
* @param mixed $value
* @return mixed
*/
protected function mapFluentValueToDoctrine($option, $value)
{
return $option == 'notnull' ? ! $value : $value;
}
}
Console/Seeds/SeederMakeCommand.php 0000666 00000003524 13436755161 0013251 0 ustar 00 composer = $composer;
}
/**
* Execute the console command.
*
* @return void
*/
public function fire()
{
parent::fire();
$this->composer->dumpAutoloads();
}
/**
* Get the stub file for the generator.
*
* @return string
*/
protected function getStub()
{
return __DIR__.'/stubs/seeder.stub';
}
/**
* Get the destination class path.
*
* @param string $name
* @return string
*/
protected function getPath($name)
{
return $this->laravel->databasePath().'/seeds/'.$name.'.php';
}
/**
* Parse the name and format according to the root namespace.
*
* @param string $name
* @return string
*/
protected function parseName($name)
{
return $name;
}
}
Console/Seeds/SeedCommand.php 0000666 00000004653 13436755161 0012130 0 ustar 00 resolver = $resolver;
}
/**
* Execute the console command.
*
* @return void
*/
public function fire()
{
if (! $this->confirmToProceed()) {
return;
}
$this->resolver->setDefaultConnection($this->getDatabase());
Model::unguarded(function () {
$this->getSeeder()->run();
});
}
/**
* Get a seeder instance from the container.
*
* @return \Illuminate\Database\Seeder
*/
protected function getSeeder()
{
$class = $this->laravel->make($this->input->getOption('class'));
return $class->setContainer($this->laravel)->setCommand($this);
}
/**
* Get the name of the database connection to use.
*
* @return string
*/
protected function getDatabase()
{
$database = $this->input->getOption('database');
return $database ?: $this->laravel['config']['database.default'];
}
/**
* Get the console command options.
*
* @return array
*/
protected function getOptions()
{
return [
['class', null, InputOption::VALUE_OPTIONAL, 'The class name of the root seeder', 'DatabaseSeeder'],
['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to seed'],
['force', null, InputOption::VALUE_NONE, 'Force the operation to run when in production.'],
];
}
}
Console/Seeds/stubs/seeder.stub 0000666 00000000307 13436755161 0012536 0 ustar 00 confirmToProceed()) {
return;
}
$database = $this->input->getOption('database');
$force = $this->input->getOption('force');
$path = $this->input->getOption('path');
$this->call('migrate:reset', [
'--database' => $database, '--force' => $force,
]);
// The refresh command is essentially just a brief aggregate of a few other of
// the migration commands and just provides a convenient wrapper to execute
// them in succession. We'll also see if we need to re-seed the database.
$this->call('migrate', [
'--database' => $database,
'--force' => $force,
'--path' => $path,
]);
if ($this->needsSeeding()) {
$this->runSeeder($database);
}
}
/**
* Determine if the developer has requested database seeding.
*
* @return bool
*/
protected function needsSeeding()
{
return $this->option('seed') || $this->option('seeder');
}
/**
* Run the database seeder command.
*
* @param string $database
* @return void
*/
protected function runSeeder($database)
{
$class = $this->option('seeder') ?: 'DatabaseSeeder';
$force = $this->input->getOption('force');
$this->call('db:seed', [
'--database' => $database, '--class' => $class, '--force' => $force,
]);
}
/**
* Get the console command options.
*
* @return array
*/
protected function getOptions()
{
return [
['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to use.'],
['force', null, InputOption::VALUE_NONE, 'Force the operation to run when in production.'],
['path', null, InputOption::VALUE_OPTIONAL, 'The path of migrations files to be executed.'],
['seed', null, InputOption::VALUE_NONE, 'Indicates if the seed task should be re-run.'],
['seeder', null, InputOption::VALUE_OPTIONAL, 'The class name of the root seeder.'],
];
}
}
Console/Migrations/InstallCommand.php 0000666 00000003047 13436755161 0013723 0 ustar 00 repository = $repository;
}
/**
* Execute the console command.
*
* @return void
*/
public function fire()
{
$this->repository->setSource($this->input->getOption('database'));
$this->repository->createRepository();
$this->info('Migration table created successfully.');
}
/**
* Get the console command options.
*
* @return array
*/
protected function getOptions()
{
return [
['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to use.'],
];
}
}
Console/Migrations/RollbackCommand.php 0000666 00000004215 13436755161 0014044 0 ustar 00 migrator = $migrator;
}
/**
* Execute the console command.
*
* @return void
*/
public function fire()
{
if (! $this->confirmToProceed()) {
return;
}
$this->migrator->setConnection($this->input->getOption('database'));
$pretend = $this->input->getOption('pretend');
$this->migrator->rollback($pretend);
// Once the migrator has run we will grab the note output and send it out to
// the console screen, since the migrator itself functions without having
// any instances of the OutputInterface contract passed into the class.
foreach ($this->migrator->getNotes() as $note) {
$this->output->writeln($note);
}
}
/**
* Get the console command options.
*
* @return array
*/
protected function getOptions()
{
return [
['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to use.'],
['force', null, InputOption::VALUE_NONE, 'Force the operation to run when in production.'],
['pretend', null, InputOption::VALUE_NONE, 'Dump the SQL queries that would be run.'],
];
}
}
Console/Migrations/ResetCommand.php 0000666 00000004452 13436755161 0013400 0 ustar 00 migrator = $migrator;
}
/**
* Execute the console command.
*
* @return void
*/
public function fire()
{
if (! $this->confirmToProceed()) {
return;
}
$this->migrator->setConnection($this->input->getOption('database'));
if (! $this->migrator->repositoryExists()) {
$this->output->writeln('Migration table not found.');
return;
}
$pretend = $this->input->getOption('pretend');
$this->migrator->reset($pretend);
// Once the migrator has run we will grab the note output and send it out to
// the console screen, since the migrator itself functions without having
// any instances of the OutputInterface contract passed into the class.
foreach ($this->migrator->getNotes() as $note) {
$this->output->writeln($note);
}
}
/**
* Get the console command options.
*
* @return array
*/
protected function getOptions()
{
return [
['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to use.'],
['force', null, InputOption::VALUE_NONE, 'Force the operation to run when in production.'],
['pretend', null, InputOption::VALUE_NONE, 'Dump the SQL queries that would be run.'],
];
}
}
Console/Migrations/BaseCommand.php 0000666 00000000544 13436755161 0013166 0 ustar 00 laravel->databasePath().DIRECTORY_SEPARATOR.'migrations';
}
}
Console/Migrations/MigrateCommand.php 0000666 00000007636 13436755161 0013715 0 ustar 00 migrator = $migrator;
}
/**
* Execute the console command.
*
* @return void
*/
public function fire()
{
if (! $this->confirmToProceed()) {
return;
}
$this->prepareDatabase();
// The pretend option can be used for "simulating" the migration and grabbing
// the SQL queries that would fire if the migration were to be run against
// a database for real, which is helpful for double checking migrations.
$pretend = $this->input->getOption('pretend');
// Next, we will check to see if a path option has been defined. If it has
// we will use the path relative to the root of this installation folder
// so that migrations may be run for any path within the applications.
if (! is_null($path = $this->input->getOption('path'))) {
$path = $this->laravel->basePath().'/'.$path;
} else {
$path = $this->getMigrationPath();
}
$this->migrator->run($path, [
'pretend' => $pretend,
'step' => $this->input->getOption('step'),
]);
// Once the migrator has run we will grab the note output and send it out to
// the console screen, since the migrator itself functions without having
// any instances of the OutputInterface contract passed into the class.
foreach ($this->migrator->getNotes() as $note) {
$this->output->writeln($note);
}
// Finally, if the "seed" option has been given, we will re-run the database
// seed task to re-populate the database, which is convenient when adding
// a migration and a seed at the same time, as it is only this command.
if ($this->input->getOption('seed')) {
$this->call('db:seed', ['--force' => true]);
}
}
/**
* Prepare the migration database for running.
*
* @return void
*/
protected function prepareDatabase()
{
$this->migrator->setConnection($this->input->getOption('database'));
if (! $this->migrator->repositoryExists()) {
$options = ['--database' => $this->input->getOption('database')];
$this->call('migrate:install', $options);
}
}
/**
* Get the console command options.
*
* @return array
*/
protected function getOptions()
{
return [
['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to use.'],
['force', null, InputOption::VALUE_NONE, 'Force the operation to run when in production.'],
['path', null, InputOption::VALUE_OPTIONAL, 'The path of migrations files to be executed.'],
['pretend', null, InputOption::VALUE_NONE, 'Dump the SQL queries that would be run.'],
['seed', null, InputOption::VALUE_NONE, 'Indicates if the seed task should be re-run.'],
['step', null, InputOption::VALUE_NONE, 'Force the migrations to be run so they can be rolled back individually.'],
];
}
}
Console/Migrations/StatusCommand.php 0000666 00000004725 13436755161 0013604 0 ustar 00 migrator = $migrator;
}
/**
* Execute the console command.
*
* @return void
*/
public function fire()
{
if (! $this->migrator->repositoryExists()) {
return $this->error('No migrations found.');
}
$this->migrator->setConnection($this->input->getOption('database'));
if (! is_null($path = $this->input->getOption('path'))) {
$path = $this->laravel->basePath().'/'.$path;
} else {
$path = $this->getMigrationPath();
}
$ran = $this->migrator->getRepository()->getRan();
$migrations = [];
foreach ($this->getAllMigrationFiles($path) as $migration) {
$migrations[] = in_array($migration, $ran) ? ['Y', $migration] : ['N', $migration];
}
if (count($migrations) > 0) {
$this->table(['Ran?', 'Migration'], $migrations);
} else {
$this->error('No migrations found');
}
}
/**
* Get all of the migration files.
*
* @param string $path
* @return array
*/
protected function getAllMigrationFiles($path)
{
return $this->migrator->getMigrationFiles($path);
}
/**
* Get the console command options.
*
* @return array
*/
protected function getOptions()
{
return [
['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to use.'],
['path', null, InputOption::VALUE_OPTIONAL, 'The path of migrations files to use.'],
];
}
}
Console/Migrations/MigrateMakeCommand.php 0000666 00000006151 13436755161 0014502 0 ustar 00 creator = $creator;
$this->composer = $composer;
}
/**
* Execute the console command.
*
* @return void
*/
public function fire()
{
// It's possible for the developer to specify the tables to modify in this
// schema operation. The developer may also specify if this table needs
// to be freshly created so we can create the appropriate migrations.
$name = trim($this->input->getArgument('name'));
$table = $this->input->getOption('table');
$create = $this->input->getOption('create') ?: false;
if (! $table && is_string($create)) {
$table = $create;
$create = true;
}
// Now we are ready to write the migration out to disk. Once we've written
// the migration out, we will dump-autoload for the entire framework to
// make sure that the migrations are registered by the class loaders.
$this->writeMigration($name, $table, $create);
$this->composer->dumpAutoloads();
}
/**
* Write the migration file to disk.
*
* @param string $name
* @param string $table
* @param bool $create
* @return string
*/
protected function writeMigration($name, $table, $create)
{
$path = $this->getMigrationPath();
$file = pathinfo($this->creator->create($name, $path, $table, $create), PATHINFO_FILENAME);
$this->line("Created Migration: $file");
}
/**
* Get migration path (either specified by '--path' option or default location).
*
* @return string
*/
protected function getMigrationPath()
{
if (! is_null($targetPath = $this->input->getOption('path'))) {
return $this->laravel->basePath().'/'.$targetPath;
}
return parent::getMigrationPath();
}
}
PostgresConnection.php 0000666 00000003241 13436755161 0011122 0 ustar 00 schemaGrammar)) {
$this->useDefaultSchemaGrammar();
}
return new PostgresBuilder($this);
}
/**
* Get the default query grammar instance.
*
* @return \Illuminate\Database\Query\Grammars\PostgresGrammar
*/
protected function getDefaultQueryGrammar()
{
return $this->withTablePrefix(new QueryGrammar);
}
/**
* Get the default schema grammar instance.
*
* @return \Illuminate\Database\Schema\Grammars\PostgresGrammar
*/
protected function getDefaultSchemaGrammar()
{
return $this->withTablePrefix(new SchemaGrammar);
}
/**
* Get the default post processor instance.
*
* @return \Illuminate\Database\Query\Processors\PostgresProcessor
*/
protected function getDefaultPostProcessor()
{
return new PostgresProcessor;
}
/**
* Get the Doctrine DBAL driver.
*
* @return \Doctrine\DBAL\Driver\PDOPgSql\Driver
*/
protected function getDoctrineDriver()
{
return new DoctrineDriver;
}
}
Eloquent/ScopeInterface.php 0000666 00000000255 13436755161 0011764 0 ustar 00 query->get();
}
/**
* Initialize the relation on a set of models.
*
* @param array $models
* @param string $relation
* @return array
*/
public function initRelation(array $models, $relation)
{
foreach ($models as $model) {
$model->setRelation($relation, $this->related->newCollection());
}
return $models;
}
/**
* Match the eagerly loaded results to their parents.
*
* @param array $models
* @param \Illuminate\Database\Eloquent\Collection $results
* @param string $relation
* @return array
*/
public function match(array $models, Collection $results, $relation)
{
return $this->matchMany($models, $results, $relation);
}
}
Eloquent/Relations/MorphToMany.php 0000666 00000010106 13436755161 0013243 0 ustar 00 inverse = $inverse;
$this->morphType = $name.'_type';
$this->morphClass = $inverse ? $query->getModel()->getMorphClass() : $parent->getMorphClass();
parent::__construct($query, $parent, $table, $foreignKey, $otherKey, $relationName);
}
/**
* Set the where clause for the relation query.
*
* @return $this
*/
protected function setWhere()
{
parent::setWhere();
$this->query->where($this->table.'.'.$this->morphType, $this->morphClass);
return $this;
}
/**
* Add the constraints for a relationship count query.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param \Illuminate\Database\Eloquent\Builder $parent
* @param array|mixed $columns
* @return \Illuminate\Database\Eloquent\Builder
*/
public function getRelationQuery(Builder $query, Builder $parent, $columns = ['*'])
{
$query = parent::getRelationQuery($query, $parent, $columns);
return $query->where($this->table.'.'.$this->morphType, $this->morphClass);
}
/**
* Set the constraints for an eager load of the relation.
*
* @param array $models
* @return void
*/
public function addEagerConstraints(array $models)
{
parent::addEagerConstraints($models);
$this->query->where($this->table.'.'.$this->morphType, $this->morphClass);
}
/**
* Create a new pivot attachment record.
*
* @param int $id
* @param bool $timed
* @return array
*/
protected function createAttachRecord($id, $timed)
{
$record = parent::createAttachRecord($id, $timed);
return Arr::add($record, $this->morphType, $this->morphClass);
}
/**
* Create a new query builder for the pivot table.
*
* @return \Illuminate\Database\Query\Builder
*/
protected function newPivotQuery()
{
$query = parent::newPivotQuery();
return $query->where($this->morphType, $this->morphClass);
}
/**
* Create a new pivot model instance.
*
* @param array $attributes
* @param bool $exists
* @return \Illuminate\Database\Eloquent\Relations\Pivot
*/
public function newPivot(array $attributes = [], $exists = false)
{
$pivot = new MorphPivot($this->parent, $attributes, $this->table, $exists);
$pivot->setPivotKeys($this->foreignKey, $this->otherKey)
->setMorphType($this->morphType)
->setMorphClass($this->morphClass);
return $pivot;
}
/**
* Get the foreign key "type" name.
*
* @return string
*/
public function getMorphType()
{
return $this->morphType;
}
/**
* Get the class name of the parent model.
*
* @return string
*/
public function getMorphClass()
{
return $this->morphClass;
}
}
Eloquent/Relations/MorphOne.php 0000666 00000002033 13436755161 0012555 0 ustar 00 query->first();
}
/**
* Initialize the relation on a set of models.
*
* @param array $models
* @param string $relation
* @return array
*/
public function initRelation(array $models, $relation)
{
foreach ($models as $model) {
$model->setRelation($relation, null);
}
return $models;
}
/**
* Match the eagerly loaded results to their parents.
*
* @param array $models
* @param \Illuminate\Database\Eloquent\Collection $results
* @param string $relation
* @return array
*/
public function match(array $models, Collection $results, $relation)
{
return $this->matchOne($models, $results, $relation);
}
}
Eloquent/Relations/BelongsTo.php 0000666 00000021614 13436755161 0012730 0 ustar 00 otherKey = $otherKey;
$this->relation = $relation;
$this->foreignKey = $foreignKey;
parent::__construct($query, $parent);
}
/**
* Get the results of the relationship.
*
* @return mixed
*/
public function getResults()
{
return $this->query->first();
}
/**
* Set the base constraints on the relation query.
*
* @return void
*/
public function addConstraints()
{
if (static::$constraints) {
// For belongs to relationships, which are essentially the inverse of has one
// or has many relationships, we need to actually query on the primary key
// of the related models matching on the foreign key that's on a parent.
$table = $this->related->getTable();
$this->query->where($table.'.'.$this->otherKey, '=', $this->parent->{$this->foreignKey});
}
}
/**
* Add the constraints for a relationship query.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param \Illuminate\Database\Eloquent\Builder $parent
* @param array|mixed $columns
* @return \Illuminate\Database\Eloquent\Builder
*/
public function getRelationQuery(Builder $query, Builder $parent, $columns = ['*'])
{
if ($parent->getQuery()->from == $query->getQuery()->from) {
return $this->getRelationQueryForSelfRelation($query, $parent, $columns);
}
$query->select($columns);
$otherKey = $this->wrap($query->getModel()->getTable().'.'.$this->otherKey);
return $query->where($this->getQualifiedForeignKey(), '=', new Expression($otherKey));
}
/**
* Add the constraints for a relationship query on the same table.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param \Illuminate\Database\Eloquent\Builder $parent
* @param array|mixed $columns
* @return \Illuminate\Database\Eloquent\Builder
*/
public function getRelationQueryForSelfRelation(Builder $query, Builder $parent, $columns = ['*'])
{
$query->select($columns);
$query->from($query->getModel()->getTable().' as '.$hash = $this->getRelationCountHash());
$query->getModel()->setTable($hash);
$key = $this->wrap($this->getQualifiedForeignKey());
return $query->where($hash.'.'.$query->getModel()->getKeyName(), '=', new Expression($key));
}
/**
* Get a relationship join table hash.
*
* @return string
*/
public function getRelationCountHash()
{
return 'laravel_reserved_'.static::$selfJoinCount++;
}
/**
* Set the constraints for an eager load of the relation.
*
* @param array $models
* @return void
*/
public function addEagerConstraints(array $models)
{
// We'll grab the primary key name of the related models since it could be set to
// a non-standard name and not "id". We will then construct the constraint for
// our eagerly loading query so it returns the proper models from execution.
$key = $this->related->getTable().'.'.$this->otherKey;
$this->query->whereIn($key, $this->getEagerModelKeys($models));
}
/**
* Gather the keys from an array of related models.
*
* @param array $models
* @return array
*/
protected function getEagerModelKeys(array $models)
{
$keys = [];
// First we need to gather all of the keys from the parent models so we know what
// to query for via the eager loading query. We will add them to an array then
// execute a "where in" statement to gather up all of those related records.
foreach ($models as $model) {
if (! is_null($value = $model->{$this->foreignKey})) {
$keys[] = $value;
}
}
// If there are no keys that were not null we will just return an array with either
// null or 0 in (depending on if incrementing keys are in use) so the query wont
// fail plus returns zero results, which should be what the developer expects.
if (count($keys) === 0) {
return [$this->related->getIncrementing() ? 0 : null];
}
return array_values(array_unique($keys));
}
/**
* Initialize the relation on a set of models.
*
* @param array $models
* @param string $relation
* @return array
*/
public function initRelation(array $models, $relation)
{
foreach ($models as $model) {
$model->setRelation($relation, null);
}
return $models;
}
/**
* Match the eagerly loaded results to their parents.
*
* @param array $models
* @param \Illuminate\Database\Eloquent\Collection $results
* @param string $relation
* @return array
*/
public function match(array $models, Collection $results, $relation)
{
$foreign = $this->foreignKey;
$other = $this->otherKey;
// First we will get to build a dictionary of the child models by their primary
// key of the relationship, then we can easily match the children back onto
// the parents using that dictionary and the primary key of the children.
$dictionary = [];
foreach ($results as $result) {
$dictionary[$result->getAttribute($other)] = $result;
}
// Once we have the dictionary constructed, we can loop through all the parents
// and match back onto their children using these keys of the dictionary and
// the primary key of the children to map them onto the correct instances.
foreach ($models as $model) {
if (isset($dictionary[$model->$foreign])) {
$model->setRelation($relation, $dictionary[$model->$foreign]);
}
}
return $models;
}
/**
* Associate the model instance to the given parent.
*
* @param \Illuminate\Database\Eloquent\Model|int $model
* @return \Illuminate\Database\Eloquent\Model
*/
public function associate($model)
{
$otherKey = ($model instanceof Model ? $model->getAttribute($this->otherKey) : $model);
$this->parent->setAttribute($this->foreignKey, $otherKey);
if ($model instanceof Model) {
$this->parent->setRelation($this->relation, $model);
}
return $this->parent;
}
/**
* Dissociate previously associated model from the given parent.
*
* @return \Illuminate\Database\Eloquent\Model
*/
public function dissociate()
{
$this->parent->setAttribute($this->foreignKey, null);
return $this->parent->setRelation($this->relation, null);
}
/**
* Update the parent model on the relationship.
*
* @param array $attributes
* @return mixed
*/
public function update(array $attributes)
{
$instance = $this->getResults();
return $instance->fill($attributes)->save();
}
/**
* Get the foreign key of the relationship.
*
* @return string
*/
public function getForeignKey()
{
return $this->foreignKey;
}
/**
* Get the fully qualified foreign key of the relationship.
*
* @return string
*/
public function getQualifiedForeignKey()
{
return $this->parent->getTable().'.'.$this->foreignKey;
}
/**
* Get the associated key of the relationship.
*
* @return string
*/
public function getOtherKey()
{
return $this->otherKey;
}
/**
* Get the fully qualified associated key of the relationship.
*
* @return string
*/
public function getQualifiedOtherKeyName()
{
return $this->related->getTable().'.'.$this->otherKey;
}
}
Eloquent/Relations/MorphPivot.php 0000666 00000003240 13436755161 0013136 0 ustar 00 where($this->morphType, $this->morphClass);
return parent::setKeysForSaveQuery($query);
}
/**
* Delete the pivot model record from the database.
*
* @return int
*/
public function delete()
{
$query = $this->getDeleteQuery();
$query->where($this->morphType, $this->morphClass);
return $query->delete();
}
/**
* Set the morph type for the pivot.
*
* @param string $morphType
* @return $this
*/
public function setMorphType($morphType)
{
$this->morphType = $morphType;
return $this;
}
/**
* Set the morph class for the pivot.
*
* @param string $morphClass
* @return \Illuminate\Database\Eloquent\Relations\MorphPivot
*/
public function setMorphClass($morphClass)
{
$this->morphClass = $morphClass;
return $this;
}
}
Eloquent/Relations/MorphMany.php 0000666 00000002066 13436755161 0012746 0 ustar 00 query->get();
}
/**
* Initialize the relation on a set of models.
*
* @param array $models
* @param string $relation
* @return array
*/
public function initRelation(array $models, $relation)
{
foreach ($models as $model) {
$model->setRelation($relation, $this->related->newCollection());
}
return $models;
}
/**
* Match the eagerly loaded results to their parents.
*
* @param array $models
* @param \Illuminate\Database\Eloquent\Collection $results
* @param string $relation
* @return array
*/
public function match(array $models, Collection $results, $relation)
{
return $this->matchMany($models, $results, $relation);
}
}
Eloquent/Relations/MorphOneOrMany.php 0000666 00000014527 13436755161 0013716 0 ustar 00 morphType = $type;
$this->morphClass = $parent->getMorphClass();
parent::__construct($query, $parent, $id, $localKey);
}
/**
* Set the base constraints on the relation query.
*
* @return void
*/
public function addConstraints()
{
if (static::$constraints) {
parent::addConstraints();
$this->query->where($this->morphType, $this->morphClass);
}
}
/**
* Get the relationship query.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param \Illuminate\Database\Eloquent\Builder $parent
* @param array|mixed $columns
* @return \Illuminate\Database\Eloquent\Builder
*/
public function getRelationQuery(Builder $query, Builder $parent, $columns = ['*'])
{
$query = parent::getRelationQuery($query, $parent, $columns);
return $query->where($this->morphType, $this->morphClass);
}
/**
* Set the constraints for an eager load of the relation.
*
* @param array $models
* @return void
*/
public function addEagerConstraints(array $models)
{
parent::addEagerConstraints($models);
$this->query->where($this->morphType, $this->morphClass);
}
/**
* Attach a model instance to the parent model.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @return \Illuminate\Database\Eloquent\Model
*/
public function save(Model $model)
{
$model->setAttribute($this->getPlainMorphType(), $this->morphClass);
return parent::save($model);
}
/**
* Find a related model by its primary key or return new instance of the related model.
*
* @param mixed $id
* @param array $columns
* @return \Illuminate\Support\Collection|\Illuminate\Database\Eloquent\Model
*/
public function findOrNew($id, $columns = ['*'])
{
if (is_null($instance = $this->find($id, $columns))) {
$instance = $this->related->newInstance();
// When saving a polymorphic relationship, we need to set not only the foreign
// key, but also the foreign key type, which is typically the class name of
// the parent model. This makes the polymorphic item unique in the table.
$this->setForeignAttributesForCreate($instance);
}
return $instance;
}
/**
* Get the first related model record matching the attributes or instantiate it.
*
* @param array $attributes
* @return \Illuminate\Database\Eloquent\Model
*/
public function firstOrNew(array $attributes)
{
if (is_null($instance = $this->where($attributes)->first())) {
$instance = $this->related->newInstance($attributes);
// When saving a polymorphic relationship, we need to set not only the foreign
// key, but also the foreign key type, which is typically the class name of
// the parent model. This makes the polymorphic item unique in the table.
$this->setForeignAttributesForCreate($instance);
}
return $instance;
}
/**
* Get the first related record matching the attributes or create it.
*
* @param array $attributes
* @return \Illuminate\Database\Eloquent\Model
*/
public function firstOrCreate(array $attributes)
{
if (is_null($instance = $this->where($attributes)->first())) {
$instance = $this->create($attributes);
}
return $instance;
}
/**
* Create or update a related record matching the attributes, and fill it with values.
*
* @param array $attributes
* @param array $values
* @return \Illuminate\Database\Eloquent\Model
*/
public function updateOrCreate(array $attributes, array $values = [])
{
$instance = $this->firstOrNew($attributes);
$instance->fill($values);
$instance->save();
return $instance;
}
/**
* Create a new instance of the related model.
*
* @param array $attributes
* @return \Illuminate\Database\Eloquent\Model
*/
public function create(array $attributes)
{
$instance = $this->related->newInstance($attributes);
// When saving a polymorphic relationship, we need to set not only the foreign
// key, but also the foreign key type, which is typically the class name of
// the parent model. This makes the polymorphic item unique in the table.
$this->setForeignAttributesForCreate($instance);
$instance->save();
return $instance;
}
/**
* Set the foreign ID and type for creating a related model.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @return void
*/
protected function setForeignAttributesForCreate(Model $model)
{
$model->{$this->getPlainForeignKey()} = $this->getParentKey();
$model->{last(explode('.', $this->morphType))} = $this->morphClass;
}
/**
* Get the foreign key "type" name.
*
* @return string
*/
public function getMorphType()
{
return $this->morphType;
}
/**
* Get the plain morph type name without the table.
*
* @return string
*/
public function getPlainMorphType()
{
return last(explode('.', $this->morphType));
}
/**
* Get the class name of the parent model.
*
* @return string
*/
public function getMorphClass()
{
return $this->morphClass;
}
}
Eloquent/Relations/HasOne.php 0000666 00000002027 13436755161 0012206 0 ustar 00 query->first();
}
/**
* Initialize the relation on a set of models.
*
* @param array $models
* @param string $relation
* @return array
*/
public function initRelation(array $models, $relation)
{
foreach ($models as $model) {
$model->setRelation($relation, null);
}
return $models;
}
/**
* Match the eagerly loaded results to their parents.
*
* @param array $models
* @param \Illuminate\Database\Eloquent\Collection $results
* @param string $relation
* @return array
*/
public function match(array $models, Collection $results, $relation)
{
return $this->matchOne($models, $results, $relation);
}
}
Eloquent/Relations/BelongsToMany.php 0000666 00000111120 13436755161 0013545 0 ustar 00 table = $table;
$this->otherKey = $otherKey;
$this->foreignKey = $foreignKey;
$this->relationName = $relationName;
parent::__construct($query, $parent);
}
/**
* Get the results of the relationship.
*
* @return mixed
*/
public function getResults()
{
return $this->get();
}
/**
* Set a where clause for a pivot table column.
*
* @param string $column
* @param string $operator
* @param mixed $value
* @param string $boolean
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function wherePivot($column, $operator = null, $value = null, $boolean = 'and')
{
$this->pivotWheres[] = func_get_args();
return $this->where($this->table.'.'.$column, $operator, $value, $boolean);
}
/**
* Set a "where in" clause for a pivot table column.
*
* @param string $column
* @param mixed $values
* @param string $boolean
* @param bool $not
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function wherePivotIn($column, $values, $boolean = 'and', $not = false)
{
$this->pivotWhereIns[] = func_get_args();
return $this->whereIn($this->table.'.'.$column, $values, $boolean, $not);
}
/**
* Set an "or where" clause for a pivot table column.
*
* @param string $column
* @param string $operator
* @param mixed $value
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function orWherePivot($column, $operator = null, $value = null)
{
return $this->wherePivot($column, $operator, $value, 'or');
}
/**
* Set an "or where in" clause for a pivot table column.
*
* @param string $column
* @param mixed $values
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function orWherePivotIn($column, $values)
{
return $this->wherePivotIn($column, $values, 'or');
}
/**
* Execute the query and get the first result.
*
* @param array $columns
* @return mixed
*/
public function first($columns = ['*'])
{
$results = $this->take(1)->get($columns);
return count($results) > 0 ? $results->first() : null;
}
/**
* Execute the query and get the first result or throw an exception.
*
* @param array $columns
* @return \Illuminate\Database\Eloquent\Model|static
*
* @throws \Illuminate\Database\Eloquent\ModelNotFoundException
*/
public function firstOrFail($columns = ['*'])
{
if (! is_null($model = $this->first($columns))) {
return $model;
}
throw (new ModelNotFoundException)->setModel(get_class($this->parent));
}
/**
* Execute the query as a "select" statement.
*
* @param array $columns
* @return \Illuminate\Database\Eloquent\Collection
*/
public function get($columns = ['*'])
{
// First we'll add the proper select columns onto the query so it is run with
// the proper columns. Then, we will get the results and hydrate out pivot
// models with the result of those columns as a separate model relation.
$columns = $this->query->getQuery()->columns ? [] : $columns;
$select = $this->getSelectColumns($columns);
$builder = $this->query->applyScopes();
$models = $builder->addSelect($select)->getModels();
$this->hydratePivotRelation($models);
// If we actually found models we will also eager load any relationships that
// have been specified as needing to be eager loaded. This will solve the
// n + 1 query problem for the developer and also increase performance.
if (count($models) > 0) {
$models = $builder->eagerLoadRelations($models);
}
return $this->related->newCollection($models);
}
/**
* Get a paginator for the "select" statement.
*
* @param int $perPage
* @param array $columns
* @param string $pageName
* @param int|null $page
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
*/
public function paginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null)
{
$this->query->addSelect($this->getSelectColumns($columns));
$paginator = $this->query->paginate($perPage, $columns, $pageName, $page);
$this->hydratePivotRelation($paginator->items());
return $paginator;
}
/**
* Paginate the given query into a simple paginator.
*
* @param int $perPage
* @param array $columns
* @param string $pageName
* @return \Illuminate\Contracts\Pagination\Paginator
*/
public function simplePaginate($perPage = null, $columns = ['*'], $pageName = 'page')
{
$this->query->addSelect($this->getSelectColumns($columns));
$paginator = $this->query->simplePaginate($perPage, $columns, $pageName);
$this->hydratePivotRelation($paginator->items());
return $paginator;
}
/**
* Chunk the results of the query.
*
* @param int $count
* @param callable $callback
* @return bool
*/
public function chunk($count, callable $callback)
{
$this->query->addSelect($this->getSelectColumns());
return $this->query->chunk($count, function ($results) use ($callback) {
$this->hydratePivotRelation($results->all());
return $callback($results);
});
}
/**
* Hydrate the pivot table relationship on the models.
*
* @param array $models
* @return void
*/
protected function hydratePivotRelation(array $models)
{
// To hydrate the pivot relationship, we will just gather the pivot attributes
// and create a new Pivot model, which is basically a dynamic model that we
// will set the attributes, table, and connections on so it they be used.
foreach ($models as $model) {
$pivot = $this->newExistingPivot($this->cleanPivotAttributes($model));
$model->setRelation('pivot', $pivot);
}
}
/**
* Get the pivot attributes from a model.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @return array
*/
protected function cleanPivotAttributes(Model $model)
{
$values = [];
foreach ($model->getAttributes() as $key => $value) {
// To get the pivots attributes we will just take any of the attributes which
// begin with "pivot_" and add those to this arrays, as well as unsetting
// them from the parent's models since they exist in a different table.
if (strpos($key, 'pivot_') === 0) {
$values[substr($key, 6)] = $value;
unset($model->$key);
}
}
return $values;
}
/**
* Set the base constraints on the relation query.
*
* @return void
*/
public function addConstraints()
{
$this->setJoin();
if (static::$constraints) {
$this->setWhere();
}
}
/**
* Add the constraints for a relationship query.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param \Illuminate\Database\Eloquent\Builder $parent
* @param array|mixed $columns
* @return \Illuminate\Database\Eloquent\Builder
*/
public function getRelationQuery(Builder $query, Builder $parent, $columns = ['*'])
{
if ($parent->getQuery()->from == $query->getQuery()->from) {
return $this->getRelationQueryForSelfJoin($query, $parent, $columns);
}
$this->setJoin($query);
return parent::getRelationQuery($query, $parent, $columns);
}
/**
* Add the constraints for a relationship query on the same table.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param \Illuminate\Database\Eloquent\Builder $parent
* @param array|mixed $columns
* @return \Illuminate\Database\Eloquent\Builder
*/
public function getRelationQueryForSelfJoin(Builder $query, Builder $parent, $columns = ['*'])
{
$query->select($columns);
$query->from($this->related->getTable().' as '.$hash = $this->getRelationCountHash());
$this->related->setTable($hash);
$this->setJoin($query);
return parent::getRelationQuery($query, $parent, $columns);
}
/**
* Get a relationship join table hash.
*
* @return string
*/
public function getRelationCountHash()
{
return 'laravel_reserved_'.static::$selfJoinCount++;
}
/**
* Set the select clause for the relation query.
*
* @param array $columns
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
protected function getSelectColumns(array $columns = ['*'])
{
if ($columns == ['*']) {
$columns = [$this->related->getTable().'.*'];
}
return array_merge($columns, $this->getAliasedPivotColumns());
}
/**
* Get the pivot columns for the relation.
*
* @return array
*/
protected function getAliasedPivotColumns()
{
$defaults = [$this->foreignKey, $this->otherKey];
// We need to alias all of the pivot columns with the "pivot_" prefix so we
// can easily extract them out of the models and put them into the pivot
// relationships when they are retrieved and hydrated into the models.
$columns = [];
foreach (array_merge($defaults, $this->pivotColumns) as $column) {
$columns[] = $this->table.'.'.$column.' as pivot_'.$column;
}
return array_unique($columns);
}
/**
* Determine whether the given column is defined as a pivot column.
*
* @param string $column
* @return bool
*/
protected function hasPivotColumn($column)
{
return in_array($column, $this->pivotColumns);
}
/**
* Set the join clause for the relation query.
*
* @param \Illuminate\Database\Eloquent\Builder|null $query
* @return $this
*/
protected function setJoin($query = null)
{
$query = $query ?: $this->query;
// We need to join to the intermediate table on the related model's primary
// key column with the intermediate table's foreign key for the related
// model instance. Then we can set the "where" for the parent models.
$baseTable = $this->related->getTable();
$key = $baseTable.'.'.$this->related->getKeyName();
$query->join($this->table, $key, '=', $this->getOtherKey());
return $this;
}
/**
* Set the where clause for the relation query.
*
* @return $this
*/
protected function setWhere()
{
$foreign = $this->getForeignKey();
$this->query->where($foreign, '=', $this->parent->getKey());
return $this;
}
/**
* Set the constraints for an eager load of the relation.
*
* @param array $models
* @return void
*/
public function addEagerConstraints(array $models)
{
$this->query->whereIn($this->getForeignKey(), $this->getKeys($models));
}
/**
* Initialize the relation on a set of models.
*
* @param array $models
* @param string $relation
* @return array
*/
public function initRelation(array $models, $relation)
{
foreach ($models as $model) {
$model->setRelation($relation, $this->related->newCollection());
}
return $models;
}
/**
* Match the eagerly loaded results to their parents.
*
* @param array $models
* @param \Illuminate\Database\Eloquent\Collection $results
* @param string $relation
* @return array
*/
public function match(array $models, Collection $results, $relation)
{
$dictionary = $this->buildDictionary($results);
// Once we have an array dictionary of child objects we can easily match the
// children back to their parent using the dictionary and the keys on the
// the parent models. Then we will return the hydrated models back out.
foreach ($models as $model) {
if (isset($dictionary[$key = $model->getKey()])) {
$collection = $this->related->newCollection($dictionary[$key]);
$model->setRelation($relation, $collection);
}
}
return $models;
}
/**
* Build model dictionary keyed by the relation's foreign key.
*
* @param \Illuminate\Database\Eloquent\Collection $results
* @return array
*/
protected function buildDictionary(Collection $results)
{
$foreign = $this->foreignKey;
// First we will build a dictionary of child models keyed by the foreign key
// of the relation so that we will easily and quickly match them to their
// parents without having a possibly slow inner loops for every models.
$dictionary = [];
foreach ($results as $result) {
$dictionary[$result->pivot->$foreign][] = $result;
}
return $dictionary;
}
/**
* Touch all of the related models for the relationship.
*
* E.g.: Touch all roles associated with this user.
*
* @return void
*/
public function touch()
{
$key = $this->getRelated()->getKeyName();
$columns = $this->getRelatedFreshUpdate();
// If we actually have IDs for the relation, we will run the query to update all
// the related model's timestamps, to make sure these all reflect the changes
// to the parent models. This will help us keep any caching synced up here.
$ids = $this->getRelatedIds();
if (count($ids) > 0) {
$this->getRelated()->newQuery()->whereIn($key, $ids)->update($columns);
}
}
/**
* Get all of the IDs for the related models.
*
* @return \Illuminate\Support\Collection
*/
public function getRelatedIds()
{
$related = $this->getRelated();
$fullKey = $related->getQualifiedKeyName();
return $this->getQuery()->select($fullKey)->pluck($related->getKeyName());
}
/**
* Save a new model and attach it to the parent model.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @param array $joining
* @param bool $touch
* @return \Illuminate\Database\Eloquent\Model
*/
public function save(Model $model, array $joining = [], $touch = true)
{
$model->save(['touch' => false]);
$this->attach($model->getKey(), $joining, $touch);
return $model;
}
/**
* Save an array of new models and attach them to the parent model.
*
* @param \Illuminate\Support\Collection|array $models
* @param array $joinings
* @return array
*/
public function saveMany($models, array $joinings = [])
{
foreach ($models as $key => $model) {
$this->save($model, (array) Arr::get($joinings, $key), false);
}
$this->touchIfTouching();
return $models;
}
/**
* Find a related model by its primary key.
*
* @param mixed $id
* @param array $columns
* @return \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Collection|null
*/
public function find($id, $columns = ['*'])
{
if (is_array($id)) {
return $this->findMany($id, $columns);
}
$this->where($this->getRelated()->getQualifiedKeyName(), '=', $id);
return $this->first($columns);
}
/**
* Find multiple related models by their primary keys.
*
* @param mixed $ids
* @param array $columns
* @return \Illuminate\Database\Eloquent\Collection
*/
public function findMany($ids, $columns = ['*'])
{
if (empty($ids)) {
return $this->getRelated()->newCollection();
}
$this->whereIn($this->getRelated()->getQualifiedKeyName(), $ids);
return $this->get($columns);
}
/**
* Find a related model by its primary key or throw an exception.
*
* @param mixed $id
* @param array $columns
* @return \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Collection
*
* @throws \Illuminate\Database\Eloquent\ModelNotFoundException
*/
public function findOrFail($id, $columns = ['*'])
{
$result = $this->find($id, $columns);
if (is_array($id)) {
if (count($result) == count(array_unique($id))) {
return $result;
}
} elseif (! is_null($result)) {
return $result;
}
throw (new ModelNotFoundException)->setModel(get_class($this->parent));
}
/**
* Find a related model by its primary key or return new instance of the related model.
*
* @param mixed $id
* @param array $columns
* @return \Illuminate\Support\Collection|\Illuminate\Database\Eloquent\Model
*/
public function findOrNew($id, $columns = ['*'])
{
if (is_null($instance = $this->find($id, $columns))) {
$instance = $this->getRelated()->newInstance();
}
return $instance;
}
/**
* Get the first related model record matching the attributes or instantiate it.
*
* @param array $attributes
* @return \Illuminate\Database\Eloquent\Model
*/
public function firstOrNew(array $attributes)
{
if (is_null($instance = $this->where($attributes)->first())) {
$instance = $this->related->newInstance($attributes);
}
return $instance;
}
/**
* Get the first related record matching the attributes or create it.
*
* @param array $attributes
* @param array $joining
* @param bool $touch
* @return \Illuminate\Database\Eloquent\Model
*/
public function firstOrCreate(array $attributes, array $joining = [], $touch = true)
{
if (is_null($instance = $this->where($attributes)->first())) {
$instance = $this->create($attributes, $joining, $touch);
}
return $instance;
}
/**
* Create or update a related record matching the attributes, and fill it with values.
*
* @param array $attributes
* @param array $values
* @param array $joining
* @param bool $touch
* @return \Illuminate\Database\Eloquent\Model
*/
public function updateOrCreate(array $attributes, array $values = [], array $joining = [], $touch = true)
{
if (is_null($instance = $this->where($attributes)->first())) {
return $this->create($values, $joining, $touch);
}
$instance->fill($values);
$instance->save(['touch' => false]);
return $instance;
}
/**
* Create a new instance of the related model.
*
* @param array $attributes
* @param array $joining
* @param bool $touch
* @return \Illuminate\Database\Eloquent\Model
*/
public function create(array $attributes, array $joining = [], $touch = true)
{
$instance = $this->related->newInstance($attributes);
// Once we save the related model, we need to attach it to the base model via
// through intermediate table so we'll use the existing "attach" method to
// accomplish this which will insert the record and any more attributes.
$instance->save(['touch' => false]);
$this->attach($instance->getKey(), $joining, $touch);
return $instance;
}
/**
* Create an array of new instances of the related models.
*
* @param array $records
* @param array $joinings
* @return array
*/
public function createMany(array $records, array $joinings = [])
{
$instances = [];
foreach ($records as $key => $record) {
$instances[] = $this->create($record, (array) Arr::get($joinings, $key), false);
}
$this->touchIfTouching();
return $instances;
}
/**
* Sync the intermediate tables with a list of IDs without detaching.
*
* @param \Illuminate\Database\Eloquent\Collection|array $ids
* @return array
*/
public function syncWithoutDetaching($ids)
{
return $this->sync($ids, false);
}
/**
* Sync the intermediate tables with a list of IDs or collection of models.
*
* @param \Illuminate\Database\Eloquent\Collection|array $ids
* @param bool $detaching
* @return array
*/
public function sync($ids, $detaching = true)
{
$changes = [
'attached' => [], 'detached' => [], 'updated' => [],
];
if ($ids instanceof Collection) {
$ids = $ids->modelKeys();
}
// First we need to attach any of the associated models that are not currently
// in this joining table. We'll spin through the given IDs, checking to see
// if they exist in the array of current ones, and if not we will insert.
$current = $this->newPivotQuery()->pluck($this->otherKey);
$records = $this->formatSyncList($ids);
$detach = array_diff($current, array_keys($records));
// Next, we will take the differences of the currents and given IDs and detach
// all of the entities that exist in the "current" array but are not in the
// array of the new IDs given to the method which will complete the sync.
if ($detaching && count($detach) > 0) {
$this->detach($detach);
$changes['detached'] = (array) array_map(function ($v) {
return is_numeric($v) ? (int) $v : (string) $v;
}, $detach);
}
// Now we are finally ready to attach the new records. Note that we'll disable
// touching until after the entire operation is complete so we don't fire a
// ton of touch operations until we are totally done syncing the records.
$changes = array_merge(
$changes, $this->attachNew($records, $current, false)
);
if (count($changes['attached']) || count($changes['updated'])) {
$this->touchIfTouching();
}
return $changes;
}
/**
* Format the sync list so that it is keyed by ID.
*
* @param array $records
* @return array
*/
protected function formatSyncList(array $records)
{
$results = [];
foreach ($records as $id => $attributes) {
if (! is_array($attributes)) {
list($id, $attributes) = [$attributes, []];
}
$results[$id] = $attributes;
}
return $results;
}
/**
* Attach all of the IDs that aren't in the current array.
*
* @param array $records
* @param array $current
* @param bool $touch
* @return array
*/
protected function attachNew(array $records, array $current, $touch = true)
{
$changes = ['attached' => [], 'updated' => []];
foreach ($records as $id => $attributes) {
// If the ID is not in the list of existing pivot IDs, we will insert a new pivot
// record, otherwise, we will just update this existing record on this joining
// table, so that the developers will easily update these records pain free.
if (! in_array($id, $current)) {
$this->attach($id, $attributes, $touch);
$changes['attached'][] = is_numeric($id) ? (int) $id : (string) $id;
}
// Now we'll try to update an existing pivot record with the attributes that were
// given to the method. If the model is actually updated we will add it to the
// list of updated pivot records so we return them back out to the consumer.
elseif (count($attributes) > 0 &&
$this->updateExistingPivot($id, $attributes, $touch)) {
$changes['updated'][] = is_numeric($id) ? (int) $id : (string) $id;
}
}
return $changes;
}
/**
* Update an existing pivot record on the table.
*
* @param mixed $id
* @param array $attributes
* @param bool $touch
* @return int
*/
public function updateExistingPivot($id, array $attributes, $touch = true)
{
if (in_array($this->updatedAt(), $this->pivotColumns)) {
$attributes = $this->setTimestampsOnAttach($attributes, true);
}
$updated = $this->newPivotStatementForId($id)->update($attributes);
if ($touch) {
$this->touchIfTouching();
}
return $updated;
}
/**
* Attach a model to the parent.
*
* @param mixed $id
* @param array $attributes
* @param bool $touch
* @return void
*/
public function attach($id, array $attributes = [], $touch = true)
{
if ($id instanceof Model) {
$id = $id->getKey();
}
if ($id instanceof Collection) {
$id = $id->modelKeys();
}
$query = $this->newPivotStatement();
$query->insert($this->createAttachRecords((array) $id, $attributes));
if ($touch) {
$this->touchIfTouching();
}
}
/**
* Create an array of records to insert into the pivot table.
*
* @param array $ids
* @param array $attributes
* @return array
*/
protected function createAttachRecords($ids, array $attributes)
{
$records = [];
$timed = ($this->hasPivotColumn($this->createdAt()) ||
$this->hasPivotColumn($this->updatedAt()));
// To create the attachment records, we will simply spin through the IDs given
// and create a new record to insert for each ID. Each ID may actually be a
// key in the array, with extra attributes to be placed in other columns.
foreach ($ids as $key => $value) {
$records[] = $this->attacher($key, $value, $attributes, $timed);
}
return $records;
}
/**
* Create a full attachment record payload.
*
* @param int $key
* @param mixed $value
* @param array $attributes
* @param bool $timed
* @return array
*/
protected function attacher($key, $value, $attributes, $timed)
{
list($id, $extra) = $this->getAttachId($key, $value, $attributes);
// To create the attachment records, we will simply spin through the IDs given
// and create a new record to insert for each ID. Each ID may actually be a
// key in the array, with extra attributes to be placed in other columns.
$record = $this->createAttachRecord($id, $timed);
return array_merge($record, $extra);
}
/**
* Get the attach record ID and extra attributes.
*
* @param mixed $key
* @param mixed $value
* @param array $attributes
* @return array
*/
protected function getAttachId($key, $value, array $attributes)
{
if (is_array($value)) {
return [$key, array_merge($value, $attributes)];
}
return [$value, $attributes];
}
/**
* Create a new pivot attachment record.
*
* @param int $id
* @param bool $timed
* @return array
*/
protected function createAttachRecord($id, $timed)
{
$record[$this->foreignKey] = $this->parent->getKey();
$record[$this->otherKey] = $id;
// If the record needs to have creation and update timestamps, we will make
// them by calling the parent model's "freshTimestamp" method which will
// provide us with a fresh timestamp in this model's preferred format.
if ($timed) {
$record = $this->setTimestampsOnAttach($record);
}
return $record;
}
/**
* Set the creation and update timestamps on an attach record.
*
* @param array $record
* @param bool $exists
* @return array
*/
protected function setTimestampsOnAttach(array $record, $exists = false)
{
$fresh = $this->parent->freshTimestamp();
if (! $exists && $this->hasPivotColumn($this->createdAt())) {
$record[$this->createdAt()] = $fresh;
}
if ($this->hasPivotColumn($this->updatedAt())) {
$record[$this->updatedAt()] = $fresh;
}
return $record;
}
/**
* Detach models from the relationship.
*
* @param mixed $ids
* @param bool $touch
* @return int
*/
public function detach($ids = [], $touch = true)
{
if ($ids instanceof Model) {
$ids = $ids->getKey();
}
if ($ids instanceof Collection) {
$ids = $ids->modelKeys();
}
$query = $this->newPivotQuery();
// If associated IDs were passed to the method we will only delete those
// associations, otherwise all of the association ties will be broken.
// We'll return the numbers of affected rows when we do the deletes.
$ids = (array) $ids;
if (count($ids) > 0) {
$query->whereIn($this->otherKey, $ids);
}
// Once we have all of the conditions set on the statement, we are ready
// to run the delete on the pivot table. Then, if the touch parameter
// is true, we will go ahead and touch all related models to sync.
$results = $query->delete();
if ($touch) {
$this->touchIfTouching();
}
return $results;
}
/**
* If we're touching the parent model, touch.
*
* @return void
*/
public function touchIfTouching()
{
if ($this->touchingParent()) {
$this->getParent()->touch();
}
if ($this->getParent()->touches($this->relationName)) {
$this->touch();
}
}
/**
* Determine if we should touch the parent on sync.
*
* @return bool
*/
protected function touchingParent()
{
return $this->getRelated()->touches($this->guessInverseRelation());
}
/**
* Attempt to guess the name of the inverse of the relation.
*
* @return string
*/
protected function guessInverseRelation()
{
return Str::camel(Str::plural(class_basename($this->getParent())));
}
/**
* Create a new query builder for the pivot table.
*
* @return \Illuminate\Database\Query\Builder
*/
protected function newPivotQuery()
{
$query = $this->newPivotStatement();
foreach ($this->pivotWheres as $whereArgs) {
call_user_func_array([$query, 'where'], $whereArgs);
}
foreach ($this->pivotWhereIns as $whereArgs) {
call_user_func_array([$query, 'whereIn'], $whereArgs);
}
return $query->where($this->foreignKey, $this->parent->getKey());
}
/**
* Get a new plain query builder for the pivot table.
*
* @return \Illuminate\Database\Query\Builder
*/
public function newPivotStatement()
{
return $this->query->getQuery()->newQuery()->from($this->table);
}
/**
* Get a new pivot statement for a given "other" ID.
*
* @param mixed $id
* @return \Illuminate\Database\Query\Builder
*/
public function newPivotStatementForId($id)
{
return $this->newPivotQuery()->where($this->otherKey, $id);
}
/**
* Create a new pivot model instance.
*
* @param array $attributes
* @param bool $exists
* @return \Illuminate\Database\Eloquent\Relations\Pivot
*/
public function newPivot(array $attributes = [], $exists = false)
{
$pivot = $this->related->newPivot($this->parent, $attributes, $this->table, $exists);
return $pivot->setPivotKeys($this->foreignKey, $this->otherKey);
}
/**
* Create a new existing pivot model instance.
*
* @param array $attributes
* @return \Illuminate\Database\Eloquent\Relations\Pivot
*/
public function newExistingPivot(array $attributes = [])
{
return $this->newPivot($attributes, true);
}
/**
* Set the columns on the pivot table to retrieve.
*
* @param array|mixed $columns
* @return $this
*/
public function withPivot($columns)
{
$columns = is_array($columns) ? $columns : func_get_args();
$this->pivotColumns = array_merge($this->pivotColumns, $columns);
return $this;
}
/**
* Specify that the pivot table has creation and update timestamps.
*
* @param mixed $createdAt
* @param mixed $updatedAt
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function withTimestamps($createdAt = null, $updatedAt = null)
{
$this->pivotCreatedAt = $createdAt;
$this->pivotUpdatedAt = $updatedAt;
return $this->withPivot($this->createdAt(), $this->updatedAt());
}
/**
* Get the name of the "created at" column.
*
* @return string
*/
public function createdAt()
{
return $this->pivotCreatedAt ?: $this->parent->getCreatedAtColumn();
}
/**
* Get the name of the "updated at" column.
*
* @return string
*/
public function updatedAt()
{
return $this->pivotUpdatedAt ?: $this->parent->getUpdatedAtColumn();
}
/**
* Get the related model's updated at column name.
*
* @return string
*/
public function getRelatedFreshUpdate()
{
return [$this->related->getUpdatedAtColumn() => $this->related->freshTimestampString()];
}
/**
* Get the key for comparing against the parent key in "has" query.
*
* @return string
*/
public function getHasCompareKey()
{
return $this->getForeignKey();
}
/**
* Get the fully qualified foreign key for the relation.
*
* @return string
*/
public function getForeignKey()
{
return $this->table.'.'.$this->foreignKey;
}
/**
* Get the fully qualified "other key" for the relation.
*
* @return string
*/
public function getOtherKey()
{
return $this->table.'.'.$this->otherKey;
}
/**
* Get the intermediate table for the relationship.
*
* @return string
*/
public function getTable()
{
return $this->table;
}
/**
* Get the relationship name for the relationship.
*
* @return string
*/
public function getRelationName()
{
return $this->relationName;
}
}
Eloquent/Relations/MorphTo.php 0000666 00000016116 13436755161 0012425 0 ustar 00 morphType = $type;
parent::__construct($query, $parent, $foreignKey, $otherKey, $relation);
}
/**
* Get the results of the relationship.
*
* @return mixed
*/
public function getResults()
{
if (! $this->otherKey) {
return;
}
return $this->query->first();
}
/**
* Set the constraints for an eager load of the relation.
*
* @param array $models
* @return void
*/
public function addEagerConstraints(array $models)
{
$this->buildDictionary($this->models = Collection::make($models));
}
/**
* Build a dictionary with the models.
*
* @param \Illuminate\Database\Eloquent\Collection $models
* @return void
*/
protected function buildDictionary(Collection $models)
{
foreach ($models as $model) {
if ($model->{$this->morphType}) {
$this->dictionary[$model->{$this->morphType}][$model->{$this->foreignKey}][] = $model;
}
}
}
/**
* Match the eagerly loaded results to their parents.
*
* @param array $models
* @param \Illuminate\Database\Eloquent\Collection $results
* @param string $relation
* @return array
*/
public function match(array $models, Collection $results, $relation)
{
return $models;
}
/**
* Associate the model instance to the given parent.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @return \Illuminate\Database\Eloquent\Model
*/
public function associate($model)
{
$this->parent->setAttribute($this->foreignKey, $model->getKey());
$this->parent->setAttribute($this->morphType, $model->getMorphClass());
return $this->parent->setRelation($this->relation, $model);
}
/**
* Dissociate previously associated model from the given parent.
*
* @return \Illuminate\Database\Eloquent\Model
*/
public function dissociate()
{
$this->parent->setAttribute($this->foreignKey, null);
$this->parent->setAttribute($this->morphType, null);
return $this->parent->setRelation($this->relation, null);
}
/**
* Get the results of the relationship.
*
* Called via eager load method of Eloquent query builder.
*
* @return mixed
*/
public function getEager()
{
foreach (array_keys($this->dictionary) as $type) {
$this->matchToMorphParents($type, $this->getResultsByType($type));
}
return $this->models;
}
/**
* Match the results for a given type to their parents.
*
* @param string $type
* @param \Illuminate\Database\Eloquent\Collection $results
* @return void
*/
protected function matchToMorphParents($type, Collection $results)
{
foreach ($results as $result) {
if (isset($this->dictionary[$type][$result->getKey()])) {
foreach ($this->dictionary[$type][$result->getKey()] as $model) {
$model->setRelation($this->relation, $result);
}
}
}
}
/**
* Get all of the relation results for a type.
*
* @param string $type
* @return \Illuminate\Database\Eloquent\Collection
*/
protected function getResultsByType($type)
{
$instance = $this->createModelByType($type);
$key = $instance->getTable().'.'.$instance->getKeyName();
$query = $this->replayMacros($instance->newQuery())
->mergeModelDefinedRelationConstraints($this->getQuery())
->with($this->getQuery()->getEagerLoads());
return $query->whereIn($key, $this->gatherKeysByType($type)->all())->get();
}
/**
* Gather all of the foreign keys for a given type.
*
* @param string $type
* @return array
*/
protected function gatherKeysByType($type)
{
$foreign = $this->foreignKey;
return collect($this->dictionary[$type])->map(function ($models) use ($foreign) {
return head($models)->{$foreign};
})->values()->unique();
}
/**
* Create a new model instance by type.
*
* @param string $type
* @return \Illuminate\Database\Eloquent\Model
*/
public function createModelByType($type)
{
$class = $this->parent->getActualClassNameForMorph($type);
return new $class;
}
/**
* Get the foreign key "type" name.
*
* @return string
*/
public function getMorphType()
{
return $this->morphType;
}
/**
* Get the dictionary used by the relationship.
*
* @return array
*/
public function getDictionary()
{
return $this->dictionary;
}
/**
* Replay stored macro calls on the actual related instance.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @return \Illuminate\Database\Eloquent\Builder
*/
protected function replayMacros(Builder $query)
{
foreach ($this->macroBuffer as $macro) {
call_user_func_array([$query, $macro['method']], $macro['parameters']);
}
return $query;
}
/**
* Handle dynamic method calls to the relationship.
*
* @param string $method
* @param array $parameters
* @return mixed
*/
public function __call($method, $parameters)
{
try {
return parent::__call($method, $parameters);
}
// If we tried to call a method that does not exist on the parent Builder instance,
// we'll assume that we want to call a query macro (e.g. withTrashed) that only
// exists on related models. We will just store the call and replay it later.
catch (BadMethodCallException $e) {
$this->macroBuffer[] = compact('method', 'parameters');
return $this;
}
}
}
Eloquent/Relations/Pivot.php 0000666 00000011153 13436755161 0012132 0 ustar 00 setTable($table);
$this->setConnection($parent->getConnectionName());
$this->forceFill($attributes);
$this->syncOriginal();
// We store off the parent instance so we will access the timestamp column names
// for the model, since the pivot model timestamps aren't easily configurable
// from the developer's point of view. We can use the parents to get these.
$this->parent = $parent;
$this->exists = $exists;
$this->timestamps = $this->hasTimestampAttributes();
}
/**
* Create a new pivot model from raw values returned from a query.
*
* @param \Illuminate\Database\Eloquent\Model $parent
* @param array $attributes
* @param string $table
* @param bool $exists
* @return static
*/
public static function fromRawAttributes(Model $parent, $attributes, $table, $exists = false)
{
$instance = new static($parent, $attributes, $table, $exists);
$instance->setRawAttributes($attributes, true);
return $instance;
}
/**
* Set the keys for a save update query.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @return \Illuminate\Database\Eloquent\Builder
*/
protected function setKeysForSaveQuery(Builder $query)
{
$query->where($this->foreignKey, $this->getAttribute($this->foreignKey));
return $query->where($this->otherKey, $this->getAttribute($this->otherKey));
}
/**
* Delete the pivot model record from the database.
*
* @return int
*/
public function delete()
{
return $this->getDeleteQuery()->delete();
}
/**
* Get the query builder for a delete operation on the pivot.
*
* @return \Illuminate\Database\Eloquent\Builder
*/
protected function getDeleteQuery()
{
$foreign = $this->getAttribute($this->foreignKey);
$query = $this->newQuery()->where($this->foreignKey, $foreign);
return $query->where($this->otherKey, $this->getAttribute($this->otherKey));
}
/**
* Get the foreign key column name.
*
* @return string
*/
public function getForeignKey()
{
return $this->foreignKey;
}
/**
* Get the "other key" column name.
*
* @return string
*/
public function getOtherKey()
{
return $this->otherKey;
}
/**
* Set the key names for the pivot model instance.
*
* @param string $foreignKey
* @param string $otherKey
* @return $this
*/
public function setPivotKeys($foreignKey, $otherKey)
{
$this->foreignKey = $foreignKey;
$this->otherKey = $otherKey;
return $this;
}
/**
* Determine if the pivot model has timestamp attributes.
*
* @return bool
*/
public function hasTimestampAttributes()
{
return array_key_exists($this->getCreatedAtColumn(), $this->attributes);
}
/**
* Get the name of the "created at" column.
*
* @return string
*/
public function getCreatedAtColumn()
{
return $this->parent->getCreatedAtColumn();
}
/**
* Get the name of the "updated at" column.
*
* @return string
*/
public function getUpdatedAtColumn()
{
return $this->parent->getUpdatedAtColumn();
}
}
Eloquent/Relations/HasManyThrough.php 0000666 00000026531 13436755161 0013740 0 ustar 00 localKey = $localKey;
$this->firstKey = $firstKey;
$this->secondKey = $secondKey;
$this->farParent = $farParent;
parent::__construct($query, $parent);
}
/**
* Set the base constraints on the relation query.
*
* @return void
*/
public function addConstraints()
{
$parentTable = $this->parent->getTable();
$localValue = $this->farParent[$this->localKey];
$this->setJoin();
if (static::$constraints) {
$this->query->where($parentTable.'.'.$this->firstKey, '=', $localValue);
}
}
/**
* Add the constraints for a relationship query.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param \Illuminate\Database\Eloquent\Builder $parent
* @param array|mixed $columns
* @return \Illuminate\Database\Eloquent\Builder
*/
public function getRelationQuery(Builder $query, Builder $parent, $columns = ['*'])
{
$parentTable = $this->parent->getTable();
$this->setJoin($query);
$query->select($columns);
$key = $this->wrap($parentTable.'.'.$this->firstKey);
return $query->where($this->getHasCompareKey(), '=', new Expression($key));
}
/**
* Set the join clause on the query.
*
* @param \Illuminate\Database\Eloquent\Builder|null $query
* @return void
*/
protected function setJoin(Builder $query = null)
{
$query = $query ?: $this->query;
$foreignKey = $this->related->getTable().'.'.$this->secondKey;
$query->join($this->parent->getTable(), $this->getQualifiedParentKeyName(), '=', $foreignKey);
if ($this->parentSoftDeletes()) {
$query->whereNull($this->parent->getQualifiedDeletedAtColumn());
}
}
/**
* Determine whether close parent of the relation uses Soft Deletes.
*
* @return bool
*/
public function parentSoftDeletes()
{
return in_array(SoftDeletes::class, class_uses_recursive(get_class($this->parent)));
}
/**
* Set the constraints for an eager load of the relation.
*
* @param array $models
* @return void
*/
public function addEagerConstraints(array $models)
{
$table = $this->parent->getTable();
$this->query->whereIn($table.'.'.$this->firstKey, $this->getKeys($models));
}
/**
* Initialize the relation on a set of models.
*
* @param array $models
* @param string $relation
* @return array
*/
public function initRelation(array $models, $relation)
{
foreach ($models as $model) {
$model->setRelation($relation, $this->related->newCollection());
}
return $models;
}
/**
* Match the eagerly loaded results to their parents.
*
* @param array $models
* @param \Illuminate\Database\Eloquent\Collection $results
* @param string $relation
* @return array
*/
public function match(array $models, Collection $results, $relation)
{
$dictionary = $this->buildDictionary($results);
// Once we have the dictionary we can simply spin through the parent models to
// link them up with their children using the keyed dictionary to make the
// matching very convenient and easy work. Then we'll just return them.
foreach ($models as $model) {
$key = $model->getKey();
if (isset($dictionary[$key])) {
$value = $this->related->newCollection($dictionary[$key]);
$model->setRelation($relation, $value);
}
}
return $models;
}
/**
* Build model dictionary keyed by the relation's foreign key.
*
* @param \Illuminate\Database\Eloquent\Collection $results
* @return array
*/
protected function buildDictionary(Collection $results)
{
$dictionary = [];
$foreign = $this->firstKey;
// First we will create a dictionary of models keyed by the foreign key of the
// relationship as this will allow us to quickly access all of the related
// models without having to do nested looping which will be quite slow.
foreach ($results as $result) {
$dictionary[$result->{$foreign}][] = $result;
}
return $dictionary;
}
/**
* Get the results of the relationship.
*
* @return mixed
*/
public function getResults()
{
return $this->get();
}
/**
* Execute the query and get the first related model.
*
* @param array $columns
* @return mixed
*/
public function first($columns = ['*'])
{
$results = $this->take(1)->get($columns);
return count($results) > 0 ? $results->first() : null;
}
/**
* Execute the query and get the first result or throw an exception.
*
* @param array $columns
* @return \Illuminate\Database\Eloquent\Model|static
*
* @throws \Illuminate\Database\Eloquent\ModelNotFoundException
*/
public function firstOrFail($columns = ['*'])
{
if (! is_null($model = $this->first($columns))) {
return $model;
}
throw (new ModelNotFoundException)->setModel(get_class($this->parent));
}
/**
* Find a related model by its primary key.
*
* @param mixed $id
* @param array $columns
* @return \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Collection|null
*/
public function find($id, $columns = ['*'])
{
if (is_array($id)) {
return $this->findMany($id, $columns);
}
$this->where($this->getRelated()->getQualifiedKeyName(), '=', $id);
return $this->first($columns);
}
/**
* Find multiple related models by their primary keys.
*
* @param mixed $ids
* @param array $columns
* @return \Illuminate\Database\Eloquent\Collection
*/
public function findMany($ids, $columns = ['*'])
{
if (empty($ids)) {
return $this->getRelated()->newCollection();
}
$this->whereIn($this->getRelated()->getQualifiedKeyName(), $ids);
return $this->get($columns);
}
/**
* Find a related model by its primary key or throw an exception.
*
* @param mixed $id
* @param array $columns
* @return \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Collection
*
* @throws \Illuminate\Database\Eloquent\ModelNotFoundException
*/
public function findOrFail($id, $columns = ['*'])
{
$result = $this->find($id, $columns);
if (is_array($id)) {
if (count($result) == count(array_unique($id))) {
return $result;
}
} elseif (! is_null($result)) {
return $result;
}
throw (new ModelNotFoundException)->setModel(get_class($this->parent));
}
/**
* Execute the query as a "select" statement.
*
* @param array $columns
* @return \Illuminate\Database\Eloquent\Collection
*/
public function get($columns = ['*'])
{
// First we'll add the proper select columns onto the query so it is run with
// the proper columns. Then, we will get the results and hydrate out pivot
// models with the result of those columns as a separate model relation.
$columns = $this->query->getQuery()->columns ? [] : $columns;
$select = $this->getSelectColumns($columns);
$builder = $this->query->applyScopes();
$models = $builder->addSelect($select)->getModels();
// If we actually found models we will also eager load any relationships that
// have been specified as needing to be eager loaded. This will solve the
// n + 1 query problem for the developer and also increase performance.
if (count($models) > 0) {
$models = $builder->eagerLoadRelations($models);
}
return $this->related->newCollection($models);
}
/**
* Set the select clause for the relation query.
*
* @param array $columns
* @return array
*/
protected function getSelectColumns(array $columns = ['*'])
{
if ($columns == ['*']) {
$columns = [$this->related->getTable().'.*'];
}
return array_merge($columns, [$this->parent->getTable().'.'.$this->firstKey]);
}
/**
* Get a paginator for the "select" statement.
*
* @param int $perPage
* @param array $columns
* @param string $pageName
* @param int $page
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
*/
public function paginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null)
{
$this->query->addSelect($this->getSelectColumns($columns));
return $this->query->paginate($perPage, $columns, $pageName, $page);
}
/**
* Paginate the given query into a simple paginator.
*
* @param int $perPage
* @param array $columns
* @param string $pageName
* @return \Illuminate\Contracts\Pagination\Paginator
*/
public function simplePaginate($perPage = null, $columns = ['*'], $pageName = 'page')
{
$this->query->addSelect($this->getSelectColumns($columns));
return $this->query->simplePaginate($perPage, $columns, $pageName);
}
/**
* Get the key for comparing against the parent key in "has" query.
*
* @return string
*/
public function getHasCompareKey()
{
return $this->farParent->getQualifiedKeyName();
}
/**
* Get the qualified foreign key on the related model.
*
* @return string
*/
public function getForeignKey()
{
return $this->related->getTable().'.'.$this->secondKey;
}
/**
* Get the qualified foreign key on the "through" model.
*
* @return string
*/
public function getThroughKey()
{
return $this->parent->getTable().'.'.$this->firstKey;
}
}
Eloquent/Relations/HasOneOrMany.php 0000666 00000026141 13436755161 0013337 0 ustar 00 localKey = $localKey;
$this->foreignKey = $foreignKey;
parent::__construct($query, $parent);
}
/**
* Set the base constraints on the relation query.
*
* @return void
*/
public function addConstraints()
{
if (static::$constraints) {
$this->query->where($this->foreignKey, '=', $this->getParentKey());
$this->query->whereNotNull($this->foreignKey);
}
}
/**
* Add the constraints for a relationship query.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param \Illuminate\Database\Eloquent\Builder $parent
* @param array|mixed $columns
* @return \Illuminate\Database\Eloquent\Builder
*/
public function getRelationQuery(Builder $query, Builder $parent, $columns = ['*'])
{
if ($parent->getQuery()->from == $query->getQuery()->from) {
return $this->getRelationQueryForSelfRelation($query, $parent, $columns);
}
return parent::getRelationQuery($query, $parent, $columns);
}
/**
* Add the constraints for a relationship query on the same table.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param \Illuminate\Database\Eloquent\Builder $parent
* @param array|mixed $columns
* @return \Illuminate\Database\Eloquent\Builder
*/
public function getRelationQueryForSelfRelation(Builder $query, Builder $parent, $columns = ['*'])
{
$query->select($columns);
$query->from($query->getModel()->getTable().' as '.$hash = $this->getRelationCountHash());
$query->getModel()->setTable($hash);
$key = $this->wrap($this->getQualifiedParentKeyName());
return $query->where($hash.'.'.$this->getPlainForeignKey(), '=', new Expression($key));
}
/**
* Get a relationship join table hash.
*
* @return string
*/
public function getRelationCountHash()
{
return 'laravel_reserved_'.static::$selfJoinCount++;
}
/**
* Set the constraints for an eager load of the relation.
*
* @param array $models
* @return void
*/
public function addEagerConstraints(array $models)
{
$this->query->whereIn($this->foreignKey, $this->getKeys($models, $this->localKey));
}
/**
* Match the eagerly loaded results to their single parents.
*
* @param array $models
* @param \Illuminate\Database\Eloquent\Collection $results
* @param string $relation
* @return array
*/
public function matchOne(array $models, Collection $results, $relation)
{
return $this->matchOneOrMany($models, $results, $relation, 'one');
}
/**
* Match the eagerly loaded results to their many parents.
*
* @param array $models
* @param \Illuminate\Database\Eloquent\Collection $results
* @param string $relation
* @return array
*/
public function matchMany(array $models, Collection $results, $relation)
{
return $this->matchOneOrMany($models, $results, $relation, 'many');
}
/**
* Match the eagerly loaded results to their many parents.
*
* @param array $models
* @param \Illuminate\Database\Eloquent\Collection $results
* @param string $relation
* @param string $type
* @return array
*/
protected function matchOneOrMany(array $models, Collection $results, $relation, $type)
{
$dictionary = $this->buildDictionary($results);
// Once we have the dictionary we can simply spin through the parent models to
// link them up with their children using the keyed dictionary to make the
// matching very convenient and easy work. Then we'll just return them.
foreach ($models as $model) {
$key = $model->getAttribute($this->localKey);
if (isset($dictionary[$key])) {
$value = $this->getRelationValue($dictionary, $key, $type);
$model->setRelation($relation, $value);
}
}
return $models;
}
/**
* Get the value of a relationship by one or many type.
*
* @param array $dictionary
* @param string $key
* @param string $type
* @return mixed
*/
protected function getRelationValue(array $dictionary, $key, $type)
{
$value = $dictionary[$key];
return $type == 'one' ? reset($value) : $this->related->newCollection($value);
}
/**
* Build model dictionary keyed by the relation's foreign key.
*
* @param \Illuminate\Database\Eloquent\Collection $results
* @return array
*/
protected function buildDictionary(Collection $results)
{
$dictionary = [];
$foreign = $this->getPlainForeignKey();
// First we will create a dictionary of models keyed by the foreign key of the
// relationship as this will allow us to quickly access all of the related
// models without having to do nested looping which will be quite slow.
foreach ($results as $result) {
$dictionary[$result->{$foreign}][] = $result;
}
return $dictionary;
}
/**
* Attach a model instance to the parent model.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @return \Illuminate\Database\Eloquent\Model
*/
public function save(Model $model)
{
$model->setAttribute($this->getPlainForeignKey(), $this->getParentKey());
return $model->save() ? $model : false;
}
/**
* Attach a collection of models to the parent instance.
*
* @param \Traversable|array $models
* @return \Traversable|array
*/
public function saveMany($models)
{
foreach ($models as $model) {
$this->save($model);
}
return $models;
}
/**
* Find a model by its primary key or return new instance of the related model.
*
* @param mixed $id
* @param array $columns
* @return \Illuminate\Support\Collection|\Illuminate\Database\Eloquent\Model
*/
public function findOrNew($id, $columns = ['*'])
{
if (is_null($instance = $this->find($id, $columns))) {
$instance = $this->related->newInstance();
$instance->setAttribute($this->getPlainForeignKey(), $this->getParentKey());
}
return $instance;
}
/**
* Get the first related model record matching the attributes or instantiate it.
*
* @param array $attributes
* @return \Illuminate\Database\Eloquent\Model
*/
public function firstOrNew(array $attributes)
{
if (is_null($instance = $this->where($attributes)->first())) {
$instance = $this->related->newInstance($attributes);
$instance->setAttribute($this->getPlainForeignKey(), $this->getParentKey());
}
return $instance;
}
/**
* Get the first related record matching the attributes or create it.
*
* @param array $attributes
* @return \Illuminate\Database\Eloquent\Model
*/
public function firstOrCreate(array $attributes)
{
if (is_null($instance = $this->where($attributes)->first())) {
$instance = $this->create($attributes);
}
return $instance;
}
/**
* Create or update a related record matching the attributes, and fill it with values.
*
* @param array $attributes
* @param array $values
* @return \Illuminate\Database\Eloquent\Model
*/
public function updateOrCreate(array $attributes, array $values = [])
{
$instance = $this->firstOrNew($attributes);
$instance->fill($values);
$instance->save();
return $instance;
}
/**
* Create a new instance of the related model.
*
* @param array $attributes
* @return \Illuminate\Database\Eloquent\Model
*/
public function create(array $attributes)
{
// Here we will set the raw attributes to avoid hitting the "fill" method so
// that we do not have to worry about a mass accessor rules blocking sets
// on the models. Otherwise, some of these attributes will not get set.
$instance = $this->related->newInstance($attributes);
$instance->setAttribute($this->getPlainForeignKey(), $this->getParentKey());
$instance->save();
return $instance;
}
/**
* Create an array of new instances of the related model.
*
* @param array $records
* @return array
*/
public function createMany(array $records)
{
$instances = [];
foreach ($records as $record) {
$instances[] = $this->create($record);
}
return $instances;
}
/**
* Perform an update on all the related models.
*
* @param array $attributes
* @return int
*/
public function update(array $attributes)
{
if ($this->related->usesTimestamps()) {
$attributes[$this->relatedUpdatedAt()] = $this->related->freshTimestampString();
}
return $this->query->update($attributes);
}
/**
* Get the key for comparing against the parent key in "has" query.
*
* @return string
*/
public function getHasCompareKey()
{
return $this->getForeignKey();
}
/**
* Get the foreign key for the relationship.
*
* @return string
*/
public function getForeignKey()
{
return $this->foreignKey;
}
/**
* Get the plain foreign key.
*
* @return string
*/
public function getPlainForeignKey()
{
$segments = explode('.', $this->getForeignKey());
return $segments[count($segments) - 1];
}
/**
* Get the key value of the parent's local key.
*
* @return mixed
*/
public function getParentKey()
{
return $this->parent->getAttribute($this->localKey);
}
/**
* Get the fully qualified parent key name.
*
* @return string
*/
public function getQualifiedParentKeyName()
{
return $this->parent->getTable().'.'.$this->localKey;
}
}
Eloquent/Relations/Relation.php 0000666 00000021056 13436755161 0012611 0 ustar 00 query = $query;
$this->parent = $parent;
$this->related = $query->getModel();
$this->addConstraints();
}
/**
* Set the base constraints on the relation query.
*
* @return void
*/
abstract public function addConstraints();
/**
* Set the constraints for an eager load of the relation.
*
* @param array $models
* @return void
*/
abstract public function addEagerConstraints(array $models);
/**
* Initialize the relation on a set of models.
*
* @param array $models
* @param string $relation
* @return array
*/
abstract public function initRelation(array $models, $relation);
/**
* Match the eagerly loaded results to their parents.
*
* @param array $models
* @param \Illuminate\Database\Eloquent\Collection $results
* @param string $relation
* @return array
*/
abstract public function match(array $models, Collection $results, $relation);
/**
* Get the results of the relationship.
*
* @return mixed
*/
abstract public function getResults();
/**
* Get the relationship for eager loading.
*
* @return \Illuminate\Database\Eloquent\Collection
*/
public function getEager()
{
return $this->get();
}
/**
* Touch all of the related models for the relationship.
*
* @return void
*/
public function touch()
{
$column = $this->getRelated()->getUpdatedAtColumn();
$this->rawUpdate([$column => $this->getRelated()->freshTimestampString()]);
}
/**
* Run a raw update against the base query.
*
* @param array $attributes
* @return int
*/
public function rawUpdate(array $attributes = [])
{
return $this->query->update($attributes);
}
/**
* Add the constraints for a relationship count query.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param \Illuminate\Database\Eloquent\Builder $parent
* @return \Illuminate\Database\Eloquent\Builder
*/
public function getRelationCountQuery(Builder $query, Builder $parent)
{
return $this->getRelationQuery($query, $parent, new Expression('count(*)'));
}
/**
* Add the constraints for a relationship query.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param \Illuminate\Database\Eloquent\Builder $parent
* @param array|mixed $columns
* @return \Illuminate\Database\Eloquent\Builder
*/
public function getRelationQuery(Builder $query, Builder $parent, $columns = ['*'])
{
$query->select($columns);
$key = $this->wrap($this->getQualifiedParentKeyName());
return $query->where($this->getHasCompareKey(), '=', new Expression($key));
}
/**
* Run a callback with constraints disabled on the relation.
*
* @param \Closure $callback
* @return mixed
*/
public static function noConstraints(Closure $callback)
{
$previous = static::$constraints;
static::$constraints = false;
// When resetting the relation where clause, we want to shift the first element
// off of the bindings, leaving only the constraints that the developers put
// as "extra" on the relationships, and not original relation constraints.
try {
$results = call_user_func($callback);
} finally {
static::$constraints = $previous;
}
return $results;
}
/**
* Get all of the primary keys for an array of models.
*
* @param array $models
* @param string $key
* @return array
*/
protected function getKeys(array $models, $key = null)
{
return array_unique(array_values(array_map(function ($value) use ($key) {
return $key ? $value->getAttribute($key) : $value->getKey();
}, $models)));
}
/**
* Get the underlying query for the relation.
*
* @return \Illuminate\Database\Eloquent\Builder
*/
public function getQuery()
{
return $this->query;
}
/**
* Get the base query builder driving the Eloquent builder.
*
* @return \Illuminate\Database\Query\Builder
*/
public function getBaseQuery()
{
return $this->query->getQuery();
}
/**
* Get the parent model of the relation.
*
* @return \Illuminate\Database\Eloquent\Model
*/
public function getParent()
{
return $this->parent;
}
/**
* Get the fully qualified parent key name.
*
* @return string
*/
public function getQualifiedParentKeyName()
{
return $this->parent->getQualifiedKeyName();
}
/**
* Get the related model of the relation.
*
* @return \Illuminate\Database\Eloquent\Model
*/
public function getRelated()
{
return $this->related;
}
/**
* Get the name of the "created at" column.
*
* @return string
*/
public function createdAt()
{
return $this->parent->getCreatedAtColumn();
}
/**
* Get the name of the "updated at" column.
*
* @return string
*/
public function updatedAt()
{
return $this->parent->getUpdatedAtColumn();
}
/**
* Get the name of the related model's "updated at" column.
*
* @return string
*/
public function relatedUpdatedAt()
{
return $this->related->getUpdatedAtColumn();
}
/**
* Wrap the given value with the parent query's grammar.
*
* @param string $value
* @return string
*/
public function wrap($value)
{
return $this->parent->newQueryWithoutScopes()->getQuery()->getGrammar()->wrap($value);
}
/**
* Set or get the morph map for polymorphic relations.
*
* @param array|null $map
* @param bool $merge
* @return array
*/
public static function morphMap(array $map = null, $merge = true)
{
$map = static::buildMorphMapFromModels($map);
if (is_array($map)) {
static::$morphMap = $merge ? array_merge(static::$morphMap, $map) : $map;
}
return static::$morphMap;
}
/**
* Builds a table-keyed array from model class names.
*
* @param string[]|null $models
* @return array|null
*/
protected static function buildMorphMapFromModels(array $models = null)
{
if (is_null($models) || Arr::isAssoc($models)) {
return $models;
}
$tables = array_map(function ($model) {
return (new $model)->getTable();
}, $models);
return array_combine($tables, $models);
}
/**
* Handle dynamic method calls to the relationship.
*
* @param string $method
* @param array $parameters
* @return mixed
*/
public function __call($method, $parameters)
{
$result = call_user_func_array([$this->query, $method], $parameters);
if ($result === $this->query) {
return $this;
}
return $result;
}
/**
* Force a clone of the underlying query builder when cloning.
*
* @return void
*/
public function __clone()
{
$this->query = clone $this->query;
}
}
Eloquent/SoftDeletingScope.php 0000666 00000007461 13436755161 0012461 0 ustar 00 whereNull($model->getQualifiedDeletedAtColumn());
}
/**
* Extend the query builder with the needed functions.
*
* @param \Illuminate\Database\Eloquent\Builder $builder
* @return void
*/
public function extend(Builder $builder)
{
foreach ($this->extensions as $extension) {
$this->{"add{$extension}"}($builder);
}
$builder->onDelete(function (Builder $builder) {
$column = $this->getDeletedAtColumn($builder);
return $builder->update([
$column => $builder->getModel()->freshTimestampString(),
]);
});
}
/**
* Get the "deleted at" column for the builder.
*
* @param \Illuminate\Database\Eloquent\Builder $builder
* @return string
*/
protected function getDeletedAtColumn(Builder $builder)
{
if (count($builder->getQuery()->joins) > 0) {
return $builder->getModel()->getQualifiedDeletedAtColumn();
} else {
return $builder->getModel()->getDeletedAtColumn();
}
}
/**
* Add the force delete extension to the builder.
*
* @param \Illuminate\Database\Eloquent\Builder $builder
* @return void
*/
protected function addForceDelete(Builder $builder)
{
$builder->macro('forceDelete', function (Builder $builder) {
return $builder->getQuery()->delete();
});
}
/**
* Add the restore extension to the builder.
*
* @param \Illuminate\Database\Eloquent\Builder $builder
* @return void
*/
protected function addRestore(Builder $builder)
{
$builder->macro('restore', function (Builder $builder) {
$builder->withTrashed();
return $builder->update([$builder->getModel()->getDeletedAtColumn() => null]);
});
}
/**
* Add the with-trashed extension to the builder.
*
* @param \Illuminate\Database\Eloquent\Builder $builder
* @return void
*/
protected function addWithTrashed(Builder $builder)
{
$builder->macro('withTrashed', function (Builder $builder) {
return $builder->withoutGlobalScope($this);
});
}
/**
* Add the without-trashed extension to the builder.
*
* @param \Illuminate\Database\Eloquent\Builder $builder
* @return void
*/
protected function addWithoutTrashed(Builder $builder)
{
$builder->macro('withoutTrashed', function (Builder $builder) {
$model = $builder->getModel();
$builder->withoutGlobalScope($this)->whereNull(
$model->getQualifiedDeletedAtColumn()
);
return $builder;
});
}
/**
* Add the only-trashed extension to the builder.
*
* @param \Illuminate\Database\Eloquent\Builder $builder
* @return void
*/
protected function addOnlyTrashed(Builder $builder)
{
$builder->macro('onlyTrashed', function (Builder $builder) {
$model = $builder->getModel();
$builder->withoutGlobalScope($this)->whereNotNull(
$model->getQualifiedDeletedAtColumn()
);
return $builder;
});
}
}
Eloquent/ModelNotFoundException.php 0000666 00000001252 13436755161 0013464 0 ustar 00 model = $model;
$this->message = "No query results for model [{$model}].";
return $this;
}
/**
* Get the affected Eloquent model.
*
* @return string
*/
public function getModel()
{
return $this->model;
}
}
Eloquent/FactoryBuilder.php 0000666 00000007151 13436755161 0012012 0 ustar 00 name = $name;
$this->class = $class;
$this->faker = $faker;
$this->definitions = $definitions;
}
/**
* Set the amount of models you wish to create / make.
*
* @param int $amount
* @return $this
*/
public function times($amount)
{
$this->amount = $amount;
return $this;
}
/**
* Create a collection of models and persist them to the database.
*
* @param array $attributes
* @return mixed
*/
public function create(array $attributes = [])
{
$results = $this->make($attributes);
if ($this->amount === 1) {
$results->save();
} else {
foreach ($results as $result) {
$result->save();
}
}
return $results;
}
/**
* Create a collection of models.
*
* @param array $attributes
* @return mixed
*/
public function make(array $attributes = [])
{
if ($this->amount === 1) {
return $this->makeInstance($attributes);
} else {
$results = [];
for ($i = 0; $i < $this->amount; $i++) {
$results[] = $this->makeInstance($attributes);
}
return new Collection($results);
}
}
/**
* Make an instance of the model with the given attributes.
*
* @param array $attributes
* @return \Illuminate\Database\Eloquent\Model
*
* @throws \InvalidArgumentException
*/
protected function makeInstance(array $attributes = [])
{
return Model::unguarded(function () use ($attributes) {
if (! isset($this->definitions[$this->class][$this->name])) {
throw new InvalidArgumentException("Unable to locate factory with name [{$this->name}] [{$this->class}].");
}
$definition = call_user_func(
$this->definitions[$this->class][$this->name],
$this->faker, $attributes
);
$evaluated = $this->callClosureAttributes(
array_merge($definition, $attributes)
);
return new $this->class($evaluated);
});
}
/**
* Evaluate any Closure attributes on the attribute array.
*
* @param array $attributes
* @return array
*/
protected function callClosureAttributes(array $attributes)
{
foreach ($attributes as &$attribute) {
$attribute = $attribute instanceof Closure
? $attribute($attributes) : $attribute;
}
return $attributes;
}
}
Eloquent/Model.php 0000666 00000270575 13436755161 0010150 0 ustar 00 bootIfNotBooted();
$this->syncOriginal();
$this->fill($attributes);
}
/**
* Check if the model needs to be booted and if so, do it.
*
* @return void
*/
protected function bootIfNotBooted()
{
if (! isset(static::$booted[static::class])) {
static::$booted[static::class] = true;
$this->fireModelEvent('booting', false);
static::boot();
$this->fireModelEvent('booted', false);
}
}
/**
* The "booting" method of the model.
*
* @return void
*/
protected static function boot()
{
static::bootTraits();
}
/**
* Boot all of the bootable traits on the model.
*
* @return void
*/
protected static function bootTraits()
{
$class = static::class;
foreach (class_uses_recursive($class) as $trait) {
if (method_exists($class, $method = 'boot'.class_basename($trait))) {
forward_static_call([$class, $method]);
}
}
}
/**
* Clear the list of booted models so they will be re-booted.
*
* @return void
*/
public static function clearBootedModels()
{
static::$booted = [];
static::$globalScopes = [];
}
/**
* Register a new global scope on the model.
*
* @param \Illuminate\Database\Eloquent\Scope|\Closure|string $scope
* @param \Closure|null $implementation
* @return mixed
*
* @throws \InvalidArgumentException
*/
public static function addGlobalScope($scope, Closure $implementation = null)
{
if (is_string($scope) && $implementation !== null) {
return static::$globalScopes[static::class][$scope] = $implementation;
}
if ($scope instanceof Closure) {
return static::$globalScopes[static::class][spl_object_hash($scope)] = $scope;
}
if ($scope instanceof Scope) {
return static::$globalScopes[static::class][get_class($scope)] = $scope;
}
throw new InvalidArgumentException('Global scope must be an instance of Closure or Scope.');
}
/**
* Determine if a model has a global scope.
*
* @param \Illuminate\Database\Eloquent\Scope|string $scope
* @return bool
*/
public static function hasGlobalScope($scope)
{
return ! is_null(static::getGlobalScope($scope));
}
/**
* Get a global scope registered with the model.
*
* @param \Illuminate\Database\Eloquent\Scope|string $scope
* @return \Illuminate\Database\Eloquent\Scope|\Closure|null
*/
public static function getGlobalScope($scope)
{
if (! is_string($scope)) {
$scope = get_class($scope);
}
return Arr::get(static::$globalScopes, static::class.'.'.$scope);
}
/**
* Get the global scopes for this class instance.
*
* @return array
*/
public function getGlobalScopes()
{
return Arr::get(static::$globalScopes, static::class, []);
}
/**
* Register an observer with the Model.
*
* @param object|string $class
* @param int $priority
* @return void
*/
public static function observe($class, $priority = 0)
{
$instance = new static;
$className = is_string($class) ? $class : get_class($class);
// When registering a model observer, we will spin through the possible events
// and determine if this observer has that method. If it does, we will hook
// it into the model's event system, making it convenient to watch these.
foreach ($instance->getObservableEvents() as $event) {
if (method_exists($class, $event)) {
static::registerModelEvent($event, $className.'@'.$event, $priority);
}
}
}
/**
* Fill the model with an array of attributes.
*
* @param array $attributes
* @return $this
*
* @throws \Illuminate\Database\Eloquent\MassAssignmentException
*/
public function fill(array $attributes)
{
$totallyGuarded = $this->totallyGuarded();
foreach ($this->fillableFromArray($attributes) as $key => $value) {
$key = $this->removeTableFromKey($key);
// The developers may choose to place some attributes in the "fillable"
// array, which means only those attributes may be set through mass
// assignment to the model, and all others will just be ignored.
if ($this->isFillable($key)) {
$this->setAttribute($key, $value);
} elseif ($totallyGuarded) {
throw new MassAssignmentException($key);
}
}
return $this;
}
/**
* Fill the model with an array of attributes. Force mass assignment.
*
* @param array $attributes
* @return $this
*/
public function forceFill(array $attributes)
{
// Since some versions of PHP have a bug that prevents it from properly
// binding the late static context in a closure, we will first store
// the model in a variable, which we will then use in the closure.
$model = $this;
return static::unguarded(function () use ($model, $attributes) {
return $model->fill($attributes);
});
}
/**
* Get the fillable attributes of a given array.
*
* @param array $attributes
* @return array
*/
protected function fillableFromArray(array $attributes)
{
if (count($this->getFillable()) > 0 && ! static::$unguarded) {
return array_intersect_key($attributes, array_flip($this->getFillable()));
}
return $attributes;
}
/**
* Create a new instance of the given model.
*
* @param array $attributes
* @param bool $exists
* @return static
*/
public function newInstance($attributes = [], $exists = false)
{
// This method just provides a convenient way for us to generate fresh model
// instances of this current model. It is particularly useful during the
// hydration of new objects via the Eloquent query builder instances.
$model = new static((array) $attributes);
$model->exists = $exists;
return $model;
}
/**
* Create a new model instance that is existing.
*
* @param array $attributes
* @param string|null $connection
* @return static
*/
public function newFromBuilder($attributes = [], $connection = null)
{
$model = $this->newInstance([], true);
$model->setRawAttributes((array) $attributes, true);
$model->setConnection($connection ?: $this->getConnectionName());
return $model;
}
/**
* Create a collection of models from plain arrays.
*
* @param array $items
* @param string|null $connection
* @return \Illuminate\Database\Eloquent\Collection
*/
public static function hydrate(array $items, $connection = null)
{
$instance = (new static)->setConnection($connection);
$items = array_map(function ($item) use ($instance) {
return $instance->newFromBuilder($item);
}, $items);
return $instance->newCollection($items);
}
/**
* Create a collection of models from a raw query.
*
* @param string $query
* @param array $bindings
* @param string|null $connection
* @return \Illuminate\Database\Eloquent\Collection
*/
public static function hydrateRaw($query, $bindings = [], $connection = null)
{
$instance = (new static)->setConnection($connection);
$items = $instance->getConnection()->select($query, $bindings);
return static::hydrate($items, $connection);
}
/**
* Save a new model and return the instance.
*
* @param array $attributes
* @return static
*/
public static function create(array $attributes = [])
{
$model = new static($attributes);
$model->save();
return $model;
}
/**
* Save a new model and return the instance. Allow mass-assignment.
*
* @param array $attributes
* @return static
*/
public static function forceCreate(array $attributes)
{
// Since some versions of PHP have a bug that prevents it from properly
// binding the late static context in a closure, we will first store
// the model in a variable, which we will then use in the closure.
$model = new static;
return static::unguarded(function () use ($model, $attributes) {
return $model->create($attributes);
});
}
/**
* Begin querying the model.
*
* @return \Illuminate\Database\Eloquent\Builder
*/
public static function query()
{
return (new static)->newQuery();
}
/**
* Begin querying the model on a given connection.
*
* @param string|null $connection
* @return \Illuminate\Database\Eloquent\Builder
*/
public static function on($connection = null)
{
// First we will just create a fresh instance of this model, and then we can
// set the connection on the model so that it is be used for the queries
// we execute, as well as being set on each relationship we retrieve.
$instance = new static;
$instance->setConnection($connection);
return $instance->newQuery();
}
/**
* Begin querying the model on the write connection.
*
* @return \Illuminate\Database\Query\Builder
*/
public static function onWriteConnection()
{
$instance = new static;
return $instance->newQuery()->useWritePdo();
}
/**
* Get all of the models from the database.
*
* @param array|mixed $columns
* @return \Illuminate\Database\Eloquent\Collection|static[]
*/
public static function all($columns = ['*'])
{
$columns = is_array($columns) ? $columns : func_get_args();
$instance = new static;
return $instance->newQuery()->get($columns);
}
/**
* Reload a fresh model instance from the database.
*
* @param array|string $with
* @return $this|null
*/
public function fresh($with = [])
{
if (! $this->exists) {
return;
}
if (is_string($with)) {
$with = func_get_args();
}
$key = $this->getKeyName();
return static::with($with)->where($key, $this->getKey())->first();
}
/**
* Eager load relations on the model.
*
* @param array|string $relations
* @return $this
*/
public function load($relations)
{
if (is_string($relations)) {
$relations = func_get_args();
}
$query = $this->newQuery()->with($relations);
$query->eagerLoadRelations([$this]);
return $this;
}
/**
* Begin querying a model with eager loading.
*
* @param array|string $relations
* @return \Illuminate\Database\Eloquent\Builder|static
*/
public static function with($relations)
{
if (is_string($relations)) {
$relations = func_get_args();
}
$instance = new static;
return $instance->newQuery()->with($relations);
}
/**
* Append attributes to query when building a query.
*
* @param array|string $attributes
* @return $this
*/
public function append($attributes)
{
if (is_string($attributes)) {
$attributes = func_get_args();
}
$this->appends = array_unique(
array_merge($this->appends, $attributes)
);
return $this;
}
/**
* Define a one-to-one relationship.
*
* @param string $related
* @param string $foreignKey
* @param string $localKey
* @return \Illuminate\Database\Eloquent\Relations\HasOne
*/
public function hasOne($related, $foreignKey = null, $localKey = null)
{
$foreignKey = $foreignKey ?: $this->getForeignKey();
$instance = new $related;
$localKey = $localKey ?: $this->getKeyName();
return new HasOne($instance->newQuery(), $this, $instance->getTable().'.'.$foreignKey, $localKey);
}
/**
* Define a polymorphic one-to-one relationship.
*
* @param string $related
* @param string $name
* @param string $type
* @param string $id
* @param string $localKey
* @return \Illuminate\Database\Eloquent\Relations\MorphOne
*/
public function morphOne($related, $name, $type = null, $id = null, $localKey = null)
{
$instance = new $related;
list($type, $id) = $this->getMorphs($name, $type, $id);
$table = $instance->getTable();
$localKey = $localKey ?: $this->getKeyName();
return new MorphOne($instance->newQuery(), $this, $table.'.'.$type, $table.'.'.$id, $localKey);
}
/**
* Define an inverse one-to-one or many relationship.
*
* @param string $related
* @param string $foreignKey
* @param string $otherKey
* @param string $relation
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function belongsTo($related, $foreignKey = null, $otherKey = null, $relation = null)
{
// If no relation name was given, we will use this debug backtrace to extract
// the calling method's name and use that as the relationship name as most
// of the time this will be what we desire to use for the relationships.
if (is_null($relation)) {
list($current, $caller) = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
$relation = $caller['function'];
}
// If no foreign key was supplied, we can use a backtrace to guess the proper
// foreign key name by using the name of the relationship function, which
// when combined with an "_id" should conventionally match the columns.
if (is_null($foreignKey)) {
$foreignKey = Str::snake($relation).'_id';
}
$instance = new $related;
// Once we have the foreign key names, we'll just create a new Eloquent query
// for the related models and returns the relationship instance which will
// actually be responsible for retrieving and hydrating every relations.
$query = $instance->newQuery();
$otherKey = $otherKey ?: $instance->getKeyName();
return new BelongsTo($query, $this, $foreignKey, $otherKey, $relation);
}
/**
* Define a polymorphic, inverse one-to-one or many relationship.
*
* @param string $name
* @param string $type
* @param string $id
* @return \Illuminate\Database\Eloquent\Relations\MorphTo
*/
public function morphTo($name = null, $type = null, $id = null)
{
// If no name is provided, we will use the backtrace to get the function name
// since that is most likely the name of the polymorphic interface. We can
// use that to get both the class and foreign key that will be utilized.
if (is_null($name)) {
list($current, $caller) = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
$name = Str::snake($caller['function']);
}
list($type, $id) = $this->getMorphs($name, $type, $id);
// If the type value is null it is probably safe to assume we're eager loading
// the relationship. In this case we'll just pass in a dummy query where we
// need to remove any eager loads that may already be defined on a model.
if (empty($class = $this->$type)) {
return new MorphTo(
$this->newQuery()->setEagerLoads([]), $this, $id, null, $type, $name
);
}
// If we are not eager loading the relationship we will essentially treat this
// as a belongs-to style relationship since morph-to extends that class and
// we will pass in the appropriate values so that it behaves as expected.
else {
$class = $this->getActualClassNameForMorph($class);
$instance = new $class;
return new MorphTo(
$instance->newQuery(), $this, $id, $instance->getKeyName(), $type, $name
);
}
}
/**
* Retrieve the fully qualified class name from a slug.
*
* @param string $class
* @return string
*/
public function getActualClassNameForMorph($class)
{
return Arr::get(Relation::morphMap(), $class, $class);
}
/**
* Define a one-to-many relationship.
*
* @param string $related
* @param string $foreignKey
* @param string $localKey
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function hasMany($related, $foreignKey = null, $localKey = null)
{
$foreignKey = $foreignKey ?: $this->getForeignKey();
$instance = new $related;
$localKey = $localKey ?: $this->getKeyName();
return new HasMany($instance->newQuery(), $this, $instance->getTable().'.'.$foreignKey, $localKey);
}
/**
* Define a has-many-through relationship.
*
* @param string $related
* @param string $through
* @param string|null $firstKey
* @param string|null $secondKey
* @param string|null $localKey
* @return \Illuminate\Database\Eloquent\Relations\HasManyThrough
*/
public function hasManyThrough($related, $through, $firstKey = null, $secondKey = null, $localKey = null)
{
$through = new $through;
$firstKey = $firstKey ?: $this->getForeignKey();
$secondKey = $secondKey ?: $through->getForeignKey();
$localKey = $localKey ?: $this->getKeyName();
return new HasManyThrough((new $related)->newQuery(), $this, $through, $firstKey, $secondKey, $localKey);
}
/**
* Define a polymorphic one-to-many relationship.
*
* @param string $related
* @param string $name
* @param string $type
* @param string $id
* @param string $localKey
* @return \Illuminate\Database\Eloquent\Relations\MorphMany
*/
public function morphMany($related, $name, $type = null, $id = null, $localKey = null)
{
$instance = new $related;
// Here we will gather up the morph type and ID for the relationship so that we
// can properly query the intermediate table of a relation. Finally, we will
// get the table and create the relationship instances for the developers.
list($type, $id) = $this->getMorphs($name, $type, $id);
$table = $instance->getTable();
$localKey = $localKey ?: $this->getKeyName();
return new MorphMany($instance->newQuery(), $this, $table.'.'.$type, $table.'.'.$id, $localKey);
}
/**
* Define a many-to-many relationship.
*
* @param string $related
* @param string $table
* @param string $foreignKey
* @param string $otherKey
* @param string $relation
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function belongsToMany($related, $table = null, $foreignKey = null, $otherKey = null, $relation = null)
{
// If no relationship name was passed, we will pull backtraces to get the
// name of the calling function. We will use that function name as the
// title of this relation since that is a great convention to apply.
if (is_null($relation)) {
$relation = $this->getBelongsToManyCaller();
}
// First, we'll need to determine the foreign key and "other key" for the
// relationship. Once we have determined the keys we'll make the query
// instances as well as the relationship instances we need for this.
$foreignKey = $foreignKey ?: $this->getForeignKey();
$instance = new $related;
$otherKey = $otherKey ?: $instance->getForeignKey();
// If no table name was provided, we can guess it by concatenating the two
// models using underscores in alphabetical order. The two model names
// are transformed to snake case from their default CamelCase also.
if (is_null($table)) {
$table = $this->joiningTable($related);
}
// Now we're ready to create a new query builder for the related model and
// the relationship instances for the relation. The relations will set
// appropriate query constraint and entirely manages the hydrations.
$query = $instance->newQuery();
return new BelongsToMany($query, $this, $table, $foreignKey, $otherKey, $relation);
}
/**
* Define a polymorphic many-to-many relationship.
*
* @param string $related
* @param string $name
* @param string $table
* @param string $foreignKey
* @param string $otherKey
* @param bool $inverse
* @return \Illuminate\Database\Eloquent\Relations\MorphToMany
*/
public function morphToMany($related, $name, $table = null, $foreignKey = null, $otherKey = null, $inverse = false)
{
$caller = $this->getBelongsToManyCaller();
// First, we will need to determine the foreign key and "other key" for the
// relationship. Once we have determined the keys we will make the query
// instances, as well as the relationship instances we need for these.
$foreignKey = $foreignKey ?: $name.'_id';
$instance = new $related;
$otherKey = $otherKey ?: $instance->getForeignKey();
// Now we're ready to create a new query builder for this related model and
// the relationship instances for this relation. This relations will set
// appropriate query constraints then entirely manages the hydrations.
$query = $instance->newQuery();
$table = $table ?: Str::plural($name);
return new MorphToMany(
$query, $this, $name, $table, $foreignKey,
$otherKey, $caller, $inverse
);
}
/**
* Define a polymorphic, inverse many-to-many relationship.
*
* @param string $related
* @param string $name
* @param string $table
* @param string $foreignKey
* @param string $otherKey
* @return \Illuminate\Database\Eloquent\Relations\MorphToMany
*/
public function morphedByMany($related, $name, $table = null, $foreignKey = null, $otherKey = null)
{
$foreignKey = $foreignKey ?: $this->getForeignKey();
// For the inverse of the polymorphic many-to-many relations, we will change
// the way we determine the foreign and other keys, as it is the opposite
// of the morph-to-many method since we're figuring out these inverses.
$otherKey = $otherKey ?: $name.'_id';
return $this->morphToMany($related, $name, $table, $foreignKey, $otherKey, true);
}
/**
* Get the relationship name of the belongs to many.
*
* @return string
*/
protected function getBelongsToManyCaller()
{
$self = __FUNCTION__;
$caller = Arr::first(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS), function ($key, $trace) use ($self) {
$caller = $trace['function'];
return ! in_array($caller, Model::$manyMethods) && $caller != $self;
});
return ! is_null($caller) ? $caller['function'] : null;
}
/**
* Get the joining table name for a many-to-many relation.
*
* @param string $related
* @return string
*/
public function joiningTable($related)
{
// The joining table name, by convention, is simply the snake cased models
// sorted alphabetically and concatenated with an underscore, so we can
// just sort the models and join them together to get the table name.
$base = Str::snake(class_basename($this));
$related = Str::snake(class_basename($related));
$models = [$related, $base];
// Now that we have the model names in an array we can just sort them and
// use the implode function to join them together with an underscores,
// which is typically used by convention within the database system.
sort($models);
return strtolower(implode('_', $models));
}
/**
* Destroy the models for the given IDs.
*
* @param array|int $ids
* @return int
*/
public static function destroy($ids)
{
// We'll initialize a count here so we will return the total number of deletes
// for the operation. The developers can then check this number as a boolean
// type value or get this total count of records deleted for logging, etc.
$count = 0;
$ids = is_array($ids) ? $ids : func_get_args();
$instance = new static;
// We will actually pull the models from the database table and call delete on
// each of them individually so that their events get fired properly with a
// correct set of attributes in case the developers wants to check these.
$key = $instance->getKeyName();
foreach ($instance->whereIn($key, $ids)->get() as $model) {
if ($model->delete()) {
$count++;
}
}
return $count;
}
/**
* Delete the model from the database.
*
* @return bool|null
*
* @throws \Exception
*/
public function delete()
{
if (is_null($this->getKeyName())) {
throw new Exception('No primary key defined on model.');
}
if ($this->exists) {
if ($this->fireModelEvent('deleting') === false) {
return false;
}
// Here, we'll touch the owning models, verifying these timestamps get updated
// for the models. This will allow any caching to get broken on the parents
// by the timestamp. Then we will go ahead and delete the model instance.
$this->touchOwners();
$this->performDeleteOnModel();
$this->exists = false;
// Once the model has been deleted, we will fire off the deleted event so that
// the developers may hook into post-delete operations. We will then return
// a boolean true as the delete is presumably successful on the database.
$this->fireModelEvent('deleted', false);
return true;
}
}
/**
* Force a hard delete on a soft deleted model.
*
* This method protects developers from running forceDelete when trait is missing.
*
* @return bool|null
*/
public function forceDelete()
{
return $this->delete();
}
/**
* Perform the actual delete query on this model instance.
*
* @return void
*/
protected function performDeleteOnModel()
{
$this->setKeysForSaveQuery($this->newQueryWithoutScopes())->delete();
}
/**
* Register a saving model event with the dispatcher.
*
* @param \Closure|string $callback
* @param int $priority
* @return void
*/
public static function saving($callback, $priority = 0)
{
static::registerModelEvent('saving', $callback, $priority);
}
/**
* Register a saved model event with the dispatcher.
*
* @param \Closure|string $callback
* @param int $priority
* @return void
*/
public static function saved($callback, $priority = 0)
{
static::registerModelEvent('saved', $callback, $priority);
}
/**
* Register an updating model event with the dispatcher.
*
* @param \Closure|string $callback
* @param int $priority
* @return void
*/
public static function updating($callback, $priority = 0)
{
static::registerModelEvent('updating', $callback, $priority);
}
/**
* Register an updated model event with the dispatcher.
*
* @param \Closure|string $callback
* @param int $priority
* @return void
*/
public static function updated($callback, $priority = 0)
{
static::registerModelEvent('updated', $callback, $priority);
}
/**
* Register a creating model event with the dispatcher.
*
* @param \Closure|string $callback
* @param int $priority
* @return void
*/
public static function creating($callback, $priority = 0)
{
static::registerModelEvent('creating', $callback, $priority);
}
/**
* Register a created model event with the dispatcher.
*
* @param \Closure|string $callback
* @param int $priority
* @return void
*/
public static function created($callback, $priority = 0)
{
static::registerModelEvent('created', $callback, $priority);
}
/**
* Register a deleting model event with the dispatcher.
*
* @param \Closure|string $callback
* @param int $priority
* @return void
*/
public static function deleting($callback, $priority = 0)
{
static::registerModelEvent('deleting', $callback, $priority);
}
/**
* Register a deleted model event with the dispatcher.
*
* @param \Closure|string $callback
* @param int $priority
* @return void
*/
public static function deleted($callback, $priority = 0)
{
static::registerModelEvent('deleted', $callback, $priority);
}
/**
* Remove all of the event listeners for the model.
*
* @return void
*/
public static function flushEventListeners()
{
if (! isset(static::$dispatcher)) {
return;
}
$instance = new static;
foreach ($instance->getObservableEvents() as $event) {
static::$dispatcher->forget("eloquent.{$event}: ".static::class);
}
}
/**
* Register a model event with the dispatcher.
*
* @param string $event
* @param \Closure|string $callback
* @param int $priority
* @return void
*/
protected static function registerModelEvent($event, $callback, $priority = 0)
{
if (isset(static::$dispatcher)) {
$name = static::class;
static::$dispatcher->listen("eloquent.{$event}: {$name}", $callback, $priority);
}
}
/**
* Get the observable event names.
*
* @return array
*/
public function getObservableEvents()
{
return array_merge(
[
'creating', 'created', 'updating', 'updated',
'deleting', 'deleted', 'saving', 'saved',
'restoring', 'restored',
],
$this->observables
);
}
/**
* Set the observable event names.
*
* @param array $observables
* @return $this
*/
public function setObservableEvents(array $observables)
{
$this->observables = $observables;
return $this;
}
/**
* Add an observable event name.
*
* @param array|mixed $observables
* @return void
*/
public function addObservableEvents($observables)
{
$observables = is_array($observables) ? $observables : func_get_args();
$this->observables = array_unique(array_merge($this->observables, $observables));
}
/**
* Remove an observable event name.
*
* @param array|mixed $observables
* @return void
*/
public function removeObservableEvents($observables)
{
$observables = is_array($observables) ? $observables : func_get_args();
$this->observables = array_diff($this->observables, $observables);
}
/**
* Increment a column's value by a given amount.
*
* @param string $column
* @param int $amount
* @param array $extra
* @return int
*/
protected function increment($column, $amount = 1, array $extra = [])
{
return $this->incrementOrDecrement($column, $amount, $extra, 'increment');
}
/**
* Decrement a column's value by a given amount.
*
* @param string $column
* @param int $amount
* @param array $extra
* @return int
*/
protected function decrement($column, $amount = 1, array $extra = [])
{
return $this->incrementOrDecrement($column, $amount, $extra, 'decrement');
}
/**
* Run the increment or decrement method on the model.
*
* @param string $column
* @param int $amount
* @param array $extra
* @param string $method
* @return int
*/
protected function incrementOrDecrement($column, $amount, $extra, $method)
{
$query = $this->newQuery();
if (! $this->exists) {
return $query->{$method}($column, $amount, $extra);
}
$this->incrementOrDecrementAttributeValue($column, $amount, $method);
return $query->where($this->getKeyName(), $this->getKey())->{$method}($column, $amount, $extra);
}
/**
* Increment the underlying attribute value and sync with original.
*
* @param string $column
* @param int $amount
* @param string $method
* @return void
*/
protected function incrementOrDecrementAttributeValue($column, $amount, $method)
{
$this->{$column} = $this->{$column} + ($method == 'increment' ? $amount : $amount * -1);
$this->syncOriginalAttribute($column);
}
/**
* Update the model in the database.
*
* @param array $attributes
* @param array $options
* @return bool|int
*/
public function update(array $attributes = [], array $options = [])
{
if (! $this->exists) {
return false;
}
return $this->fill($attributes)->save($options);
}
/**
* Save the model and all of its relationships.
*
* @return bool
*/
public function push()
{
if (! $this->save()) {
return false;
}
// To sync all of the relationships to the database, we will simply spin through
// the relationships and save each model via this "push" method, which allows
// us to recurse into all of these nested relations for the model instance.
foreach ($this->relations as $models) {
$models = $models instanceof Collection
? $models->all() : [$models];
foreach (array_filter($models) as $model) {
if (! $model->push()) {
return false;
}
}
}
return true;
}
/**
* Save the model to the database.
*
* @param array $options
* @return bool
*/
public function save(array $options = [])
{
$query = $this->newQueryWithoutScopes();
// If the "saving" event returns false we'll bail out of the save and return
// false, indicating that the save failed. This provides a chance for any
// listeners to cancel save operations if validations fail or whatever.
if ($this->fireModelEvent('saving') === false) {
return false;
}
// If the model already exists in the database we can just update our record
// that is already in this database using the current IDs in this "where"
// clause to only update this model. Otherwise, we'll just insert them.
if ($this->exists) {
$saved = $this->performUpdate($query, $options);
}
// If the model is brand new, we'll insert it into our database and set the
// ID attribute on the model to the value of the newly inserted row's ID
// which is typically an auto-increment value managed by the database.
else {
$saved = $this->performInsert($query, $options);
}
if ($saved) {
$this->finishSave($options);
}
return $saved;
}
/**
* Save the model to the database using transaction.
*
* @param array $options
* @return bool
*
* @throws \Throwable
*/
public function saveOrFail(array $options = [])
{
return $this->getConnection()->transaction(function () use ($options) {
return $this->save($options);
});
}
/**
* Finish processing on a successful save operation.
*
* @param array $options
* @return void
*/
protected function finishSave(array $options)
{
$this->fireModelEvent('saved', false);
$this->syncOriginal();
if (Arr::get($options, 'touch', true)) {
$this->touchOwners();
}
}
/**
* Perform a model update operation.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param array $options
* @return bool
*/
protected function performUpdate(Builder $query, array $options = [])
{
$dirty = $this->getDirty();
if (count($dirty) > 0) {
// If the updating event returns false, we will cancel the update operation so
// developers can hook Validation systems into their models and cancel this
// operation if the model does not pass validation. Otherwise, we update.
if ($this->fireModelEvent('updating') === false) {
return false;
}
// First we need to create a fresh query instance and touch the creation and
// update timestamp on the model which are maintained by us for developer
// convenience. Then we will just continue saving the model instances.
if ($this->timestamps && Arr::get($options, 'timestamps', true)) {
$this->updateTimestamps();
}
// Once we have run the update operation, we will fire the "updated" event for
// this model instance. This will allow developers to hook into these after
// models are updated, giving them a chance to do any special processing.
$dirty = $this->getDirty();
if (count($dirty) > 0) {
$numRows = $this->setKeysForSaveQuery($query)->update($dirty);
$this->fireModelEvent('updated', false);
}
}
return true;
}
/**
* Perform a model insert operation.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param array $options
* @return bool
*/
protected function performInsert(Builder $query, array $options = [])
{
if ($this->fireModelEvent('creating') === false) {
return false;
}
// First we'll need to create a fresh query instance and touch the creation and
// update timestamps on this model, which are maintained by us for developer
// convenience. After, we will just continue saving these model instances.
if ($this->timestamps && Arr::get($options, 'timestamps', true)) {
$this->updateTimestamps();
}
// If the model has an incrementing key, we can use the "insertGetId" method on
// the query builder, which will give us back the final inserted ID for this
// table from the database. Not all tables have to be incrementing though.
$attributes = $this->attributes;
if ($this->getIncrementing()) {
$this->insertAndSetId($query, $attributes);
}
// If the table isn't incrementing we'll simply insert these attributes as they
// are. These attribute arrays must contain an "id" column previously placed
// there by the developer as the manually determined key for these models.
else {
$query->insert($attributes);
}
// We will go ahead and set the exists property to true, so that it is set when
// the created event is fired, just in case the developer tries to update it
// during the event. This will allow them to do so and run an update here.
$this->exists = true;
$this->wasRecentlyCreated = true;
$this->fireModelEvent('created', false);
return true;
}
/**
* Insert the given attributes and set the ID on the model.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param array $attributes
* @return void
*/
protected function insertAndSetId(Builder $query, $attributes)
{
$id = $query->insertGetId($attributes, $keyName = $this->getKeyName());
$this->setAttribute($keyName, $id);
}
/**
* Touch the owning relations of the model.
*
* @return void
*/
public function touchOwners()
{
foreach ($this->touches as $relation) {
$this->$relation()->touch();
if ($this->$relation instanceof self) {
$this->$relation->fireModelEvent('saved', false);
$this->$relation->touchOwners();
} elseif ($this->$relation instanceof Collection) {
$this->$relation->each(function (Model $relation) {
$relation->touchOwners();
});
}
}
}
/**
* Determine if the model touches a given relation.
*
* @param string $relation
* @return bool
*/
public function touches($relation)
{
return in_array($relation, $this->touches);
}
/**
* Fire the given event for the model.
*
* @param string $event
* @param bool $halt
* @return mixed
*/
protected function fireModelEvent($event, $halt = true)
{
if (! isset(static::$dispatcher)) {
return true;
}
// We will append the names of the class to the event to distinguish it from
// other model events that are fired, allowing us to listen on each model
// event set individually instead of catching event for all the models.
$event = "eloquent.{$event}: ".static::class;
$method = $halt ? 'until' : 'fire';
return static::$dispatcher->$method($event, $this);
}
/**
* Set the keys for a save update query.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @return \Illuminate\Database\Eloquent\Builder
*/
protected function setKeysForSaveQuery(Builder $query)
{
$query->where($this->getKeyName(), '=', $this->getKeyForSaveQuery());
return $query;
}
/**
* Get the primary key value for a save query.
*
* @return mixed
*/
protected function getKeyForSaveQuery()
{
if (isset($this->original[$this->getKeyName()])) {
return $this->original[$this->getKeyName()];
}
return $this->getAttribute($this->getKeyName());
}
/**
* Update the model's update timestamp.
*
* @return bool
*/
public function touch()
{
if (! $this->timestamps) {
return false;
}
$this->updateTimestamps();
return $this->save();
}
/**
* Update the creation and update timestamps.
*
* @return void
*/
protected function updateTimestamps()
{
$time = $this->freshTimestamp();
if (! $this->isDirty(static::UPDATED_AT)) {
$this->setUpdatedAt($time);
}
if (! $this->exists && ! $this->isDirty(static::CREATED_AT)) {
$this->setCreatedAt($time);
}
}
/**
* Set the value of the "created at" attribute.
*
* @param mixed $value
* @return $this
*/
public function setCreatedAt($value)
{
$this->{static::CREATED_AT} = $value;
return $this;
}
/**
* Set the value of the "updated at" attribute.
*
* @param mixed $value
* @return $this
*/
public function setUpdatedAt($value)
{
$this->{static::UPDATED_AT} = $value;
return $this;
}
/**
* Get the name of the "created at" column.
*
* @return string
*/
public function getCreatedAtColumn()
{
return static::CREATED_AT;
}
/**
* Get the name of the "updated at" column.
*
* @return string
*/
public function getUpdatedAtColumn()
{
return static::UPDATED_AT;
}
/**
* Get a fresh timestamp for the model.
*
* @return \Carbon\Carbon
*/
public function freshTimestamp()
{
return new Carbon;
}
/**
* Get a fresh timestamp for the model.
*
* @return string
*/
public function freshTimestampString()
{
return $this->fromDateTime($this->freshTimestamp());
}
/**
* Get a new query builder for the model's table.
*
* @return \Illuminate\Database\Eloquent\Builder
*/
public function newQuery()
{
$builder = $this->newQueryWithoutScopes();
foreach ($this->getGlobalScopes() as $identifier => $scope) {
$builder->withGlobalScope($identifier, $scope);
}
return $builder;
}
/**
* Get a new query instance without a given scope.
*
* @param \Illuminate\Database\Eloquent\Scope|string $scope
* @return \Illuminate\Database\Eloquent\Builder
*/
public function newQueryWithoutScope($scope)
{
$builder = $this->newQuery();
return $builder->withoutGlobalScope($scope);
}
/**
* Get a new query builder that doesn't have any global scopes.
*
* @return \Illuminate\Database\Eloquent\Builder|static
*/
public function newQueryWithoutScopes()
{
$builder = $this->newEloquentBuilder(
$this->newBaseQueryBuilder()
);
// Once we have the query builders, we will set the model instances so the
// builder can easily access any information it may need from the model
// while it is constructing and executing various queries against it.
return $builder->setModel($this)->with($this->with);
}
/**
* Create a new Eloquent query builder for the model.
*
* @param \Illuminate\Database\Query\Builder $query
* @return \Illuminate\Database\Eloquent\Builder|static
*/
public function newEloquentBuilder($query)
{
return new Builder($query);
}
/**
* Get a new query builder instance for the connection.
*
* @return \Illuminate\Database\Query\Builder
*/
protected function newBaseQueryBuilder()
{
$conn = $this->getConnection();
$grammar = $conn->getQueryGrammar();
return new QueryBuilder($conn, $grammar, $conn->getPostProcessor());
}
/**
* Create a new Eloquent Collection instance.
*
* @param array $models
* @return \Illuminate\Database\Eloquent\Collection
*/
public function newCollection(array $models = [])
{
return new Collection($models);
}
/**
* Create a new pivot model instance.
*
* @param \Illuminate\Database\Eloquent\Model $parent
* @param array $attributes
* @param string $table
* @param bool $exists
* @return \Illuminate\Database\Eloquent\Relations\Pivot
*/
public function newPivot(Model $parent, array $attributes, $table, $exists)
{
return new Pivot($parent, $attributes, $table, $exists);
}
/**
* Get the table associated with the model.
*
* @return string
*/
public function getTable()
{
if (isset($this->table)) {
return $this->table;
}
return str_replace('\\', '', Str::snake(Str::plural(class_basename($this))));
}
/**
* Set the table associated with the model.
*
* @param string $table
* @return $this
*/
public function setTable($table)
{
$this->table = $table;
return $this;
}
/**
* Get the value of the model's primary key.
*
* @return mixed
*/
public function getKey()
{
return $this->getAttribute($this->getKeyName());
}
/**
* Get the queueable identity for the entity.
*
* @return mixed
*/
public function getQueueableId()
{
return $this->getKey();
}
/**
* Get the primary key for the model.
*
* @return string
*/
public function getKeyName()
{
return $this->primaryKey;
}
/**
* Set the primary key for the model.
*
* @param string $key
* @return $this
*/
public function setKeyName($key)
{
$this->primaryKey = $key;
return $this;
}
/**
* Get the table qualified key name.
*
* @return string
*/
public function getQualifiedKeyName()
{
return $this->getTable().'.'.$this->getKeyName();
}
/**
* Get the value of the model's route key.
*
* @return mixed
*/
public function getRouteKey()
{
return $this->getAttribute($this->getRouteKeyName());
}
/**
* Get the route key for the model.
*
* @return string
*/
public function getRouteKeyName()
{
return $this->getKeyName();
}
/**
* Determine if the model uses timestamps.
*
* @return bool
*/
public function usesTimestamps()
{
return $this->timestamps;
}
/**
* Get the polymorphic relationship columns.
*
* @param string $name
* @param string $type
* @param string $id
* @return array
*/
protected function getMorphs($name, $type, $id)
{
$type = $type ?: $name.'_type';
$id = $id ?: $name.'_id';
return [$type, $id];
}
/**
* Get the class name for polymorphic relations.
*
* @return string
*/
public function getMorphClass()
{
$morphMap = Relation::morphMap();
$class = static::class;
if (! empty($morphMap) && in_array($class, $morphMap)) {
return array_search($class, $morphMap, true);
}
return $this->morphClass ?: $class;
}
/**
* Get the number of models to return per page.
*
* @return int
*/
public function getPerPage()
{
return $this->perPage;
}
/**
* Set the number of models to return per page.
*
* @param int $perPage
* @return $this
*/
public function setPerPage($perPage)
{
$this->perPage = $perPage;
return $this;
}
/**
* Get the default foreign key name for the model.
*
* @return string
*/
public function getForeignKey()
{
return Str::snake(class_basename($this)).'_id';
}
/**
* Get the hidden attributes for the model.
*
* @return array
*/
public function getHidden()
{
return $this->hidden;
}
/**
* Set the hidden attributes for the model.
*
* @param array $hidden
* @return $this
*/
public function setHidden(array $hidden)
{
$this->hidden = $hidden;
return $this;
}
/**
* Add hidden attributes for the model.
*
* @param array|string|null $attributes
* @return void
*/
public function addHidden($attributes = null)
{
$attributes = is_array($attributes) ? $attributes : func_get_args();
$this->hidden = array_merge($this->hidden, $attributes);
}
/**
* Make the given, typically hidden, attributes visible.
*
* @param array|string $attributes
* @return $this
*/
public function makeVisible($attributes)
{
$this->hidden = array_diff($this->hidden, (array) $attributes);
if (! empty($this->visible)) {
$this->addVisible($attributes);
}
return $this;
}
/**
* Make the given, typically visible, attributes hidden.
*
* @param array|string $attributes
* @return $this
*/
public function makeHidden($attributes)
{
$attributes = (array) $attributes;
$this->visible = array_diff($this->visible, $attributes);
$this->hidden = array_unique(array_merge($this->hidden, $attributes));
return $this;
}
/**
* Make the given, typically hidden, attributes visible.
*
* @param array|string $attributes
* @return $this
*
* @deprecated since version 5.2. Use the "makeVisible" method directly.
*/
public function withHidden($attributes)
{
return $this->makeVisible($attributes);
}
/**
* Get the visible attributes for the model.
*
* @return array
*/
public function getVisible()
{
return $this->visible;
}
/**
* Set the visible attributes for the model.
*
* @param array $visible
* @return $this
*/
public function setVisible(array $visible)
{
$this->visible = $visible;
return $this;
}
/**
* Add visible attributes for the model.
*
* @param array|string|null $attributes
* @return void
*/
public function addVisible($attributes = null)
{
$attributes = is_array($attributes) ? $attributes : func_get_args();
$this->visible = array_merge($this->visible, $attributes);
}
/**
* Set the accessors to append to model arrays.
*
* @param array $appends
* @return $this
*/
public function setAppends(array $appends)
{
$this->appends = $appends;
return $this;
}
/**
* Get the fillable attributes for the model.
*
* @return array
*/
public function getFillable()
{
return $this->fillable;
}
/**
* Set the fillable attributes for the model.
*
* @param array $fillable
* @return $this
*/
public function fillable(array $fillable)
{
$this->fillable = $fillable;
return $this;
}
/**
* Get the guarded attributes for the model.
*
* @return array
*/
public function getGuarded()
{
return $this->guarded;
}
/**
* Set the guarded attributes for the model.
*
* @param array $guarded
* @return $this
*/
public function guard(array $guarded)
{
$this->guarded = $guarded;
return $this;
}
/**
* Disable all mass assignable restrictions.
*
* @param bool $state
* @return void
*/
public static function unguard($state = true)
{
static::$unguarded = $state;
}
/**
* Enable the mass assignment restrictions.
*
* @return void
*/
public static function reguard()
{
static::$unguarded = false;
}
/**
* Determine if current state is "unguarded".
*
* @return bool
*/
public static function isUnguarded()
{
return static::$unguarded;
}
/**
* Run the given callable while being unguarded.
*
* @param callable $callback
* @return mixed
*/
public static function unguarded(callable $callback)
{
if (static::$unguarded) {
return $callback();
}
static::unguard();
try {
return $callback();
} finally {
static::reguard();
}
}
/**
* Determine if the given attribute may be mass assigned.
*
* @param string $key
* @return bool
*/
public function isFillable($key)
{
if (static::$unguarded) {
return true;
}
// If the key is in the "fillable" array, we can of course assume that it's
// a fillable attribute. Otherwise, we will check the guarded array when
// we need to determine if the attribute is black-listed on the model.
if (in_array($key, $this->getFillable())) {
return true;
}
if ($this->isGuarded($key)) {
return false;
}
return empty($this->getFillable()) && ! Str::startsWith($key, '_');
}
/**
* Determine if the given key is guarded.
*
* @param string $key
* @return bool
*/
public function isGuarded($key)
{
return in_array($key, $this->getGuarded()) || $this->getGuarded() == ['*'];
}
/**
* Determine if the model is totally guarded.
*
* @return bool
*/
public function totallyGuarded()
{
return count($this->getFillable()) == 0 && $this->getGuarded() == ['*'];
}
/**
* Remove the table name from a given key.
*
* @param string $key
* @return string
*/
protected function removeTableFromKey($key)
{
if (! Str::contains($key, '.')) {
return $key;
}
return last(explode('.', $key));
}
/**
* Get the relationships that are touched on save.
*
* @return array
*/
public function getTouchedRelations()
{
return $this->touches;
}
/**
* Set the relationships that are touched on save.
*
* @param array $touches
* @return $this
*/
public function setTouchedRelations(array $touches)
{
$this->touches = $touches;
return $this;
}
/**
* Get the value indicating whether the IDs are incrementing.
*
* @return bool
*/
public function getIncrementing()
{
return $this->incrementing;
}
/**
* Set whether IDs are incrementing.
*
* @param bool $value
* @return $this
*/
public function setIncrementing($value)
{
$this->incrementing = $value;
return $this;
}
/**
* Convert the model instance to JSON.
*
* @param int $options
* @return string
*/
public function toJson($options = 0)
{
return json_encode($this->jsonSerialize(), $options);
}
/**
* Convert the object into something JSON serializable.
*
* @return array
*/
public function jsonSerialize()
{
return $this->toArray();
}
/**
* Convert the model instance to an array.
*
* @return array
*/
public function toArray()
{
$attributes = $this->attributesToArray();
return array_merge($attributes, $this->relationsToArray());
}
/**
* Convert the model's attributes to an array.
*
* @return array
*/
public function attributesToArray()
{
$attributes = $this->getArrayableAttributes();
// If an attribute is a date, we will cast it to a string after converting it
// to a DateTime / Carbon instance. This is so we will get some consistent
// formatting while accessing attributes vs. arraying / JSONing a model.
foreach ($this->getDates() as $key) {
if (! isset($attributes[$key])) {
continue;
}
$attributes[$key] = $this->serializeDate(
$this->asDateTime($attributes[$key])
);
}
$mutatedAttributes = $this->getMutatedAttributes();
// We want to spin through all the mutated attributes for this model and call
// the mutator for the attribute. We cache off every mutated attributes so
// we don't have to constantly check on attributes that actually change.
foreach ($mutatedAttributes as $key) {
if (! array_key_exists($key, $attributes)) {
continue;
}
$attributes[$key] = $this->mutateAttributeForArray(
$key, $attributes[$key]
);
}
// Next we will handle any casts that have been setup for this model and cast
// the values to their appropriate type. If the attribute has a mutator we
// will not perform the cast on those attributes to avoid any confusion.
foreach ($this->getCasts() as $key => $value) {
if (! array_key_exists($key, $attributes) ||
in_array($key, $mutatedAttributes)) {
continue;
}
$attributes[$key] = $this->castAttribute(
$key, $attributes[$key]
);
if ($attributes[$key] && ($value === 'date' || $value === 'datetime')) {
$attributes[$key] = $this->serializeDate($attributes[$key]);
}
}
// Here we will grab all of the appended, calculated attributes to this model
// as these attributes are not really in the attributes array, but are run
// when we need to array or JSON the model for convenience to the coder.
foreach ($this->getArrayableAppends() as $key) {
$attributes[$key] = $this->mutateAttributeForArray($key, null);
}
return $attributes;
}
/**
* Get an attribute array of all arrayable attributes.
*
* @return array
*/
protected function getArrayableAttributes()
{
return $this->getArrayableItems($this->attributes);
}
/**
* Get all of the appendable values that are arrayable.
*
* @return array
*/
protected function getArrayableAppends()
{
if (! count($this->appends)) {
return [];
}
return $this->getArrayableItems(
array_combine($this->appends, $this->appends)
);
}
/**
* Get the model's relationships in array form.
*
* @return array
*/
public function relationsToArray()
{
$attributes = [];
foreach ($this->getArrayableRelations() as $key => $value) {
// If the values implements the Arrayable interface we can just call this
// toArray method on the instances which will convert both models and
// collections to their proper array form and we'll set the values.
if ($value instanceof Arrayable) {
$relation = $value->toArray();
}
// If the value is null, we'll still go ahead and set it in this list of
// attributes since null is used to represent empty relationships if
// if it a has one or belongs to type relationships on the models.
elseif (is_null($value)) {
$relation = $value;
}
// If the relationships snake-casing is enabled, we will snake case this
// key so that the relation attribute is snake cased in this returned
// array to the developers, making this consistent with attributes.
if (static::$snakeAttributes) {
$key = Str::snake($key);
}
// If the relation value has been set, we will set it on this attributes
// list for returning. If it was not arrayable or null, we'll not set
// the value on the array because it is some type of invalid value.
if (isset($relation) || is_null($value)) {
$attributes[$key] = $relation;
}
unset($relation);
}
return $attributes;
}
/**
* Get an attribute array of all arrayable relations.
*
* @return array
*/
protected function getArrayableRelations()
{
return $this->getArrayableItems($this->relations);
}
/**
* Get an attribute array of all arrayable values.
*
* @param array $values
* @return array
*/
protected function getArrayableItems(array $values)
{
if (count($this->getVisible()) > 0) {
$values = array_intersect_key($values, array_flip($this->getVisible()));
}
if (count($this->getHidden()) > 0) {
$values = array_diff_key($values, array_flip($this->getHidden()));
}
return $values;
}
/**
* Get an attribute from the model.
*
* @param string $key
* @return mixed
*/
public function getAttribute($key)
{
if (array_key_exists($key, $this->attributes) || $this->hasGetMutator($key)) {
return $this->getAttributeValue($key);
}
return $this->getRelationValue($key);
}
/**
* Get a plain attribute (not a relationship).
*
* @param string $key
* @return mixed
*/
public function getAttributeValue($key)
{
$value = $this->getAttributeFromArray($key);
// If the attribute has a get mutator, we will call that then return what
// it returns as the value, which is useful for transforming values on
// retrieval from the model to a form that is more useful for usage.
if ($this->hasGetMutator($key)) {
return $this->mutateAttribute($key, $value);
}
// If the attribute exists within the cast array, we will convert it to
// an appropriate native PHP type dependant upon the associated value
// given with the key in the pair. Dayle made this comment line up.
if ($this->hasCast($key)) {
return $this->castAttribute($key, $value);
}
// If the attribute is listed as a date, we will convert it to a DateTime
// instance on retrieval, which makes it quite convenient to work with
// date fields without having to create a mutator for each property.
if (in_array($key, $this->getDates()) && ! is_null($value)) {
return $this->asDateTime($value);
}
return $value;
}
/**
* Get a relationship.
*
* @param string $key
* @return mixed
*/
public function getRelationValue($key)
{
// If the key already exists in the relationships array, it just means the
// relationship has already been loaded, so we'll just return it out of
// here because there is no need to query within the relations twice.
if ($this->relationLoaded($key)) {
return $this->relations[$key];
}
// If the "attribute" exists as a method on the model, we will just assume
// it is a relationship and will load and return results from the query
// and hydrate the relationship's value on the "relationships" array.
if (method_exists($this, $key)) {
return $this->getRelationshipFromMethod($key);
}
}
/**
* Get an attribute from the $attributes array.
*
* @param string $key
* @return mixed
*/
protected function getAttributeFromArray($key)
{
if (array_key_exists($key, $this->attributes)) {
return $this->attributes[$key];
}
}
/**
* Get a relationship value from a method.
*
* @param string $method
* @return mixed
*
* @throws \LogicException
*/
protected function getRelationshipFromMethod($method)
{
$relations = $this->$method();
if (! $relations instanceof Relation) {
throw new LogicException('Relationship method must return an object of type '
.'Illuminate\Database\Eloquent\Relations\Relation');
}
$this->setRelation($method, $results = $relations->getResults());
return $results;
}
/**
* Determine if a get mutator exists for an attribute.
*
* @param string $key
* @return bool
*/
public function hasGetMutator($key)
{
return method_exists($this, 'get'.Str::studly($key).'Attribute');
}
/**
* Get the value of an attribute using its mutator.
*
* @param string $key
* @param mixed $value
* @return mixed
*/
protected function mutateAttribute($key, $value)
{
return $this->{'get'.Str::studly($key).'Attribute'}($value);
}
/**
* Get the value of an attribute using its mutator for array conversion.
*
* @param string $key
* @param mixed $value
* @return mixed
*/
protected function mutateAttributeForArray($key, $value)
{
$value = $this->mutateAttribute($key, $value);
return $value instanceof Arrayable ? $value->toArray() : $value;
}
/**
* Determine whether an attribute should be cast to a native type.
*
* @param string $key
* @param array|string|null $types
* @return bool
*/
public function hasCast($key, $types = null)
{
if (array_key_exists($key, $this->getCasts())) {
return $types ? in_array($this->getCastType($key), (array) $types, true) : true;
}
return false;
}
/**
* Get the casts array.
*
* @return array
*/
public function getCasts()
{
if ($this->getIncrementing()) {
return array_merge([
$this->getKeyName() => $this->keyType,
], $this->casts);
}
return $this->casts;
}
/**
* Determine whether a value is Date / DateTime castable for inbound manipulation.
*
* @param string $key
* @return bool
*/
protected function isDateCastable($key)
{
return $this->hasCast($key, ['date', 'datetime']);
}
/**
* Determine whether a value is JSON castable for inbound manipulation.
*
* @param string $key
* @return bool
*/
protected function isJsonCastable($key)
{
return $this->hasCast($key, ['array', 'json', 'object', 'collection']);
}
/**
* Get the type of cast for a model attribute.
*
* @param string $key
* @return string
*/
protected function getCastType($key)
{
return trim(strtolower($this->getCasts()[$key]));
}
/**
* Cast an attribute to a native PHP type.
*
* @param string $key
* @param mixed $value
* @return mixed
*/
protected function castAttribute($key, $value)
{
if (is_null($value)) {
return $value;
}
switch ($this->getCastType($key)) {
case 'int':
case 'integer':
return (int) $value;
case 'real':
case 'float':
case 'double':
return (float) $value;
case 'string':
return (string) $value;
case 'bool':
case 'boolean':
return (bool) $value;
case 'object':
return $this->fromJson($value, true);
case 'array':
case 'json':
return $this->fromJson($value);
case 'collection':
return new BaseCollection($this->fromJson($value));
case 'date':
case 'datetime':
return $this->asDateTime($value);
case 'timestamp':
return $this->asTimeStamp($value);
default:
return $value;
}
}
/**
* Set a given attribute on the model.
*
* @param string $key
* @param mixed $value
* @return $this
*/
public function setAttribute($key, $value)
{
// First we will check for the presence of a mutator for the set operation
// which simply lets the developers tweak the attribute as it is set on
// the model, such as "json_encoding" an listing of data for storage.
if ($this->hasSetMutator($key)) {
$method = 'set'.Str::studly($key).'Attribute';
return $this->{$method}($value);
}
// If an attribute is listed as a "date", we'll convert it from a DateTime
// instance into a form proper for storage on the database tables using
// the connection grammar's date format. We will auto set the values.
elseif ($value && (in_array($key, $this->getDates()) || $this->isDateCastable($key))) {
$value = $this->fromDateTime($value);
}
if ($this->isJsonCastable($key) && ! is_null($value)) {
$value = $this->asJson($value);
}
$this->attributes[$key] = $value;
return $this;
}
/**
* Determine if a set mutator exists for an attribute.
*
* @param string $key
* @return bool
*/
public function hasSetMutator($key)
{
return method_exists($this, 'set'.Str::studly($key).'Attribute');
}
/**
* Get the attributes that should be converted to dates.
*
* @return array
*/
public function getDates()
{
$defaults = [static::CREATED_AT, static::UPDATED_AT];
return $this->timestamps ? array_merge($this->dates, $defaults) : $this->dates;
}
/**
* Convert a DateTime to a storable string.
*
* @param \DateTime|int $value
* @return string
*/
public function fromDateTime($value)
{
$format = $this->getDateFormat();
$value = $this->asDateTime($value);
return $value->format($format);
}
/**
* Return a timestamp as DateTime object.
*
* @param mixed $value
* @return \Carbon\Carbon
*/
protected function asDateTime($value)
{
// If this value is already a Carbon instance, we shall just return it as is.
// This prevents us having to re-instantiate a Carbon instance when we know
// it already is one, which wouldn't be fulfilled by the DateTime check.
if ($value instanceof Carbon) {
return $value;
}
// If the value is already a DateTime instance, we will just skip the rest of
// these checks since they will be a waste of time, and hinder performance
// when checking the field. We will just return the DateTime right away.
if ($value instanceof DateTimeInterface) {
return new Carbon(
$value->format('Y-m-d H:i:s.u'), $value->getTimeZone()
);
}
// If this value is an integer, we will assume it is a UNIX timestamp's value
// and format a Carbon object from this timestamp. This allows flexibility
// when defining your date fields as they might be UNIX timestamps here.
if (is_numeric($value)) {
return Carbon::createFromTimestamp($value);
}
// If the value is in simply year, month, day format, we will instantiate the
// Carbon instances from that format. Again, this provides for simple date
// fields on the database, while still supporting Carbonized conversion.
if (preg_match('/^(\d{4})-(\d{1,2})-(\d{1,2})$/', $value)) {
return Carbon::createFromFormat('Y-m-d', $value)->startOfDay();
}
// Finally, we will just assume this date is in the format used by default on
// the database connection and use that format to create the Carbon object
// that is returned back out to the developers after we convert it here.
return Carbon::createFromFormat($this->getDateFormat(), $value);
}
/**
* Return a timestamp as unix timestamp.
*
* @param mixed $value
* @return int
*/
protected function asTimeStamp($value)
{
return $this->asDateTime($value)->getTimestamp();
}
/**
* Prepare a date for array / JSON serialization.
*
* @param \DateTime $date
* @return string
*/
protected function serializeDate(DateTime $date)
{
return $date->format($this->getDateFormat());
}
/**
* Get the format for database stored dates.
*
* @return string
*/
protected function getDateFormat()
{
return $this->dateFormat ?: $this->getConnection()->getQueryGrammar()->getDateFormat();
}
/**
* Set the date format used by the model.
*
* @param string $format
* @return $this
*/
public function setDateFormat($format)
{
$this->dateFormat = $format;
return $this;
}
/**
* Encode the given value as JSON.
*
* @param mixed $value
* @return string
*/
protected function asJson($value)
{
return json_encode($value);
}
/**
* Decode the given JSON back into an array or object.
*
* @param string $value
* @param bool $asObject
* @return mixed
*/
public function fromJson($value, $asObject = false)
{
return json_decode($value, ! $asObject);
}
/**
* Clone the model into a new, non-existing instance.
*
* @param array|null $except
* @return \Illuminate\Database\Eloquent\Model
*/
public function replicate(array $except = null)
{
$defaults = [
$this->getKeyName(),
$this->getCreatedAtColumn(),
$this->getUpdatedAtColumn(),
];
$except = $except ? array_unique(array_merge($except, $defaults)) : $defaults;
$attributes = Arr::except($this->attributes, $except);
$instance = new static;
$instance->setRawAttributes($attributes);
return $instance->setRelations($this->relations);
}
/**
* Get all of the current attributes on the model.
*
* @return array
*/
public function getAttributes()
{
return $this->attributes;
}
/**
* Set the array of model attributes. No checking is done.
*
* @param array $attributes
* @param bool $sync
* @return $this
*/
public function setRawAttributes(array $attributes, $sync = false)
{
$this->attributes = $attributes;
if ($sync) {
$this->syncOriginal();
}
return $this;
}
/**
* Get the model's original attribute values.
*
* @param string|null $key
* @param mixed $default
* @return mixed|array
*/
public function getOriginal($key = null, $default = null)
{
return Arr::get($this->original, $key, $default);
}
/**
* Sync the original attributes with the current.
*
* @return $this
*/
public function syncOriginal()
{
$this->original = $this->attributes;
return $this;
}
/**
* Sync a single original attribute with its current value.
*
* @param string $attribute
* @return $this
*/
public function syncOriginalAttribute($attribute)
{
$this->original[$attribute] = $this->attributes[$attribute];
return $this;
}
/**
* Determine if the model or given attribute(s) have been modified.
*
* @param array|string|null $attributes
* @return bool
*/
public function isDirty($attributes = null)
{
$dirty = $this->getDirty();
if (is_null($attributes)) {
return count($dirty) > 0;
}
if (! is_array($attributes)) {
$attributes = func_get_args();
}
foreach ($attributes as $attribute) {
if (array_key_exists($attribute, $dirty)) {
return true;
}
}
return false;
}
/**
* Get the attributes that have been changed since last sync.
*
* @return array
*/
public function getDirty()
{
$dirty = [];
foreach ($this->attributes as $key => $value) {
if (! array_key_exists($key, $this->original)) {
$dirty[$key] = $value;
} elseif ($value !== $this->original[$key] &&
! $this->originalIsNumericallyEquivalent($key)) {
$dirty[$key] = $value;
}
}
return $dirty;
}
/**
* Determine if the new and old values for a given key are numerically equivalent.
*
* @param string $key
* @return bool
*/
protected function originalIsNumericallyEquivalent($key)
{
$current = $this->attributes[$key];
$original = $this->original[$key];
return is_numeric($current) && is_numeric($original) && strcmp((string) $current, (string) $original) === 0;
}
/**
* Get all the loaded relations for the instance.
*
* @return array
*/
public function getRelations()
{
return $this->relations;
}
/**
* Get a specified relationship.
*
* @param string $relation
* @return mixed
*/
public function getRelation($relation)
{
return $this->relations[$relation];
}
/**
* Determine if the given relation is loaded.
*
* @param string $key
* @return bool
*/
public function relationLoaded($key)
{
return array_key_exists($key, $this->relations);
}
/**
* Set the specific relationship in the model.
*
* @param string $relation
* @param mixed $value
* @return $this
*/
public function setRelation($relation, $value)
{
$this->relations[$relation] = $value;
return $this;
}
/**
* Set the entire relations array on the model.
*
* @param array $relations
* @return $this
*/
public function setRelations(array $relations)
{
$this->relations = $relations;
return $this;
}
/**
* Get the database connection for the model.
*
* @return \Illuminate\Database\Connection
*/
public function getConnection()
{
return static::resolveConnection($this->getConnectionName());
}
/**
* Get the current connection name for the model.
*
* @return string
*/
public function getConnectionName()
{
return $this->connection;
}
/**
* Set the connection associated with the model.
*
* @param string $name
* @return $this
*/
public function setConnection($name)
{
$this->connection = $name;
return $this;
}
/**
* Resolve a connection instance.
*
* @param string|null $connection
* @return \Illuminate\Database\Connection
*/
public static function resolveConnection($connection = null)
{
return static::$resolver->connection($connection);
}
/**
* Get the connection resolver instance.
*
* @return \Illuminate\Database\ConnectionResolverInterface
*/
public static function getConnectionResolver()
{
return static::$resolver;
}
/**
* Set the connection resolver instance.
*
* @param \Illuminate\Database\ConnectionResolverInterface $resolver
* @return void
*/
public static function setConnectionResolver(Resolver $resolver)
{
static::$resolver = $resolver;
}
/**
* Unset the connection resolver for models.
*
* @return void
*/
public static function unsetConnectionResolver()
{
static::$resolver = null;
}
/**
* Get the event dispatcher instance.
*
* @return \Illuminate\Contracts\Events\Dispatcher
*/
public static function getEventDispatcher()
{
return static::$dispatcher;
}
/**
* Set the event dispatcher instance.
*
* @param \Illuminate\Contracts\Events\Dispatcher $dispatcher
* @return void
*/
public static function setEventDispatcher(Dispatcher $dispatcher)
{
static::$dispatcher = $dispatcher;
}
/**
* Unset the event dispatcher for models.
*
* @return void
*/
public static function unsetEventDispatcher()
{
static::$dispatcher = null;
}
/**
* Get the mutated attributes for a given instance.
*
* @return array
*/
public function getMutatedAttributes()
{
$class = static::class;
if (! isset(static::$mutatorCache[$class])) {
static::cacheMutatedAttributes($class);
}
return static::$mutatorCache[$class];
}
/**
* Extract and cache all the mutated attributes of a class.
*
* @param string $class
* @return void
*/
public static function cacheMutatedAttributes($class)
{
$mutatedAttributes = [];
// Here we will extract all of the mutated attributes so that we can quickly
// spin through them after we export models to their array form, which we
// need to be fast. This'll let us know the attributes that can mutate.
if (preg_match_all('/(?<=^|;)get([^;]+?)Attribute(;|$)/', implode(';', get_class_methods($class)), $matches)) {
foreach ($matches[1] as $match) {
if (static::$snakeAttributes) {
$match = Str::snake($match);
}
$mutatedAttributes[] = lcfirst($match);
}
}
static::$mutatorCache[$class] = $mutatedAttributes;
}
/**
* Dynamically retrieve attributes on the model.
*
* @param string $key
* @return mixed
*/
public function __get($key)
{
return $this->getAttribute($key);
}
/**
* Dynamically set attributes on the model.
*
* @param string $key
* @param mixed $value
* @return void
*/
public function __set($key, $value)
{
$this->setAttribute($key, $value);
}
/**
* Determine if the given attribute exists.
*
* @param mixed $offset
* @return bool
*/
public function offsetExists($offset)
{
return isset($this->$offset);
}
/**
* Get the value for a given offset.
*
* @param mixed $offset
* @return mixed
*/
public function offsetGet($offset)
{
return $this->$offset;
}
/**
* Set the value for a given offset.
*
* @param mixed $offset
* @param mixed $value
* @return void
*/
public function offsetSet($offset, $value)
{
$this->$offset = $value;
}
/**
* Unset the value for a given offset.
*
* @param mixed $offset
* @return void
*/
public function offsetUnset($offset)
{
unset($this->$offset);
}
/**
* Determine if an attribute or relation exists on the model.
*
* @param string $key
* @return bool
*/
public function __isset($key)
{
return ! is_null($this->getAttribute($key));
}
/**
* Unset an attribute on the model.
*
* @param string $key
* @return void
*/
public function __unset($key)
{
unset($this->attributes[$key], $this->relations[$key]);
}
/**
* Handle dynamic method calls into the model.
*
* @param string $method
* @param array $parameters
* @return mixed
*/
public function __call($method, $parameters)
{
if (in_array($method, ['increment', 'decrement'])) {
return call_user_func_array([$this, $method], $parameters);
}
$query = $this->newQuery();
return call_user_func_array([$query, $method], $parameters);
}
/**
* Handle dynamic static method calls into the method.
*
* @param string $method
* @param array $parameters
* @return mixed
*/
public static function __callStatic($method, $parameters)
{
$instance = new static;
return call_user_func_array([$instance, $method], $parameters);
}
/**
* Convert the model to its string representation.
*
* @return string
*/
public function __toString()
{
return $this->toJson();
}
/**
* When a model is being unserialized, check if it needs to be booted.
*
* @return void
*/
public function __wakeup()
{
$this->bootIfNotBooted();
}
}
Eloquent/Builder.php 0000666 00000117650 13436755161 0010470 0 ustar 00 query = $query;
}
/**
* Register a new global scope.
*
* @param string $identifier
* @param \Illuminate\Database\Eloquent\Scope|\Closure $scope
* @return $this
*/
public function withGlobalScope($identifier, $scope)
{
$this->scopes[$identifier] = $scope;
if (method_exists($scope, 'extend')) {
$scope->extend($this);
}
return $this;
}
/**
* Remove a registered global scope.
*
* @param \Illuminate\Database\Eloquent\Scope|string $scope
* @return $this
*/
public function withoutGlobalScope($scope)
{
if (! is_string($scope)) {
$scope = get_class($scope);
}
unset($this->scopes[$scope]);
$this->removedScopes[] = $scope;
return $this;
}
/**
* Remove all or passed registered global scopes.
*
* @param array|null $scopes
* @return $this
*/
public function withoutGlobalScopes(array $scopes = null)
{
if (is_array($scopes)) {
foreach ($scopes as $scope) {
$this->withoutGlobalScope($scope);
}
} else {
$this->scopes = [];
}
return $this;
}
/**
* Get an array of global scopes that were removed from the query.
*
* @return array
*/
public function removedScopes()
{
return $this->removedScopes;
}
/**
* Find a model by its primary key.
*
* @param mixed $id
* @param array $columns
* @return \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Collection|static[]|static|null
*/
public function find($id, $columns = ['*'])
{
if (is_array($id)) {
return $this->findMany($id, $columns);
}
$this->query->where($this->model->getQualifiedKeyName(), '=', $id);
return $this->first($columns);
}
/**
* Find multiple models by their primary keys.
*
* @param array $ids
* @param array $columns
* @return \Illuminate\Database\Eloquent\Collection
*/
public function findMany($ids, $columns = ['*'])
{
if (empty($ids)) {
return $this->model->newCollection();
}
$this->query->whereIn($this->model->getQualifiedKeyName(), $ids);
return $this->get($columns);
}
/**
* Find a model by its primary key or throw an exception.
*
* @param mixed $id
* @param array $columns
* @return \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Collection
*
* @throws \Illuminate\Database\Eloquent\ModelNotFoundException
*/
public function findOrFail($id, $columns = ['*'])
{
$result = $this->find($id, $columns);
if (is_array($id)) {
if (count($result) == count(array_unique($id))) {
return $result;
}
} elseif (! is_null($result)) {
return $result;
}
throw (new ModelNotFoundException)->setModel(get_class($this->model));
}
/**
* Find a model by its primary key or return fresh model instance.
*
* @param mixed $id
* @param array $columns
* @return \Illuminate\Database\Eloquent\Model
*/
public function findOrNew($id, $columns = ['*'])
{
if (! is_null($model = $this->find($id, $columns))) {
return $model;
}
return $this->model->newInstance();
}
/**
* Get the first record matching the attributes or instantiate it.
*
* @param array $attributes
* @return \Illuminate\Database\Eloquent\Model
*/
public function firstOrNew(array $attributes)
{
if (! is_null($instance = $this->where($attributes)->first())) {
return $instance;
}
return $this->model->newInstance($attributes);
}
/**
* Get the first record matching the attributes or create it.
*
* @param array $attributes
* @return \Illuminate\Database\Eloquent\Model
*/
public function firstOrCreate(array $attributes)
{
if (! is_null($instance = $this->where($attributes)->first())) {
return $instance;
}
$instance = $this->model->newInstance($attributes);
$instance->save();
return $instance;
}
/**
* Create or update a record matching the attributes, and fill it with values.
*
* @param array $attributes
* @param array $values
* @return \Illuminate\Database\Eloquent\Model
*/
public function updateOrCreate(array $attributes, array $values = [])
{
$instance = $this->firstOrNew($attributes);
$instance->fill($values)->save();
return $instance;
}
/**
* Execute the query and get the first result.
*
* @param array $columns
* @return \Illuminate\Database\Eloquent\Model|static|null
*/
public function first($columns = ['*'])
{
return $this->take(1)->get($columns)->first();
}
/**
* Execute the query and get the first result or throw an exception.
*
* @param array $columns
* @return \Illuminate\Database\Eloquent\Model|static
*
* @throws \Illuminate\Database\Eloquent\ModelNotFoundException
*/
public function firstOrFail($columns = ['*'])
{
if (! is_null($model = $this->first($columns))) {
return $model;
}
throw (new ModelNotFoundException)->setModel(get_class($this->model));
}
/**
* Execute the query as a "select" statement.
*
* @param array $columns
* @return \Illuminate\Database\Eloquent\Collection|static[]
*/
public function get($columns = ['*'])
{
$builder = $this->applyScopes();
$models = $builder->getModels($columns);
// If we actually found models we will also eager load any relationships that
// have been specified as needing to be eager loaded, which will solve the
// n+1 query issue for the developers to avoid running a lot of queries.
if (count($models) > 0) {
$models = $builder->eagerLoadRelations($models);
}
return $builder->getModel()->newCollection($models);
}
/**
* Get a single column's value from the first result of a query.
*
* @param string $column
* @return mixed
*/
public function value($column)
{
$result = $this->first([$column]);
if ($result) {
return $result->{$column};
}
}
/**
* Get a generator for the given query.
*
* @return \Generator
*/
public function cursor()
{
$builder = $this->applyScopes();
foreach ($builder->query->cursor() as $record) {
yield $this->model->newFromBuilder($record);
}
}
/**
* Chunk the results of the query.
*
* @param int $count
* @param callable $callback
* @return bool
*/
public function chunk($count, callable $callback)
{
$results = $this->forPage($page = 1, $count)->get();
while (count($results) > 0) {
// On each chunk result set, we will pass them to the callback and then let the
// developer take care of everything within the callback, which allows us to
// keep the memory low for spinning through large result sets for working.
if (call_user_func($callback, $results) === false) {
return false;
}
$page++;
$results = $this->forPage($page, $count)->get();
}
return true;
}
/**
* Chunk the results of a query by comparing numeric IDs.
*
* @param int $count
* @param callable $callback
* @param string $column
* @return bool
*/
public function chunkById($count, callable $callback, $column = 'id')
{
$lastId = null;
$results = $this->forPageAfterId($count, 0, $column)->get();
while (! $results->isEmpty()) {
if (call_user_func($callback, $results) === false) {
return false;
}
$lastId = $results->last()->{$column};
$results = $this->forPageAfterId($count, $lastId, $column)->get();
}
return true;
}
/**
* Execute a callback over each item while chunking.
*
* @param callable $callback
* @param int $count
* @return bool
*/
public function each(callable $callback, $count = 1000)
{
if (is_null($this->query->orders) && is_null($this->query->unionOrders)) {
$this->orderBy($this->model->getQualifiedKeyName(), 'asc');
}
return $this->chunk($count, function ($results) use ($callback) {
foreach ($results as $key => $value) {
if ($callback($value, $key) === false) {
return false;
}
}
});
}
/**
* Get an array with the values of a given column.
*
* @param string $column
* @param string|null $key
* @return \Illuminate\Support\Collection
*/
public function pluck($column, $key = null)
{
$results = $this->toBase()->pluck($column, $key);
// If the model has a mutator for the requested column, we will spin through
// the results and mutate the values so that the mutated version of these
// columns are returned as you would expect from these Eloquent models.
if ($this->model->hasGetMutator($column)) {
foreach ($results as $key => &$value) {
$fill = [$column => $value];
$value = $this->model->newFromBuilder($fill)->$column;
}
}
return collect($results);
}
/**
* Alias for the "pluck" method.
*
* @param string $column
* @param string $key
* @return \Illuminate\Support\Collection
*
* @deprecated since version 5.2. Use the "pluck" method directly.
*/
public function lists($column, $key = null)
{
return $this->pluck($column, $key);
}
/**
* Paginate the given query.
*
* @param int $perPage
* @param array $columns
* @param string $pageName
* @param int|null $page
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
*
* @throws \InvalidArgumentException
*/
public function paginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null)
{
$page = $page ?: Paginator::resolveCurrentPage($pageName);
$perPage = $perPage ?: $this->model->getPerPage();
$query = $this->toBase();
$total = $query->getCountForPagination();
$results = $total ? $this->forPage($page, $perPage)->get($columns) : new Collection;
return new LengthAwarePaginator($results, $total, $perPage, $page, [
'path' => Paginator::resolveCurrentPath(),
'pageName' => $pageName,
]);
}
/**
* Paginate the given query into a simple paginator.
*
* @param int $perPage
* @param array $columns
* @param string $pageName
* @param int|null $page
* @return \Illuminate\Contracts\Pagination\Paginator
*/
public function simplePaginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null)
{
$page = $page ?: Paginator::resolveCurrentPage($pageName);
$perPage = $perPage ?: $this->model->getPerPage();
$this->skip(($page - 1) * $perPage)->take($perPage + 1);
return new Paginator($this->get($columns), $perPage, $page, [
'path' => Paginator::resolveCurrentPath(),
'pageName' => $pageName,
]);
}
/**
* Update a record in the database.
*
* @param array $values
* @return int
*/
public function update(array $values)
{
return $this->toBase()->update($this->addUpdatedAtColumn($values));
}
/**
* Increment a column's value by a given amount.
*
* @param string $column
* @param int $amount
* @param array $extra
* @return int
*/
public function increment($column, $amount = 1, array $extra = [])
{
$extra = $this->addUpdatedAtColumn($extra);
return $this->toBase()->increment($column, $amount, $extra);
}
/**
* Decrement a column's value by a given amount.
*
* @param string $column
* @param int $amount
* @param array $extra
* @return int
*/
public function decrement($column, $amount = 1, array $extra = [])
{
$extra = $this->addUpdatedAtColumn($extra);
return $this->toBase()->decrement($column, $amount, $extra);
}
/**
* Add the "updated at" column to an array of values.
*
* @param array $values
* @return array
*/
protected function addUpdatedAtColumn(array $values)
{
if (! $this->model->usesTimestamps()) {
return $values;
}
$column = $this->model->getUpdatedAtColumn();
return Arr::add($values, $column, $this->model->freshTimestampString());
}
/**
* Delete a record from the database.
*
* @return mixed
*/
public function delete()
{
if (isset($this->onDelete)) {
return call_user_func($this->onDelete, $this);
}
return $this->toBase()->delete();
}
/**
* Run the default delete function on the builder.
*
* @return mixed
*/
public function forceDelete()
{
return $this->query->delete();
}
/**
* Register a replacement for the default delete function.
*
* @param \Closure $callback
* @return void
*/
public function onDelete(Closure $callback)
{
$this->onDelete = $callback;
}
/**
* Get the hydrated models without eager loading.
*
* @param array $columns
* @return \Illuminate\Database\Eloquent\Model[]
*/
public function getModels($columns = ['*'])
{
$results = $this->query->get($columns);
$connection = $this->model->getConnectionName();
return $this->model->hydrate($results, $connection)->all();
}
/**
* Eager load the relationships for the models.
*
* @param array $models
* @return array
*/
public function eagerLoadRelations(array $models)
{
foreach ($this->eagerLoad as $name => $constraints) {
// For nested eager loads we'll skip loading them here and they will be set as an
// eager load on the query to retrieve the relation so that they will be eager
// loaded on that query, because that is where they get hydrated as models.
if (strpos($name, '.') === false) {
$models = $this->loadRelation($models, $name, $constraints);
}
}
return $models;
}
/**
* Eagerly load the relationship on a set of models.
*
* @param array $models
* @param string $name
* @param \Closure $constraints
* @return array
*/
protected function loadRelation(array $models, $name, Closure $constraints)
{
// First we will "back up" the existing where conditions on the query so we can
// add our eager constraints. Then we will merge the wheres that were on the
// query back to it in order that any where conditions might be specified.
$relation = $this->getRelation($name);
$relation->addEagerConstraints($models);
call_user_func($constraints, $relation);
$models = $relation->initRelation($models, $name);
// Once we have the results, we just match those back up to their parent models
// using the relationship instance. Then we just return the finished arrays
// of models which have been eagerly hydrated and are readied for return.
$results = $relation->getEager();
return $relation->match($models, $results, $name);
}
/**
* Get the relation instance for the given relation name.
*
* @param string $name
* @return \Illuminate\Database\Eloquent\Relations\Relation
*/
public function getRelation($name)
{
// We want to run a relationship query without any constrains so that we will
// not have to remove these where clauses manually which gets really hacky
// and is error prone while we remove the developer's own where clauses.
$relation = Relation::noConstraints(function () use ($name) {
return $this->getModel()->$name();
});
$nested = $this->nestedRelations($name);
// If there are nested relationships set on the query, we will put those onto
// the query instances so that they can be handled after this relationship
// is loaded. In this way they will all trickle down as they are loaded.
if (count($nested) > 0) {
$relation->getQuery()->with($nested);
}
return $relation;
}
/**
* Get the deeply nested relations for a given top-level relation.
*
* @param string $relation
* @return array
*/
protected function nestedRelations($relation)
{
$nested = [];
// We are basically looking for any relationships that are nested deeper than
// the given top-level relationship. We will just check for any relations
// that start with the given top relations and adds them to our arrays.
foreach ($this->eagerLoad as $name => $constraints) {
if ($this->isNested($name, $relation)) {
$nested[substr($name, strlen($relation.'.'))] = $constraints;
}
}
return $nested;
}
/**
* Determine if the relationship is nested.
*
* @param string $name
* @param string $relation
* @return bool
*/
protected function isNested($name, $relation)
{
$dots = Str::contains($name, '.');
return $dots && Str::startsWith($name, $relation.'.');
}
/**
* Apply the callback's query changes if the given "value" is true.
*
* @param bool $value
* @param \Closure $callback
* @return $this
*/
public function when($value, $callback)
{
$builder = $this;
if ($value) {
$builder = call_user_func($callback, $builder);
}
return $builder;
}
/**
* Add a basic where clause to the query.
*
* @param string $column
* @param string $operator
* @param mixed $value
* @param string $boolean
* @return $this
*/
public function where($column, $operator = null, $value = null, $boolean = 'and')
{
if ($column instanceof Closure) {
$query = $this->model->newQueryWithoutScopes();
call_user_func($column, $query);
$this->query->addNestedWhereQuery($query->getQuery(), $boolean);
} else {
call_user_func_array([$this->query, 'where'], func_get_args());
}
return $this;
}
/**
* Add an "or where" clause to the query.
*
* @param string $column
* @param string $operator
* @param mixed $value
* @return \Illuminate\Database\Eloquent\Builder|static
*/
public function orWhere($column, $operator = null, $value = null)
{
return $this->where($column, $operator, $value, 'or');
}
/**
* Add a relationship count / exists condition to the query.
*
* @param string $relation
* @param string $operator
* @param int $count
* @param string $boolean
* @param \Closure|null $callback
* @return \Illuminate\Database\Eloquent\Builder|static
*/
public function has($relation, $operator = '>=', $count = 1, $boolean = 'and', Closure $callback = null)
{
if (strpos($relation, '.') !== false) {
return $this->hasNested($relation, $operator, $count, $boolean, $callback);
}
$relation = $this->getHasRelationQuery($relation);
// If we only need to check for the existence of the relation, then we can
// optimize the subquery to only run a "where exists" clause instead of
// the full "count" clause. This will make the query run much faster.
$queryType = $this->shouldRunExistsQuery($operator, $count)
? 'getRelationQuery' : 'getRelationCountQuery';
$query = $relation->{$queryType}($relation->getRelated()->newQuery(), $this);
if ($callback) {
$query->callScope($callback);
}
return $this->addHasWhere(
$query, $relation, $operator, $count, $boolean
);
}
/**
* Add nested relationship count / exists conditions to the query.
*
* @param string $relations
* @param string $operator
* @param int $count
* @param string $boolean
* @param \Closure|null $callback
* @return \Illuminate\Database\Eloquent\Builder|static
*/
protected function hasNested($relations, $operator = '>=', $count = 1, $boolean = 'and', $callback = null)
{
$relations = explode('.', $relations);
// In order to nest "has", we need to add count relation constraints on the
// callback Closure. We'll do this by simply passing the Closure its own
// reference to itself so it calls itself recursively on each segment.
$closure = function ($q) use (&$closure, &$relations, $operator, $count, $boolean, $callback) {
if (count($relations) > 1) {
$q->whereHas(array_shift($relations), $closure);
} else {
$q->has(array_shift($relations), $operator, $count, 'and', $callback);
}
};
return $this->has(array_shift($relations), '>=', 1, $boolean, $closure);
}
/**
* Add a relationship count / exists condition to the query.
*
* @param string $relation
* @param string $boolean
* @param \Closure|null $callback
* @return \Illuminate\Database\Eloquent\Builder|static
*/
public function doesntHave($relation, $boolean = 'and', Closure $callback = null)
{
return $this->has($relation, '<', 1, $boolean, $callback);
}
/**
* Add a relationship count / exists condition to the query with where clauses.
*
* @param string $relation
* @param \Closure $callback
* @param string $operator
* @param int $count
* @return \Illuminate\Database\Eloquent\Builder|static
*/
public function whereHas($relation, Closure $callback, $operator = '>=', $count = 1)
{
return $this->has($relation, $operator, $count, 'and', $callback);
}
/**
* Add a relationship count / exists condition to the query with where clauses.
*
* @param string $relation
* @param \Closure|null $callback
* @return \Illuminate\Database\Eloquent\Builder|static
*/
public function whereDoesntHave($relation, Closure $callback = null)
{
return $this->doesntHave($relation, 'and', $callback);
}
/**
* Add a relationship count / exists condition to the query with an "or".
*
* @param string $relation
* @param string $operator
* @param int $count
* @return \Illuminate\Database\Eloquent\Builder|static
*/
public function orHas($relation, $operator = '>=', $count = 1)
{
return $this->has($relation, $operator, $count, 'or');
}
/**
* Add a relationship count / exists condition to the query with where clauses and an "or".
*
* @param string $relation
* @param \Closure $callback
* @param string $operator
* @param int $count
* @return \Illuminate\Database\Eloquent\Builder|static
*/
public function orWhereHas($relation, Closure $callback, $operator = '>=', $count = 1)
{
return $this->has($relation, $operator, $count, 'or', $callback);
}
/**
* Add the "has" condition where clause to the query.
*
* @param \Illuminate\Database\Eloquent\Builder $hasQuery
* @param \Illuminate\Database\Eloquent\Relations\Relation $relation
* @param string $operator
* @param int $count
* @param string $boolean
* @return \Illuminate\Database\Eloquent\Builder|static
*/
protected function addHasWhere(Builder $hasQuery, Relation $relation, $operator, $count, $boolean)
{
$hasQuery->mergeModelDefinedRelationConstraints($relation->getQuery());
if ($this->shouldRunExistsQuery($operator, $count)) {
$not = ($operator === '<' && $count === 1);
return $this->addWhereExistsQuery($hasQuery->toBase(), $boolean, $not);
}
return $this->whereCountQuery($hasQuery->toBase(), $operator, $count, $boolean);
}
/**
* Check if we can run an "exists" query to optimize performance.
*
* @param string $operator
* @param int $count
* @return bool
*/
protected function shouldRunExistsQuery($operator, $count)
{
return ($operator === '>=' || $operator === '<') && $count === 1;
}
/**
* Add a sub query count clause to the query.
*
* @param \Illuminate\Database\Query\Builder $query
* @param string $operator
* @param int $count
* @param string $boolean
* @return $this
*/
protected function whereCountQuery(QueryBuilder $query, $operator = '>=', $count = 1, $boolean = 'and')
{
if (is_numeric($count)) {
$count = new Expression($count);
}
$this->query->addBinding($query->getBindings(), 'where');
return $this->where(new Expression('('.$query->toSql().')'), $operator, $count, $boolean);
}
/**
* Merge the constraints from a relation query to the current query.
*
* @param \Illuminate\Database\Eloquent\Builder $relation
* @return \Illuminate\Database\Eloquent\Builder|static
*/
public function mergeModelDefinedRelationConstraints(Builder $relation)
{
$removedScopes = $relation->removedScopes();
$relationQuery = $relation->getQuery();
// Here we have some relation query and the original relation. We need to copy over any
// where clauses that the developer may have put in the relation definition function.
// We need to remove any global scopes that the developer already removed as well.
return $this->withoutGlobalScopes($removedScopes)->mergeWheres(
$relationQuery->wheres, $relationQuery->getBindings()
);
}
/**
* Get the "has relation" base query instance.
*
* @param string $relation
* @return \Illuminate\Database\Eloquent\Relations\Relation
*/
protected function getHasRelationQuery($relation)
{
return Relation::noConstraints(function () use ($relation) {
return $this->getModel()->$relation();
});
}
/**
* Set the relationships that should be eager loaded.
*
* @param mixed $relations
* @return $this
*/
public function with($relations)
{
if (is_string($relations)) {
$relations = func_get_args();
}
$eagers = $this->parseWithRelations($relations);
$this->eagerLoad = array_merge($this->eagerLoad, $eagers);
return $this;
}
/**
* Prevent the specified relations from being eager loaded.
*
* @param mixed $relations
* @return $this
*/
public function without($relations)
{
if (is_string($relations)) {
$relations = func_get_args();
}
$this->eagerLoad = array_diff_key($this->eagerLoad, array_flip($relations));
return $this;
}
/**
* Add subselect queries to count the relations.
*
* @param mixed $relations
* @return $this
*/
public function withCount($relations)
{
if (is_null($this->query->columns)) {
$this->query->select(['*']);
}
$relations = is_array($relations) ? $relations : func_get_args();
foreach ($this->parseWithRelations($relations) as $name => $constraints) {
// Here we will get the relationship count query and prepare to add it to the main query
// as a sub-select. First, we'll get the "has" query and use that to get the relation
// count query. We will normalize the relation name then append _count as the name.
$relation = $this->getHasRelationQuery($name);
$query = $relation->getRelationCountQuery(
$relation->getRelated()->newQuery(), $this
);
$query->callScope($constraints);
$query->mergeModelDefinedRelationConstraints($relation->getQuery());
$this->selectSub($query->toBase(), snake_case($name).'_count');
}
return $this;
}
/**
* Parse a list of relations into individuals.
*
* @param array $relations
* @return array
*/
protected function parseWithRelations(array $relations)
{
$results = [];
foreach ($relations as $name => $constraints) {
// If the "relation" value is actually a numeric key, we can assume that no
// constraints have been specified for the eager load and we'll just put
// an empty Closure with the loader so that we can treat all the same.
if (is_numeric($name)) {
$f = function () {
//
};
list($name, $constraints) = [$constraints, $f];
}
// We need to separate out any nested includes. Which allows the developers
// to load deep relationships using "dots" without stating each level of
// the relationship with its own key in the array of eager load names.
$results = $this->parseNestedWith($name, $results);
$results[$name] = $constraints;
}
return $results;
}
/**
* Parse the nested relationships in a relation.
*
* @param string $name
* @param array $results
* @return array
*/
protected function parseNestedWith($name, $results)
{
$progress = [];
// If the relation has already been set on the result array, we will not set it
// again, since that would override any constraints that were already placed
// on the relationships. We will only set the ones that are not specified.
foreach (explode('.', $name) as $segment) {
$progress[] = $segment;
if (! isset($results[$last = implode('.', $progress)])) {
$results[$last] = function () {
//
};
}
}
return $results;
}
/**
* Add the given scopes to the current builder instance.
*
* @param array $scopes
* @return mixed
*/
public function scopes(array $scopes)
{
$builder = $this;
foreach ($scopes as $scope => $parameters) {
if (is_int($scope)) {
list($scope, $parameters) = [$parameters, []];
}
$builder = $builder->callScope(
[$this->model, 'scope'.ucfirst($scope)], (array) $parameters
);
}
return $builder;
}
/**
* Apply the given scope on the current builder instance.
*
* @param callable $scope
* @param array $parameters
* @return mixed
*/
protected function callScope(callable $scope, $parameters = [])
{
array_unshift($parameters, $this);
$query = $this->getQuery();
// We will keep track of how many wheres are on the query before running the
// scope so that we can properly group the added scope constraints in the
// query as their own isolated nested where statement and avoid issues.
$originalWhereCount = count($query->wheres);
$result = call_user_func_array($scope, $parameters) ?: $this;
if ($this->shouldNestWheresForScope($query, $originalWhereCount)) {
$this->nestWheresForScope($query, $originalWhereCount);
}
return $result;
}
/**
* Apply the scopes to the Eloquent builder instance and return it.
*
* @return \Illuminate\Database\Eloquent\Builder|static
*/
public function applyScopes()
{
if (! $this->scopes) {
return $this;
}
$builder = clone $this;
foreach ($this->scopes as $scope) {
$builder->callScope(function (Builder $builder) use ($scope) {
if ($scope instanceof Closure) {
$scope($builder);
} elseif ($scope instanceof Scope) {
$scope->apply($builder, $this->getModel());
}
});
}
return $builder;
}
/**
* Determine if the scope added after the given offset should be nested.
*
* @param \Illuminate\Database\Query\Builder $query
* @param int $originalWhereCount
* @return bool
*/
protected function shouldNestWheresForScope(QueryBuilder $query, $originalWhereCount)
{
return count($query->wheres) > $originalWhereCount;
}
/**
* Nest where conditions by slicing them at the given where count.
*
* @param \Illuminate\Database\Query\Builder $query
* @param int $originalWhereCount
* @return void
*/
protected function nestWheresForScope(QueryBuilder $query, $originalWhereCount)
{
// Here, we totally remove all of the where clauses since we are going to
// rebuild them as nested queries by slicing the groups of wheres into
// their own sections. This is to prevent any confusing logic order.
$allWheres = $query->wheres;
$query->wheres = [];
$this->addNestedWhereSlice(
$query, $allWheres, 0, $originalWhereCount
);
$this->addNestedWhereSlice(
$query, $allWheres, $originalWhereCount
);
}
/**
* Slice where conditions at the given offset and add them to the query as a nested condition.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $wheres
* @param int $offset
* @param int $length
* @return void
*/
protected function addNestedWhereSlice(QueryBuilder $query, $wheres, $offset, $length = null)
{
$whereSlice = array_slice($wheres, $offset, $length);
$whereBooleans = collect($whereSlice)->pluck('boolean');
// Here we'll check if the given subset of where clauses contains any "or"
// booleans and in this case create a nested where expression. That way
// we don't add any unnecessary nesting thus keeping the query clean.
if ($whereBooleans->contains('or')) {
$query->wheres[] = $this->nestWhereSlice($whereSlice);
} else {
$query->wheres = array_merge($query->wheres, $whereSlice);
}
}
/**
* Create a where array with nested where conditions.
*
* @param array $whereSlice
* @return array
*/
protected function nestWhereSlice($whereSlice)
{
$whereGroup = $this->getQuery()->forNestedWhere();
$whereGroup->wheres = $whereSlice;
return ['type' => 'Nested', 'query' => $whereGroup, 'boolean' => 'and'];
}
/**
* Get the underlying query builder instance.
*
* @return \Illuminate\Database\Query\Builder
*/
public function getQuery()
{
return $this->query;
}
/**
* Get a base query builder instance.
*
* @return \Illuminate\Database\Query\Builder
*/
public function toBase()
{
return $this->applyScopes()->getQuery();
}
/**
* Set the underlying query builder instance.
*
* @param \Illuminate\Database\Query\Builder $query
* @return $this
*/
public function setQuery($query)
{
$this->query = $query;
return $this;
}
/**
* Get the relationships being eagerly loaded.
*
* @return array
*/
public function getEagerLoads()
{
return $this->eagerLoad;
}
/**
* Set the relationships being eagerly loaded.
*
* @param array $eagerLoad
* @return $this
*/
public function setEagerLoads(array $eagerLoad)
{
$this->eagerLoad = $eagerLoad;
return $this;
}
/**
* Get the model instance being queried.
*
* @return \Illuminate\Database\Eloquent\Model
*/
public function getModel()
{
return $this->model;
}
/**
* Set a model instance for the model being queried.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @return $this
*/
public function setModel(Model $model)
{
$this->model = $model;
$this->query->from($model->getTable());
return $this;
}
/**
* Extend the builder with a given callback.
*
* @param string $name
* @param \Closure $callback
* @return void
*/
public function macro($name, Closure $callback)
{
$this->macros[$name] = $callback;
}
/**
* Get the given macro by name.
*
* @param string $name
* @return \Closure
*/
public function getMacro($name)
{
return Arr::get($this->macros, $name);
}
/**
* Dynamically handle calls into the query instance.
*
* @param string $method
* @param array $parameters
* @return mixed
*/
public function __call($method, $parameters)
{
if (isset($this->macros[$method])) {
array_unshift($parameters, $this);
return call_user_func_array($this->macros[$method], $parameters);
}
if (method_exists($this->model, $scope = 'scope'.ucfirst($method))) {
return $this->callScope([$this->model, $scope], $parameters);
}
if (in_array($method, $this->passthru)) {
return call_user_func_array([$this->toBase(), $method], $parameters);
}
call_user_func_array([$this->query, $method], $parameters);
return $this;
}
/**
* Force a clone of the underlying query builder when cloning.
*
* @return void
*/
public function __clone()
{
$this->query = clone $this->query;
}
}
Eloquent/Scope.php 0000666 00000000536 13436755161 0010145 0 ustar 00 faker = $faker;
}
/**
* The model definitions in the container.
*
* @var array
*/
protected $definitions = [];
/**
* Create a new factory container.
*
* @param \Faker\Generator $faker
* @param string|null $pathToFactories
* @return static
*/
public static function construct(Faker $faker, $pathToFactories = null)
{
$pathToFactories = $pathToFactories ?: database_path('factories');
return (new static($faker))->load($pathToFactories);
}
/**
* Define a class with a given short-name.
*
* @param string $class
* @param string $name
* @param callable $attributes
* @return void
*/
public function defineAs($class, $name, callable $attributes)
{
return $this->define($class, $attributes, $name);
}
/**
* Define a class with a given set of attributes.
*
* @param string $class
* @param callable $attributes
* @param string $name
* @return void
*/
public function define($class, callable $attributes, $name = 'default')
{
$this->definitions[$class][$name] = $attributes;
}
/**
* Create an instance of the given model and persist it to the database.
*
* @param string $class
* @param array $attributes
* @return mixed
*/
public function create($class, array $attributes = [])
{
return $this->of($class)->create($attributes);
}
/**
* Create an instance of the given model and type and persist it to the database.
*
* @param string $class
* @param string $name
* @param array $attributes
* @return mixed
*/
public function createAs($class, $name, array $attributes = [])
{
return $this->of($class, $name)->create($attributes);
}
/**
* Load factories from path.
*
* @param string $path
* @return $this
*/
public function load($path)
{
$factory = $this;
if (is_dir($path)) {
foreach (Finder::create()->files()->in($path) as $file) {
require $file->getRealPath();
}
}
return $factory;
}
/**
* Create an instance of the given model.
*
* @param string $class
* @param array $attributes
* @return mixed
*/
public function make($class, array $attributes = [])
{
return $this->of($class)->make($attributes);
}
/**
* Create an instance of the given model and type.
*
* @param string $class
* @param string $name
* @param array $attributes
* @return mixed
*/
public function makeAs($class, $name, array $attributes = [])
{
return $this->of($class, $name)->make($attributes);
}
/**
* Get the raw attribute array for a given named model.
*
* @param string $class
* @param string $name
* @param array $attributes
* @return array
*/
public function rawOf($class, $name, array $attributes = [])
{
return $this->raw($class, $attributes, $name);
}
/**
* Get the raw attribute array for a given model.
*
* @param string $class
* @param array $attributes
* @param string $name
* @return array
*/
public function raw($class, array $attributes = [], $name = 'default')
{
$raw = call_user_func($this->definitions[$class][$name], $this->faker);
return array_merge($raw, $attributes);
}
/**
* Create a builder for the given model.
*
* @param string $class
* @param string $name
* @return \Illuminate\Database\Eloquent\FactoryBuilder
*/
public function of($class, $name = 'default')
{
return new FactoryBuilder($class, $name, $this->definitions, $this->faker);
}
/**
* Determine if the given offset exists.
*
* @param string $offset
* @return bool
*/
public function offsetExists($offset)
{
return isset($this->definitions[$offset]);
}
/**
* Get the value of the given offset.
*
* @param string $offset
* @return mixed
*/
public function offsetGet($offset)
{
return $this->make($offset);
}
/**
* Set the given offset to the given value.
*
* @param string $offset
* @param callable $value
* @return void
*/
public function offsetSet($offset, $value)
{
return $this->define($offset, $value);
}
/**
* Unset the value at the given offset.
*
* @param string $offset
* @return void
*/
public function offsetUnset($offset)
{
unset($this->definitions[$offset]);
}
}
Eloquent/Collection.php 0000666 00000020465 13436755161 0011172 0 ustar 00 getKey();
}
return Arr::first($this->items, function ($itemKey, $model) use ($key) {
return $model->getKey() == $key;
}, $default);
}
/**
* Load a set of relationships onto the collection.
*
* @param mixed $relations
* @return $this
*/
public function load($relations)
{
if (count($this->items) > 0) {
if (is_string($relations)) {
$relations = func_get_args();
}
$query = $this->first()->newQuery()->with($relations);
$this->items = $query->eagerLoadRelations($this->items);
}
return $this;
}
/**
* Add an item to the collection.
*
* @param mixed $item
* @return $this
*/
public function add($item)
{
$this->items[] = $item;
return $this;
}
/**
* Determine if a key exists in the collection.
*
* @param mixed $key
* @param mixed $value
* @return bool
*/
public function contains($key, $value = null)
{
if (func_num_args() == 2) {
return parent::contains($key, $value);
}
if ($this->useAsCallable($key)) {
return parent::contains($key);
}
$key = $key instanceof Model ? $key->getKey() : $key;
return parent::contains(function ($k, $m) use ($key) {
return $m->getKey() == $key;
});
}
/**
* Get the array of primary keys.
*
* @return array
*/
public function modelKeys()
{
return array_map(function ($m) {
return $m->getKey();
}, $this->items);
}
/**
* Merge the collection with the given items.
*
* @param \ArrayAccess|array $items
* @return static
*/
public function merge($items)
{
$dictionary = $this->getDictionary();
foreach ($items as $item) {
$dictionary[$item->getKey()] = $item;
}
return new static(array_values($dictionary));
}
/**
* Diff the collection with the given items.
*
* @param \ArrayAccess|array $items
* @return static
*/
public function diff($items)
{
$diff = new static;
$dictionary = $this->getDictionary($items);
foreach ($this->items as $item) {
if (! isset($dictionary[$item->getKey()])) {
$diff->add($item);
}
}
return $diff;
}
/**
* Intersect the collection with the given items.
*
* @param \ArrayAccess|array $items
* @return static
*/
public function intersect($items)
{
$intersect = new static;
$dictionary = $this->getDictionary($items);
foreach ($this->items as $item) {
if (isset($dictionary[$item->getKey()])) {
$intersect->add($item);
}
}
return $intersect;
}
/**
* Return only unique items from the collection.
*
* @param string|callable|null $key
* @return static
*/
public function unique($key = null)
{
if (! is_null($key)) {
return parent::unique($key);
}
return new static(array_values($this->getDictionary()));
}
/**
* Returns only the models from the collection with the specified keys.
*
* @param mixed $keys
* @return static
*/
public function only($keys)
{
$dictionary = Arr::only($this->getDictionary(), $keys);
return new static(array_values($dictionary));
}
/**
* Returns all models in the collection except the models with specified keys.
*
* @param mixed $keys
* @return static
*/
public function except($keys)
{
$dictionary = Arr::except($this->getDictionary(), $keys);
return new static(array_values($dictionary));
}
/**
* Make the given, typically visible, attributes hidden across the entire collection.
*
* @param array|string $attributes
* @return $this
*/
public function makeHidden($attributes)
{
return $this->each(function ($model) use ($attributes) {
$model->addHidden($attributes);
});
}
/**
* Make the given, typically hidden, attributes visible across the entire collection.
*
* @param array|string $attributes
* @return $this
*/
public function makeVisible($attributes)
{
return $this->each(function ($model) use ($attributes) {
$model->makeVisible($attributes);
});
}
/**
* Make the given, typically hidden, attributes visible across the entire collection.
*
* @param array|string $attributes
* @return $this
*
* @deprecated since version 5.2. Use the "makeVisible" method directly.
*/
public function withHidden($attributes)
{
return $this->makeVisible($attributes);
}
/**
* Get a dictionary keyed by primary keys.
*
* @param \ArrayAccess|array|null $items
* @return array
*/
public function getDictionary($items = null)
{
$items = is_null($items) ? $this->items : $items;
$dictionary = [];
foreach ($items as $value) {
$dictionary[$value->getKey()] = $value;
}
return $dictionary;
}
/**
* The following methods are intercepted to always return base collections.
*/
/**
* Get an array with the values of a given key.
*
* @param string $value
* @param string|null $key
* @return \Illuminate\Support\Collection
*/
public function pluck($value, $key = null)
{
return $this->toBase()->pluck($value, $key);
}
/**
* Get the keys of the collection items.
*
* @return \Illuminate\Support\Collection
*/
public function keys()
{
return $this->toBase()->keys();
}
/**
* Zip the collection together with one or more arrays.
*
* @param mixed ...$items
* @return \Illuminate\Support\Collection
*/
public function zip($items)
{
return call_user_func_array([$this->toBase(), 'zip'], func_get_args());
}
/**
* Collapse the collection of items into a single array.
*
* @return \Illuminate\Support\Collection
*/
public function collapse()
{
return $this->toBase()->collapse();
}
/**
* Get a flattened array of the items in the collection.
*
* @param int $depth
* @return \Illuminate\Support\Collection
*/
public function flatten($depth = INF)
{
return $this->toBase()->flatten($depth);
}
/**
* Flip the items in the collection.
*
* @return \Illuminate\Support\Collection
*/
public function flip()
{
return $this->toBase()->flip();
}
/**
* Get the type of the entities being queued.
*
* @return string|null
*/
public function getQueueableClass()
{
if ($this->count() === 0) {
return;
}
$class = get_class($this->first());
$this->each(function ($model) use ($class) {
if (get_class($model) !== $class) {
throw new LogicException('Queueing collections with multiple model types is not supported.');
}
});
return $class;
}
/**
* Get the identifiers for all of the entities.
*
* @return array
*/
public function getQueueableIds()
{
return $this->modelKeys();
}
/**
* Get a base Support collection instance from this collection.
*
* @return \Illuminate\Support\Collection
*/
public function toBase()
{
return new BaseCollection($this->items);
}
}
Eloquent/SoftDeletes.php 0000666 00000007004 13436755161 0011312 0 ustar 00 forceDeleting = true;
$deleted = $this->delete();
$this->forceDeleting = false;
return $deleted;
}
/**
* Perform the actual delete query on this model instance.
*
* @return mixed
*/
protected function performDeleteOnModel()
{
if ($this->forceDeleting) {
return $this->newQueryWithoutScopes()->where($this->getKeyName(), $this->getKey())->forceDelete();
}
return $this->runSoftDelete();
}
/**
* Perform the actual delete query on this model instance.
*
* @return void
*/
protected function runSoftDelete()
{
$query = $this->newQueryWithoutScopes()->where($this->getKeyName(), $this->getKey());
$this->{$this->getDeletedAtColumn()} = $time = $this->freshTimestamp();
$query->update([$this->getDeletedAtColumn() => $this->fromDateTime($time)]);
}
/**
* Restore a soft-deleted model instance.
*
* @return bool|null
*/
public function restore()
{
// If the restoring event does not return false, we will proceed with this
// restore operation. Otherwise, we bail out so the developer will stop
// the restore totally. We will clear the deleted timestamp and save.
if ($this->fireModelEvent('restoring') === false) {
return false;
}
$this->{$this->getDeletedAtColumn()} = null;
// Once we have saved the model, we will fire the "restored" event so this
// developer will do anything they need to after a restore operation is
// totally finished. Then we will return the result of the save call.
$this->exists = true;
$result = $this->save();
$this->fireModelEvent('restored', false);
return $result;
}
/**
* Determine if the model instance has been soft-deleted.
*
* @return bool
*/
public function trashed()
{
return ! is_null($this->{$this->getDeletedAtColumn()});
}
/**
* Register a restoring model event with the dispatcher.
*
* @param \Closure|string $callback
* @return void
*/
public static function restoring($callback)
{
static::registerModelEvent('restoring', $callback);
}
/**
* Register a restored model event with the dispatcher.
*
* @param \Closure|string $callback
* @return void
*/
public static function restored($callback)
{
static::registerModelEvent('restored', $callback);
}
/**
* Get the name of the "deleted at" column.
*
* @return string
*/
public function getDeletedAtColumn()
{
return defined('static::DELETED_AT') ? static::DELETED_AT : 'deleted_at';
}
/**
* Get the fully qualified "deleted at" column.
*
* @return string
*/
public function getQualifiedDeletedAtColumn()
{
return $this->getTable().'.'.$this->getDeletedAtColumn();
}
}
Eloquent/QueueEntityResolver.php 0000666 00000001245 13436755161 0013075 0 ustar 00 find($id);
if ($instance) {
return $instance;
}
throw new EntityNotFoundException($type, $id);
}
}
README.md 0000666 00000004263 13436755161 0006047 0 ustar 00 ## Illuminate Database
The Illuminate Database component is a full database toolkit for PHP, providing an expressive query builder, ActiveRecord style ORM, and schema builder. It currently supports MySQL, Postgres, SQL Server, and SQLite. It also serves as the database layer of the Laravel PHP framework.
### Usage Instructions
First, create a new "Capsule" manager instance. Capsule aims to make configuring the library for usage outside of the Laravel framework as easy as possible.
```PHP
use Illuminate\Database\Capsule\Manager as Capsule;
$capsule = new Capsule;
$capsule->addConnection([
'driver' => 'mysql',
'host' => 'localhost',
'database' => 'database',
'username' => 'root',
'password' => 'password',
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
]);
// Set the event dispatcher used by Eloquent models... (optional)
use Illuminate\Events\Dispatcher;
use Illuminate\Container\Container;
$capsule->setEventDispatcher(new Dispatcher(new Container));
// Make this Capsule instance available globally via static methods... (optional)
$capsule->setAsGlobal();
// Setup the Eloquent ORM... (optional; unless you've used setEventDispatcher())
$capsule->bootEloquent();
```
> `composer require "illuminate/events"` required when you need to use observers with Eloquent.
Once the Capsule instance has been registered. You may use it like so:
**Using The Query Builder**
```PHP
$users = Capsule::table('users')->where('votes', '>', 100)->get();
```
Other core methods may be accessed directly from the Capsule in the same manner as from the DB facade:
```PHP
$results = Capsule::select('select * from users where id = ?', array(1));
```
**Using The Schema Builder**
```PHP
Capsule::schema()->create('users', function($table)
{
$table->increments('id');
$table->string('email')->unique();
$table->timestamps();
});
```
**Using The Eloquent ORM**
```PHP
class User extends Illuminate\Database\Eloquent\Model {}
$users = User::where('votes', '>', 1)->get();
```
For further documentation on using the various database facilities this library provides, consult the [Laravel framework documentation](http://laravel.com/docs).
Events/TransactionBeginning.php 0000666 00000000154 13436755161 0012646 0 ustar 00 connection = $connection;
$this->connectionName = $connection->getName();
}
}
Events/QueryExecuted.php 0000666 00000002052 13436755161 0011333 0 ustar 00 sql = $sql;
$this->time = $time;
$this->bindings = $bindings;
$this->connection = $connection;
$this->connectionName = $connection->getName();
}
}
Connectors/SqlServerConnector.php 0000666 00000010622 13436755161 0013213 0 ustar 00 PDO::CASE_NATURAL,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_ORACLE_NULLS => PDO::NULL_NATURAL,
PDO::ATTR_STRINGIFY_FETCHES => false,
];
/**
* Establish a database connection.
*
* @param array $config
* @return \PDO
*/
public function connect(array $config)
{
$options = $this->getOptions($config);
return $this->createConnection($this->getDsn($config), $config, $options);
}
/**
* Create a DSN string from a configuration.
*
* @param array $config
* @return string
*/
protected function getDsn(array $config)
{
// First we will create the basic DSN setup as well as the port if it is in
// in the configuration options. This will give us the basic DSN we will
// need to establish the PDO connections and return them back for use.
if (in_array('dblib', $this->getAvailableDrivers())) {
return $this->getDblibDsn($config);
} elseif ($this->prefersOdbc($config)) {
return $this->getOdbcDsn($config);
} else {
return $this->getSqlSrvDsn($config);
}
}
/**
* Get the DSN string for a DbLib connection.
*
* @param array $config
* @return string
*/
protected function getDblibDsn(array $config)
{
$arguments = [
'host' => $this->buildHostString($config, ':'),
'dbname' => $config['database'],
];
$arguments = array_merge(
$arguments, Arr::only($config, ['appname', 'charset'])
);
return $this->buildConnectString('dblib', $arguments);
}
/**
* Determine if the database configuration prefers ODBC.
*
* @param array $config
* @return bool
*/
protected function prefersOdbc(array $config)
{
return in_array('odbc', $this->getAvailableDrivers()) &&
array_get($config, 'odbc') === true;
}
/**
* Get the DSN string for an ODBC connection.
*
* @param array $config
* @return string
*/
protected function getOdbcDsn(array $config)
{
if (isset($config['odbc_datasource_name'])) {
return 'odbc:'.$config['odbc_datasource_name'];
}
return '';
}
/**
* Get the DSN string for a SqlSrv connection.
*
* @param array $config
* @return string
*/
protected function getSqlSrvDsn(array $config)
{
$arguments = [
'Server' => $this->buildHostString($config, ','),
];
if (isset($config['database'])) {
$arguments['Database'] = $config['database'];
}
if (isset($config['appname'])) {
$arguments['APP'] = $config['appname'];
}
if (isset($config['readonly'])) {
$arguments['ApplicationIntent'] = 'ReadOnly';
}
if (isset($config['pooling']) && $config['pooling'] === false) {
$arguments['ConnectionPooling'] = '0';
}
return $this->buildConnectString('sqlsrv', $arguments);
}
/**
* Build a connection string from the given arguments.
*
* @param string $driver
* @param array $arguments
* @return string
*/
protected function buildConnectString($driver, array $arguments)
{
$options = array_map(function ($key) use ($arguments) {
return sprintf('%s=%s', $key, $arguments[$key]);
}, array_keys($arguments));
return $driver.':'.implode(';', $options);
}
/**
* Build a host string from the given configuration.
*
* @param array $config
* @param string $separator
* @return string
*/
protected function buildHostString(array $config, $separator)
{
if (isset($config['port'])) {
return $config['host'].$separator.$config['port'];
} else {
return $config['host'];
}
}
/**
* Get the available PDO drivers.
*
* @return array
*/
protected function getAvailableDrivers()
{
return PDO::getAvailableDrivers();
}
}
Connectors/ConnectorInterface.php 0000666 00000000360 13436755161 0013163 0 ustar 00 container = $container;
}
/**
* Establish a PDO connection based on the configuration.
*
* @param array $config
* @param string $name
* @return \Illuminate\Database\Connection
*/
public function make(array $config, $name = null)
{
$config = $this->parseConfig($config, $name);
if (isset($config['read'])) {
return $this->createReadWriteConnection($config);
}
return $this->createSingleConnection($config);
}
/**
* Create a single database connection instance.
*
* @param array $config
* @return \Illuminate\Database\Connection
*/
protected function createSingleConnection(array $config)
{
$pdo = function () use ($config) {
return $this->createConnector($config)->connect($config);
};
return $this->createConnection($config['driver'], $pdo, $config['database'], $config['prefix'], $config);
}
/**
* Create a single database connection instance.
*
* @param array $config
* @return \Illuminate\Database\Connection
*/
protected function createReadWriteConnection(array $config)
{
$connection = $this->createSingleConnection($this->getWriteConfig($config));
return $connection->setReadPdo($this->createReadPdo($config));
}
/**
* Create a new PDO instance for reading.
*
* @param array $config
* @return \PDO
*/
protected function createReadPdo(array $config)
{
$readConfig = $this->getReadConfig($config);
return $this->createConnector($readConfig)->connect($readConfig);
}
/**
* Get the read configuration for a read / write connection.
*
* @param array $config
* @return array
*/
protected function getReadConfig(array $config)
{
$readConfig = $this->getReadWriteConfig($config, 'read');
if (isset($readConfig['host']) && is_array($readConfig['host'])) {
$readConfig['host'] = count($readConfig['host']) > 1
? $readConfig['host'][array_rand($readConfig['host'])]
: $readConfig['host'][0];
}
return $this->mergeReadWriteConfig($config, $readConfig);
}
/**
* Get the read configuration for a read / write connection.
*
* @param array $config
* @return array
*/
protected function getWriteConfig(array $config)
{
$writeConfig = $this->getReadWriteConfig($config, 'write');
return $this->mergeReadWriteConfig($config, $writeConfig);
}
/**
* Get a read / write level configuration.
*
* @param array $config
* @param string $type
* @return array
*/
protected function getReadWriteConfig(array $config, $type)
{
if (isset($config[$type][0])) {
return $config[$type][array_rand($config[$type])];
}
return $config[$type];
}
/**
* Merge a configuration for a read / write connection.
*
* @param array $config
* @param array $merge
* @return array
*/
protected function mergeReadWriteConfig(array $config, array $merge)
{
return Arr::except(array_merge($config, $merge), ['read', 'write']);
}
/**
* Parse and prepare the database configuration.
*
* @param array $config
* @param string $name
* @return array
*/
protected function parseConfig(array $config, $name)
{
return Arr::add(Arr::add($config, 'prefix', ''), 'name', $name);
}
/**
* Create a connector instance based on the configuration.
*
* @param array $config
* @return \Illuminate\Database\Connectors\ConnectorInterface
*
* @throws \InvalidArgumentException
*/
public function createConnector(array $config)
{
if (! isset($config['driver'])) {
throw new InvalidArgumentException('A driver must be specified.');
}
if ($this->container->bound($key = "db.connector.{$config['driver']}")) {
return $this->container->make($key);
}
switch ($config['driver']) {
case 'mysql':
return new MySqlConnector;
case 'pgsql':
return new PostgresConnector;
case 'sqlite':
return new SQLiteConnector;
case 'sqlsrv':
return new SqlServerConnector;
}
throw new InvalidArgumentException("Unsupported driver [{$config['driver']}]");
}
/**
* Create a new connection instance.
*
* @param string $driver
* @param \PDO|\Closure $connection
* @param string $database
* @param string $prefix
* @param array $config
* @return \Illuminate\Database\Connection
*
* @throws \InvalidArgumentException
*/
protected function createConnection($driver, $connection, $database, $prefix = '', array $config = [])
{
if ($this->container->bound($key = "db.connection.{$driver}")) {
return $this->container->make($key, [$connection, $database, $prefix, $config]);
}
switch ($driver) {
case 'mysql':
return new MySqlConnection($connection, $database, $prefix, $config);
case 'pgsql':
return new PostgresConnection($connection, $database, $prefix, $config);
case 'sqlite':
return new SQLiteConnection($connection, $database, $prefix, $config);
case 'sqlsrv':
return new SqlServerConnection($connection, $database, $prefix, $config);
}
throw new InvalidArgumentException("Unsupported driver [$driver]");
}
}
Connectors/PostgresConnector.php 0000666 00000007373 13436755161 0013104 0 ustar 00 PDO::CASE_NATURAL,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_ORACLE_NULLS => PDO::NULL_NATURAL,
PDO::ATTR_STRINGIFY_FETCHES => false,
];
/**
* Establish a database connection.
*
* @param array $config
* @return \PDO
*/
public function connect(array $config)
{
// First we'll create the basic DSN and connection instance connecting to the
// using the configuration option specified by the developer. We will also
// set the default character set on the connections to UTF-8 by default.
$dsn = $this->getDsn($config);
$options = $this->getOptions($config);
$connection = $this->createConnection($dsn, $config, $options);
$charset = $config['charset'];
$connection->prepare("set names '$charset'")->execute();
// Next, we will check to see if a timezone has been specified in this config
// and if it has we will issue a statement to modify the timezone with the
// database. Setting this DB timezone is an optional configuration item.
if (isset($config['timezone'])) {
$timezone = $config['timezone'];
$connection->prepare("set time zone '$timezone'")->execute();
}
// Unlike MySQL, Postgres allows the concept of "schema" and a default schema
// may have been specified on the connections. If that is the case we will
// set the default schema search paths to the specified database schema.
if (isset($config['schema'])) {
$schema = $this->formatSchema($config['schema']);
$connection->prepare("set search_path to {$schema}")->execute();
}
// Postgres allows an application_name to be set by the user and this name is
// used to when monitoring the application with pg_stat_activity. So we'll
// determine if the option has been specified and run a statement if so.
if (isset($config['application_name'])) {
$applicationName = $config['application_name'];
$connection->prepare("set application_name to '$applicationName'")->execute();
}
return $connection;
}
/**
* Create a DSN string from a configuration.
*
* @param array $config
* @return string
*/
protected function getDsn(array $config)
{
// First we will create the basic DSN setup as well as the port if it is in
// in the configuration options. This will give us the basic DSN we will
// need to establish the PDO connections and return them back for use.
extract($config, EXTR_SKIP);
$host = isset($host) ? "host={$host};" : '';
$dsn = "pgsql:{$host}dbname={$database}";
// If a port was specified, we will add it to this Postgres DSN connections
// format. Once we have done that we are ready to return this connection
// string back out for usage, as this has been fully constructed here.
if (isset($config['port'])) {
$dsn .= ";port={$port}";
}
if (isset($config['sslmode'])) {
$dsn .= ";sslmode={$sslmode}";
}
return $dsn;
}
/**
* Format the schema for the DSN.
*
* @param array|string $schema
* @return string
*/
protected function formatSchema($schema)
{
if (is_array($schema)) {
return '"'.implode('", "', $schema).'"';
} else {
return '"'.$schema.'"';
}
}
}
Connectors/MySqlConnector.php 0000666 00000007766 13436755161 0012351 0 ustar 00 getDsn($config);
$options = $this->getOptions($config);
// We need to grab the PDO options that should be used while making the brand
// new connection instance. The PDO options control various aspects of the
// connection's behavior, and some might be specified by the developers.
$connection = $this->createConnection($dsn, $config, $options);
if (! empty($config['database'])) {
$connection->exec("use `{$config['database']}`;");
}
$collation = $config['collation'];
// Next we will set the "names" and "collation" on the clients connections so
// a correct character set will be used by this client. The collation also
// is set on the server but needs to be set here on this client objects.
if (isset($config['charset'])) {
$charset = $config['charset'];
$names = "set names '$charset'".
(! is_null($collation) ? " collate '$collation'" : '');
$connection->prepare($names)->execute();
}
// Next, we will check to see if a timezone has been specified in this config
// and if it has we will issue a statement to modify the timezone with the
// database. Setting this DB timezone is an optional configuration item.
if (isset($config['timezone'])) {
$connection->prepare(
'set time_zone="'.$config['timezone'].'"'
)->execute();
}
$this->setModes($connection, $config);
return $connection;
}
/**
* Create a DSN string from a configuration.
*
* Chooses socket or host/port based on the 'unix_socket' config value.
*
* @param array $config
* @return string
*/
protected function getDsn(array $config)
{
return $this->configHasSocket($config) ? $this->getSocketDsn($config) : $this->getHostDsn($config);
}
/**
* Determine if the given configuration array has a UNIX socket value.
*
* @param array $config
* @return bool
*/
protected function configHasSocket(array $config)
{
return isset($config['unix_socket']) && ! empty($config['unix_socket']);
}
/**
* Get the DSN string for a socket configuration.
*
* @param array $config
* @return string
*/
protected function getSocketDsn(array $config)
{
return "mysql:unix_socket={$config['unix_socket']};dbname={$config['database']}";
}
/**
* Get the DSN string for a host / port configuration.
*
* @param array $config
* @return string
*/
protected function getHostDsn(array $config)
{
extract($config, EXTR_SKIP);
return isset($port)
? "mysql:host={$host};port={$port};dbname={$database}"
: "mysql:host={$host};dbname={$database}";
}
/**
* Set the modes for the connection.
*
* @param \PDO $connection
* @param array $config
* @return void
*/
protected function setModes(PDO $connection, array $config)
{
if (isset($config['modes'])) {
$modes = implode(',', $config['modes']);
$connection->prepare("set session sql_mode='".$modes."'")->execute();
} elseif (isset($config['strict'])) {
if ($config['strict']) {
$connection->prepare("set session sql_mode='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION'")->execute();
} else {
$connection->prepare("set session sql_mode='NO_ENGINE_SUBSTITUTION'")->execute();
}
}
}
}
Connectors/Connector.php 0000666 00000004651 13436755161 0011351 0 ustar 00 PDO::CASE_NATURAL,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_ORACLE_NULLS => PDO::NULL_NATURAL,
PDO::ATTR_STRINGIFY_FETCHES => false,
PDO::ATTR_EMULATE_PREPARES => false,
];
/**
* Get the PDO options based on the configuration.
*
* @param array $config
* @return array
*/
public function getOptions(array $config)
{
$options = Arr::get($config, 'options', []);
return array_diff_key($this->options, $options) + $options;
}
/**
* Create a new PDO connection.
*
* @param string $dsn
* @param array $config
* @param array $options
* @return \PDO
*/
public function createConnection($dsn, array $config, array $options)
{
$username = Arr::get($config, 'username');
$password = Arr::get($config, 'password');
try {
$pdo = new PDO($dsn, $username, $password, $options);
} catch (Exception $e) {
$pdo = $this->tryAgainIfCausedByLostConnection(
$e, $dsn, $username, $password, $options
);
}
return $pdo;
}
/**
* Get the default PDO connection options.
*
* @return array
*/
public function getDefaultOptions()
{
return $this->options;
}
/**
* Set the default PDO connection options.
*
* @param array $options
* @return void
*/
public function setDefaultOptions(array $options)
{
$this->options = $options;
}
/**
* Handle a exception that occurred during connect execution.
*
* @param \Exception $e
* @param string $dsn
* @param string $username
* @param string $password
* @param array $options
* @return \PDO
*
* @throws \Exception
*/
protected function tryAgainIfCausedByLostConnection(Exception $e, $dsn, $username, $password, $options)
{
if ($this->causedByLostConnection($e)) {
return new PDO($dsn, $username, $password, $options);
}
throw $e;
}
}
Connectors/SQLiteConnector.php 0000666 00000002460 13436755161 0012427 0 ustar 00 getOptions($config);
// SQLite supports "in-memory" databases that only last as long as the owning
// connection does. These are useful for tests or for short lifetime store
// querying. In-memory databases may only have a single open connection.
if ($config['database'] == ':memory:') {
return $this->createConnection('sqlite::memory:', $config, $options);
}
$path = realpath($config['database']);
// Here we'll verify that the SQLite database exists before going any further
// as the developer probably wants to know if the database exists and this
// SQLite driver will not throw any exception if it does not by default.
if ($path === false) {
throw new InvalidArgumentException("Database (${config['database']}) does not exist.");
}
return $this->createConnection("sqlite:{$path}", $config, $options);
}
}
MigrationServiceProvider.php 0000666 00000014636 13436755161 0012273 0 ustar 00 registerRepository();
// Once we have registered the migrator instance we will go ahead and register
// all of the migration related commands that are used by the "Artisan" CLI
// so that they may be easily accessed for registering with the consoles.
$this->registerMigrator();
$this->registerCreator();
$this->registerCommands();
}
/**
* Register the migration repository service.
*
* @return void
*/
protected function registerRepository()
{
$this->app->singleton('migration.repository', function ($app) {
$table = $app['config']['database.migrations'];
return new DatabaseMigrationRepository($app['db'], $table);
});
}
/**
* Register the migrator service.
*
* @return void
*/
protected function registerMigrator()
{
// The migrator is responsible for actually running and rollback the migration
// files in the application. We'll pass in our database connection resolver
// so the migrator can resolve any of these connections when it needs to.
$this->app->singleton('migrator', function ($app) {
$repository = $app['migration.repository'];
return new Migrator($repository, $app['db'], $app['files']);
});
}
/**
* Register the migration creator.
*
* @return void
*/
protected function registerCreator()
{
$this->app->singleton('migration.creator', function ($app) {
return new MigrationCreator($app['files']);
});
}
/**
* Register all of the migration commands.
*
* @return void
*/
protected function registerCommands()
{
$commands = ['Migrate', 'Rollback', 'Reset', 'Refresh', 'Install', 'Make', 'Status'];
// We'll simply spin through the list of commands that are migration related
// and register each one of them with an application container. They will
// be resolved in the Artisan start file and registered on the console.
foreach ($commands as $command) {
$this->{'register'.$command.'Command'}();
}
// Once the commands are registered in the application IoC container we will
// register them with the Artisan start event so that these are available
// when the Artisan application actually starts up and is getting used.
$this->commands(
'command.migrate', 'command.migrate.make',
'command.migrate.install', 'command.migrate.rollback',
'command.migrate.reset', 'command.migrate.refresh',
'command.migrate.status'
);
}
/**
* Register the "migrate" migration command.
*
* @return void
*/
protected function registerMigrateCommand()
{
$this->app->singleton('command.migrate', function ($app) {
return new MigrateCommand($app['migrator']);
});
}
/**
* Register the "rollback" migration command.
*
* @return void
*/
protected function registerRollbackCommand()
{
$this->app->singleton('command.migrate.rollback', function ($app) {
return new RollbackCommand($app['migrator']);
});
}
/**
* Register the "reset" migration command.
*
* @return void
*/
protected function registerResetCommand()
{
$this->app->singleton('command.migrate.reset', function ($app) {
return new ResetCommand($app['migrator']);
});
}
/**
* Register the "refresh" migration command.
*
* @return void
*/
protected function registerRefreshCommand()
{
$this->app->singleton('command.migrate.refresh', function () {
return new RefreshCommand;
});
}
/**
* Register the "make" migration command.
*
* @return void
*/
protected function registerMakeCommand()
{
$this->app->singleton('command.migrate.make', function ($app) {
// Once we have the migration creator registered, we will create the command
// and inject the creator. The creator is responsible for the actual file
// creation of the migrations, and may be extended by these developers.
$creator = $app['migration.creator'];
$composer = $app['composer'];
return new MigrateMakeCommand($creator, $composer);
});
}
/**
* Register the "status" migration command.
*
* @return void
*/
protected function registerStatusCommand()
{
$this->app->singleton('command.migrate.status', function ($app) {
return new StatusCommand($app['migrator']);
});
}
/**
* Register the "install" migration command.
*
* @return void
*/
protected function registerInstallCommand()
{
$this->app->singleton('command.migrate.install', function ($app) {
return new InstallCommand($app['migration.repository']);
});
}
/**
* Get the services provided by the provider.
*
* @return array
*/
public function provides()
{
return [
'migrator', 'migration.repository', 'command.migrate',
'command.migrate.rollback', 'command.migrate.reset',
'command.migrate.refresh', 'command.migrate.install',
'command.migrate.status', 'migration.creator',
'command.migrate.make',
];
}
}
QueryException.php 0000666 00000003104 13436755161 0010256 0 ustar 00 sql = $sql;
$this->bindings = $bindings;
$this->previous = $previous;
$this->code = $previous->getCode();
$this->message = $this->formatMessage($sql, $bindings, $previous);
if ($previous instanceof PDOException) {
$this->errorInfo = $previous->errorInfo;
}
}
/**
* Format the SQL error message.
*
* @param string $sql
* @param array $bindings
* @param \Exception $previous
* @return string
*/
protected function formatMessage($sql, $bindings, $previous)
{
return $previous->getMessage().' (SQL: '.str_replace_array('\?', $bindings, $sql).')';
}
/**
* Get the SQL for the query.
*
* @return string
*/
public function getSql()
{
return $this->sql;
}
/**
* Get the bindings for the query.
*
* @return array
*/
public function getBindings()
{
return $this->bindings;
}
}
ConnectionResolverInterface.php 0000666 00000001072 13436755161 0012736 0 ustar 00 setupContainer($container ?: new Container);
// Once we have the container setup, we will setup the default configuration
// options in the container "config" binding. This will make the database
// manager work correctly out of the box without extreme configuration.
$this->setupDefaultConfiguration();
$this->setupManager();
}
/**
* Setup the default database configuration options.
*
* @return void
*/
protected function setupDefaultConfiguration()
{
$this->container['config']['database.fetch'] = PDO::FETCH_OBJ;
$this->container['config']['database.default'] = 'default';
}
/**
* Build the database manager instance.
*
* @return void
*/
protected function setupManager()
{
$factory = new ConnectionFactory($this->container);
$this->manager = new DatabaseManager($this->container, $factory);
}
/**
* Get a connection instance from the global manager.
*
* @param string $connection
* @return \Illuminate\Database\Connection
*/
public static function connection($connection = null)
{
return static::$instance->getConnection($connection);
}
/**
* Get a fluent query builder instance.
*
* @param string $table
* @param string $connection
* @return \Illuminate\Database\Query\Builder
*/
public static function table($table, $connection = null)
{
return static::$instance->connection($connection)->table($table);
}
/**
* Get a schema builder instance.
*
* @param string $connection
* @return \Illuminate\Database\Schema\Builder
*/
public static function schema($connection = null)
{
return static::$instance->connection($connection)->getSchemaBuilder();
}
/**
* Get a registered connection instance.
*
* @param string $name
* @return \Illuminate\Database\Connection
*/
public function getConnection($name = null)
{
return $this->manager->connection($name);
}
/**
* Register a connection with the manager.
*
* @param array $config
* @param string $name
* @return void
*/
public function addConnection(array $config, $name = 'default')
{
$connections = $this->container['config']['database.connections'];
$connections[$name] = $config;
$this->container['config']['database.connections'] = $connections;
}
/**
* Bootstrap Eloquent so it is ready for usage.
*
* @return void
*/
public function bootEloquent()
{
Eloquent::setConnectionResolver($this->manager);
// If we have an event dispatcher instance, we will go ahead and register it
// with the Eloquent ORM, allowing for model callbacks while creating and
// updating "model" instances; however, it is not necessary to operate.
if ($dispatcher = $this->getEventDispatcher()) {
Eloquent::setEventDispatcher($dispatcher);
}
}
/**
* Set the fetch mode for the database connections.
*
* @param int $fetchMode
* @return $this
*/
public function setFetchMode($fetchMode)
{
$this->container['config']['database.fetch'] = $fetchMode;
return $this;
}
/**
* Get the database manager instance.
*
* @return \Illuminate\Database\DatabaseManager
*/
public function getDatabaseManager()
{
return $this->manager;
}
/**
* Get the current event dispatcher instance.
*
* @return \Illuminate\Contracts\Events\Dispatcher|null
*/
public function getEventDispatcher()
{
if ($this->container->bound('events')) {
return $this->container['events'];
}
}
/**
* Set the event dispatcher instance to be used by connections.
*
* @param \Illuminate\Contracts\Events\Dispatcher $dispatcher
* @return void
*/
public function setEventDispatcher(Dispatcher $dispatcher)
{
$this->container->instance('events', $dispatcher);
}
/**
* Dynamically pass methods to the default connection.
*
* @param string $method
* @param array $parameters
* @return mixed
*/
public static function __callStatic($method, $parameters)
{
return call_user_func_array([static::connection(), $method], $parameters);
}
}
ConnectionInterface.php 0000666 00000006241 13436755161 0011217 0 ustar 00 schemaGrammar)) {
$this->useDefaultSchemaGrammar();
}
return new MySqlBuilder($this);
}
/**
* Get the default query grammar instance.
*
* @return \Illuminate\Database\Query\Grammars\MySqlGrammar
*/
protected function getDefaultQueryGrammar()
{
return $this->withTablePrefix(new QueryGrammar);
}
/**
* Get the default schema grammar instance.
*
* @return \Illuminate\Database\Schema\Grammars\MySqlGrammar
*/
protected function getDefaultSchemaGrammar()
{
return $this->withTablePrefix(new SchemaGrammar);
}
/**
* Get the default post processor instance.
*
* @return \Illuminate\Database\Query\Processors\MySqlProcessor
*/
protected function getDefaultPostProcessor()
{
return new MySqlProcessor;
}
/**
* Get the Doctrine DBAL driver.
*
* @return \Doctrine\DBAL\Driver\PDOMySql\Driver
*/
protected function getDoctrineDriver()
{
return new DoctrineDriver;
}
}
DatabaseServiceProvider.php 0000666 00000005105 13436755161 0012035 0 ustar 00 app['db']);
Model::setEventDispatcher($this->app['events']);
}
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
Model::clearBootedModels();
$this->registerEloquentFactory();
$this->registerQueueableEntityResolver();
// The connection factory is used to create the actual connection instances on
// the database. We will inject the factory into the manager so that it may
// make the connections while they are actually needed and not of before.
$this->app->singleton('db.factory', function ($app) {
return new ConnectionFactory($app);
});
// The database manager is used to resolve various connections, since multiple
// connections might be managed. It also implements the connection resolver
// interface which may be used by other components requiring connections.
$this->app->singleton('db', function ($app) {
return new DatabaseManager($app, $app['db.factory']);
});
$this->app->bind('db.connection', function ($app) {
return $app['db']->connection();
});
}
/**
* Register the Eloquent factory instance in the container.
*
* @return void
*/
protected function registerEloquentFactory()
{
$this->app->singleton(FakerGenerator::class, function () {
return FakerFactory::create();
});
$this->app->singleton(EloquentFactory::class, function ($app) {
$faker = $app->make(FakerGenerator::class);
return EloquentFactory::construct($faker, database_path('factories'));
});
}
/**
* Register the queueable entity resolver implementation.
*
* @return void
*/
protected function registerQueueableEntityResolver()
{
$this->app->singleton('Illuminate\Contracts\Queue\EntityResolver', function () {
return new QueueEntityResolver;
});
}
}
Query/Processors/SqlServerProcessor.php 0000666 00000003333 13436755161 0014373 0 ustar 00 getConnection();
$connection->insert($sql, $values);
if ($connection->getConfig('odbc') === true) {
$id = $this->processInsertGetIdForOdbc($connection);
} else {
$id = $connection->getPdo()->lastInsertId();
}
return is_numeric($id) ? (int) $id : $id;
}
/**
* Process an "insert get ID" query for ODBC.
*
* @param \Illuminate\Database\Connection $connection
* @return int
*/
protected function processInsertGetIdForOdbc($connection)
{
$result = $connection->selectFromWriteConnection('SELECT CAST(COALESCE(SCOPE_IDENTITY(), @@IDENTITY) AS int) AS insertid');
if (! $result) {
throw new Exception('Unable to retrieve lastInsertID for ODBC.');
}
$row = $result[0];
return is_object($row) ? $row->insertid : $row['insertid'];
}
/**
* Process the results of a column listing query.
*
* @param array $results
* @return array
*/
public function processColumnListing($results)
{
$mapping = function ($r) {
$r = (object) $r;
return $r->name;
};
return array_map($mapping, $results);
}
}
Query/Processors/PostgresProcessor.php 0000666 00000002074 13436755161 0014254 0 ustar 00 getConnection()->selectFromWriteConnection($sql, $values)[0];
$sequence = $sequence ?: 'id';
$id = is_object($result) ? $result->$sequence : $result[$sequence];
return is_numeric($id) ? (int) $id : $id;
}
/**
* Process the results of a column listing query.
*
* @param array $results
* @return array
*/
public function processColumnListing($results)
{
$mapping = function ($r) {
$r = (object) $r;
return $r->column_name;
};
return array_map($mapping, $results);
}
}
Query/Processors/SQLiteProcessor.php 0000666 00000000675 13436755161 0013614 0 ustar 00 name;
};
return array_map($mapping, $results);
}
}
Query/Processors/Processor.php 0000666 00000002151 13436755161 0012521 0 ustar 00 getConnection()->insert($sql, $values);
$id = $query->getConnection()->getPdo()->lastInsertId($sequence);
return is_numeric($id) ? (int) $id : $id;
}
/**
* Process the results of a column listing query.
*
* @param array $results
* @return array
*/
public function processColumnListing($results)
{
return $results;
}
}
Query/Processors/MySqlProcessor.php 0000666 00000000703 13436755161 0013510 0 ustar 00 column_name;
};
return array_map($mapping, $results);
}
}
Query/JsonExpression.php 0000666 00000002637 13436755161 0011402 0 ustar 00 value = $this->getJsonBindingParameter($value);
}
/**
* Translate the given value into the appropriate JSON binding parameter.
*
* @param mixed $value
* @return string
*/
protected function getJsonBindingParameter($value)
{
switch ($type = gettype($value)) {
case 'boolean':
return $value ? 'true' : 'false';
case 'integer':
case 'double':
return $value;
case 'string':
return '?';
case 'object':
case 'array':
return '?';
}
throw new InvalidArgumentException('JSON value is of illegal type: '.$type);
}
/**
* Get the value of the expression.
*
* @return mixed
*/
public function getValue()
{
return $this->value;
}
/**
* Get the value of the expression.
*
* @return string
*/
public function __toString()
{
return (string) $this->getValue();
}
}
Query/JoinClause.php 0000666 00000014463 13436755161 0010445 0 ustar 00 type = $type;
$this->table = $table;
}
/**
* Add an "on" clause to the join.
*
* On clauses can be chained, e.g.
*
* $join->on('contacts.user_id', '=', 'users.id')
* ->on('contacts.info_id', '=', 'info.id')
*
* will produce the following SQL:
*
* on `contacts`.`user_id` = `users`.`id` and `contacts`.`info_id` = `info`.`id`
*
* @param \Closure|string $first
* @param string|null $operator
* @param string|null $second
* @param string $boolean
* @param bool $where
* @return $this
*
* @throws \InvalidArgumentException
*/
public function on($first, $operator = null, $second = null, $boolean = 'and', $where = false)
{
if ($first instanceof Closure) {
return $this->nest($first, $boolean);
}
if (func_num_args() < 3) {
throw new InvalidArgumentException('Not enough arguments for the on clause.');
}
if ($where) {
$this->bindings[] = $second;
}
if ($where && ($operator === 'in' || $operator === 'not in') && is_array($second)) {
$second = count($second);
}
$nested = false;
$this->clauses[] = compact('first', 'operator', 'second', 'boolean', 'where', 'nested');
return $this;
}
/**
* Add an "or on" clause to the join.
*
* @param \Closure|string $first
* @param string|null $operator
* @param string|null $second
* @return \Illuminate\Database\Query\JoinClause
*/
public function orOn($first, $operator = null, $second = null)
{
return $this->on($first, $operator, $second, 'or');
}
/**
* Add an "on where" clause to the join.
*
* @param \Closure|string $first
* @param string|null $operator
* @param string|null $second
* @param string $boolean
* @return \Illuminate\Database\Query\JoinClause
*/
public function where($first, $operator = null, $second = null, $boolean = 'and')
{
return $this->on($first, $operator, $second, $boolean, true);
}
/**
* Add an "or on where" clause to the join.
*
* @param \Closure|string $first
* @param string|null $operator
* @param string|null $second
* @return \Illuminate\Database\Query\JoinClause
*/
public function orWhere($first, $operator = null, $second = null)
{
return $this->on($first, $operator, $second, 'or', true);
}
/**
* Add an "on where is null" clause to the join.
*
* @param string $column
* @param string $boolean
* @return \Illuminate\Database\Query\JoinClause
*/
public function whereNull($column, $boolean = 'and')
{
return $this->on($column, 'is', new Expression('null'), $boolean, false);
}
/**
* Add an "or on where is null" clause to the join.
*
* @param string $column
* @return \Illuminate\Database\Query\JoinClause
*/
public function orWhereNull($column)
{
return $this->whereNull($column, 'or');
}
/**
* Add an "on where is not null" clause to the join.
*
* @param string $column
* @param string $boolean
* @return \Illuminate\Database\Query\JoinClause
*/
public function whereNotNull($column, $boolean = 'and')
{
return $this->on($column, 'is', new Expression('not null'), $boolean, false);
}
/**
* Add an "or on where is not null" clause to the join.
*
* @param string $column
* @return \Illuminate\Database\Query\JoinClause
*/
public function orWhereNotNull($column)
{
return $this->whereNotNull($column, 'or');
}
/**
* Add an "on where in (...)" clause to the join.
*
* @param string $column
* @param array $values
* @return \Illuminate\Database\Query\JoinClause
*/
public function whereIn($column, array $values)
{
return $this->on($column, 'in', $values, 'and', true);
}
/**
* Add an "on where not in (...)" clause to the join.
*
* @param string $column
* @param array $values
* @return \Illuminate\Database\Query\JoinClause
*/
public function whereNotIn($column, array $values)
{
return $this->on($column, 'not in', $values, 'and', true);
}
/**
* Add an "or on where in (...)" clause to the join.
*
* @param string $column
* @param array $values
* @return \Illuminate\Database\Query\JoinClause
*/
public function orWhereIn($column, array $values)
{
return $this->on($column, 'in', $values, 'or', true);
}
/**
* Add an "or on where not in (...)" clause to the join.
*
* @param string $column
* @param array $values
* @return \Illuminate\Database\Query\JoinClause
*/
public function orWhereNotIn($column, array $values)
{
return $this->on($column, 'not in', $values, 'or', true);
}
/**
* Add a nested where statement to the query.
*
* @param \Closure $callback
* @param string $boolean
* @return \Illuminate\Database\Query\JoinClause
*/
public function nest(Closure $callback, $boolean = 'and')
{
$join = new static($this->type, $this->table);
$callback($join);
if (count($join->clauses)) {
$nested = true;
$this->clauses[] = compact('nested', 'join', 'boolean');
$this->bindings = array_merge($this->bindings, $join->bindings);
}
return $this;
}
}
Query/Builder.php 0000666 00000177363 13436755161 0010010 0 ustar 00 [],
'join' => [],
'where' => [],
'having' => [],
'order' => [],
'union' => [],
];
/**
* An aggregate function and column to be run.
*
* @var array
*/
public $aggregate;
/**
* The columns that should be returned.
*
* @var array
*/
public $columns;
/**
* Indicates if the query returns distinct results.
*
* @var bool
*/
public $distinct = false;
/**
* The table which the query is targeting.
*
* @var string
*/
public $from;
/**
* The table joins for the query.
*
* @var array
*/
public $joins;
/**
* The where constraints for the query.
*
* @var array
*/
public $wheres;
/**
* The groupings for the query.
*
* @var array
*/
public $groups;
/**
* The having constraints for the query.
*
* @var array
*/
public $havings;
/**
* The orderings for the query.
*
* @var array
*/
public $orders;
/**
* The maximum number of records to return.
*
* @var int
*/
public $limit;
/**
* The number of records to skip.
*
* @var int
*/
public $offset;
/**
* The query union statements.
*
* @var array
*/
public $unions;
/**
* The maximum number of union records to return.
*
* @var int
*/
public $unionLimit;
/**
* The number of union records to skip.
*
* @var int
*/
public $unionOffset;
/**
* The orderings for the union query.
*
* @var array
*/
public $unionOrders;
/**
* Indicates whether row locking is being used.
*
* @var string|bool
*/
public $lock;
/**
* The field backups currently in use.
*
* @var array
*/
protected $backups = [];
/**
* The binding backups currently in use.
*
* @var array
*/
protected $bindingBackups = [];
/**
* All of the available clause operators.
*
* @var array
*/
protected $operators = [
'=', '<', '>', '<=', '>=', '<>', '!=',
'like', 'like binary', 'not like', 'between', 'ilike',
'&', '|', '^', '<<', '>>',
'rlike', 'regexp', 'not regexp',
'~', '~*', '!~', '!~*', 'similar to',
'not similar to', 'not ilike', '~~*', '!~~*',
];
/**
* Whether use write pdo for select.
*
* @var bool
*/
protected $useWritePdo = false;
/**
* Create a new query builder instance.
*
* @param \Illuminate\Database\ConnectionInterface $connection
* @param \Illuminate\Database\Query\Grammars\Grammar $grammar
* @param \Illuminate\Database\Query\Processors\Processor $processor
* @return void
*/
public function __construct(ConnectionInterface $connection,
Grammar $grammar = null,
Processor $processor = null)
{
$this->connection = $connection;
$this->grammar = $grammar ?: $connection->getQueryGrammar();
$this->processor = $processor ?: $connection->getPostProcessor();
}
/**
* Set the columns to be selected.
*
* @param array|mixed $columns
* @return $this
*/
public function select($columns = ['*'])
{
$this->columns = is_array($columns) ? $columns : func_get_args();
return $this;
}
/**
* Add a new "raw" select expression to the query.
*
* @param string $expression
* @param array $bindings
* @return \Illuminate\Database\Query\Builder|static
*/
public function selectRaw($expression, array $bindings = [])
{
$this->addSelect(new Expression($expression));
if ($bindings) {
$this->addBinding($bindings, 'select');
}
return $this;
}
/**
* Add a subselect expression to the query.
*
* @param \Closure|\Illuminate\Database\Query\Builder|string $query
* @param string $as
* @return \Illuminate\Database\Query\Builder|static
*
* @throws \InvalidArgumentException
*/
public function selectSub($query, $as)
{
if ($query instanceof Closure) {
$callback = $query;
$callback($query = $this->newQuery());
}
if ($query instanceof self) {
$bindings = $query->getBindings();
$query = $query->toSql();
} elseif (is_string($query)) {
$bindings = [];
} else {
throw new InvalidArgumentException;
}
return $this->selectRaw('('.$query.') as '.$this->grammar->wrap($as), $bindings);
}
/**
* Add a new select column to the query.
*
* @param array|mixed $column
* @return $this
*/
public function addSelect($column)
{
$column = is_array($column) ? $column : func_get_args();
$this->columns = array_merge((array) $this->columns, $column);
return $this;
}
/**
* Force the query to only return distinct results.
*
* @return $this
*/
public function distinct()
{
$this->distinct = true;
return $this;
}
/**
* Set the table which the query is targeting.
*
* @param string $table
* @return $this
*/
public function from($table)
{
$this->from = $table;
return $this;
}
/**
* Add a join clause to the query.
*
* @param string $table
* @param string $one
* @param string $operator
* @param string $two
* @param string $type
* @param bool $where
* @return $this
*/
public function join($table, $one, $operator = null, $two = null, $type = 'inner', $where = false)
{
// If the first "column" of the join is really a Closure instance the developer
// is trying to build a join with a complex "on" clause containing more than
// one condition, so we'll add the join and call a Closure with the query.
if ($one instanceof Closure) {
$join = new JoinClause($type, $table);
call_user_func($one, $join);
$this->joins[] = $join;
$this->addBinding($join->bindings, 'join');
}
// If the column is simply a string, we can assume the join simply has a basic
// "on" clause with a single condition. So we will just build the join with
// this simple join clauses attached to it. There is not a join callback.
else {
$join = new JoinClause($type, $table);
$this->joins[] = $join->on(
$one, $operator, $two, 'and', $where
);
$this->addBinding($join->bindings, 'join');
}
return $this;
}
/**
* Add a "join where" clause to the query.
*
* @param string $table
* @param string $one
* @param string $operator
* @param string $two
* @param string $type
* @return \Illuminate\Database\Query\Builder|static
*/
public function joinWhere($table, $one, $operator, $two, $type = 'inner')
{
return $this->join($table, $one, $operator, $two, $type, true);
}
/**
* Add a left join to the query.
*
* @param string $table
* @param string $first
* @param string $operator
* @param string $second
* @return \Illuminate\Database\Query\Builder|static
*/
public function leftJoin($table, $first, $operator = null, $second = null)
{
return $this->join($table, $first, $operator, $second, 'left');
}
/**
* Add a "join where" clause to the query.
*
* @param string $table
* @param string $one
* @param string $operator
* @param string $two
* @return \Illuminate\Database\Query\Builder|static
*/
public function leftJoinWhere($table, $one, $operator, $two)
{
return $this->joinWhere($table, $one, $operator, $two, 'left');
}
/**
* Add a right join to the query.
*
* @param string $table
* @param string $first
* @param string $operator
* @param string $second
* @return \Illuminate\Database\Query\Builder|static
*/
public function rightJoin($table, $first, $operator = null, $second = null)
{
return $this->join($table, $first, $operator, $second, 'right');
}
/**
* Add a "right join where" clause to the query.
*
* @param string $table
* @param string $one
* @param string $operator
* @param string $two
* @return \Illuminate\Database\Query\Builder|static
*/
public function rightJoinWhere($table, $one, $operator, $two)
{
return $this->joinWhere($table, $one, $operator, $two, 'right');
}
/**
* Add a "cross join" clause to the query.
*
* @param string $table
* @param string $first
* @param string $operator
* @param string $second
* @return \Illuminate\Database\Query\Builder|static
*/
public function crossJoin($table, $first = null, $operator = null, $second = null)
{
if ($first) {
return $this->join($table, $first, $operator, $second, 'cross');
}
$this->joins[] = new JoinClause('cross', $table);
return $this;
}
/**
* Apply the callback's query changes if the given "value" is true.
*
* @param bool $value
* @param \Closure $callback
* @return \Illuminate\Database\Query\Builder
*/
public function when($value, $callback)
{
$builder = $this;
if ($value) {
$builder = call_user_func($callback, $builder);
}
return $builder;
}
/**
* Add a basic where clause to the query.
*
* @param string|array|\Closure $column
* @param string $operator
* @param mixed $value
* @param string $boolean
* @return $this
*
* @throws \InvalidArgumentException
*/
public function where($column, $operator = null, $value = null, $boolean = 'and')
{
// If the column is an array, we will assume it is an array of key-value pairs
// and can add them each as a where clause. We will maintain the boolean we
// received when the method was called and pass it into the nested where.
if (is_array($column)) {
return $this->addArrayOfWheres($column, $boolean);
}
// Here we will make some assumptions about the operator. If only 2 values are
// passed to the method, we will assume that the operator is an equals sign
// and keep going. Otherwise, we'll require the operator to be passed in.
if (func_num_args() == 2) {
list($value, $operator) = [$operator, '='];
} elseif ($this->invalidOperatorAndValue($operator, $value)) {
throw new InvalidArgumentException('Illegal operator and value combination.');
}
// If the columns is actually a Closure instance, we will assume the developer
// wants to begin a nested where statement which is wrapped in parenthesis.
// We'll add that Closure to the query then return back out immediately.
if ($column instanceof Closure) {
return $this->whereNested($column, $boolean);
}
// If the given operator is not found in the list of valid operators we will
// assume that the developer is just short-cutting the '=' operators and
// we will set the operators to '=' and set the values appropriately.
if (! in_array(strtolower($operator), $this->operators, true) &&
! in_array(strtolower($operator), $this->grammar->getOperators(), true)) {
list($value, $operator) = [$operator, '='];
}
// If the value is a Closure, it means the developer is performing an entire
// sub-select within the query and we will need to compile the sub-select
// within the where clause to get the appropriate query record results.
if ($value instanceof Closure) {
return $this->whereSub($column, $operator, $value, $boolean);
}
// If the value is "null", we will just assume the developer wants to add a
// where null clause to the query. So, we will allow a short-cut here to
// that method for convenience so the developer doesn't have to check.
if (is_null($value)) {
return $this->whereNull($column, $boolean, $operator != '=');
}
// Now that we are working with just a simple query we can put the elements
// in our array and add the query binding to our array of bindings that
// will be bound to each SQL statements when it is finally executed.
$type = 'Basic';
if (Str::contains($column, '->') && is_bool($value)) {
$value = new Expression($value ? 'true' : 'false');
}
$this->wheres[] = compact('type', 'column', 'operator', 'value', 'boolean');
if (! $value instanceof Expression) {
$this->addBinding($value, 'where');
}
return $this;
}
/**
* Add an array of where clauses to the query.
*
* @param array $column
* @param string $boolean
* @param string $method
* @return $this
*/
protected function addArrayOfWheres($column, $boolean, $method = 'where')
{
return $this->whereNested(function ($query) use ($column, $method) {
foreach ($column as $key => $value) {
if (is_numeric($key) && is_array($value)) {
call_user_func_array([$query, $method], $value);
} else {
$query->$method($key, '=', $value);
}
}
}, $boolean);
}
/**
* Determine if the given operator and value combination is legal.
*
* @param string $operator
* @param mixed $value
* @return bool
*/
protected function invalidOperatorAndValue($operator, $value)
{
$isOperator = in_array($operator, $this->operators);
return is_null($value) && $isOperator && ! in_array($operator, ['=', '<>', '!=']);
}
/**
* Add an "or where" clause to the query.
*
* @param string $column
* @param string $operator
* @param mixed $value
* @return \Illuminate\Database\Query\Builder|static
*/
public function orWhere($column, $operator = null, $value = null)
{
return $this->where($column, $operator, $value, 'or');
}
/**
* Add a "where" clause comparing two columns to the query.
*
* @param string|array $first
* @param string|null $operator
* @param string|null $second
* @param string|null $boolean
* @return \Illuminate\Database\Query\Builder|static
*/
public function whereColumn($first, $operator = null, $second = null, $boolean = 'and')
{
// If the column is an array, we will assume it is an array of key-value pairs
// and can add them each as a where clause. We will maintain the boolean we
// received when the method was called and pass it into the nested where.
if (is_array($first)) {
return $this->addArrayOfWheres($first, $boolean, 'whereColumn');
}
// If the given operator is not found in the list of valid operators we will
// assume that the developer is just short-cutting the '=' operators and
// we will set the operators to '=' and set the values appropriately.
if (! in_array(strtolower($operator), $this->operators, true) &&
! in_array(strtolower($operator), $this->grammar->getOperators(), true)) {
list($second, $operator) = [$operator, '='];
}
$type = 'Column';
$this->wheres[] = compact('type', 'first', 'operator', 'second', 'boolean');
return $this;
}
/**
* Add an "or where" clause comparing two columns to the query.
*
* @param string|array $first
* @param string|null $operator
* @param string|null $second
* @return \Illuminate\Database\Query\Builder|static
*/
public function orWhereColumn($first, $operator = null, $second = null)
{
return $this->whereColumn($first, $operator, $second, 'or');
}
/**
* Add a raw where clause to the query.
*
* @param string $sql
* @param array $bindings
* @param string $boolean
* @return $this
*/
public function whereRaw($sql, array $bindings = [], $boolean = 'and')
{
$type = 'raw';
$this->wheres[] = compact('type', 'sql', 'boolean');
$this->addBinding($bindings, 'where');
return $this;
}
/**
* Add a raw or where clause to the query.
*
* @param string $sql
* @param array $bindings
* @return \Illuminate\Database\Query\Builder|static
*/
public function orWhereRaw($sql, array $bindings = [])
{
return $this->whereRaw($sql, $bindings, 'or');
}
/**
* Add a where between statement to the query.
*
* @param string $column
* @param array $values
* @param string $boolean
* @param bool $not
* @return $this
*/
public function whereBetween($column, array $values, $boolean = 'and', $not = false)
{
$type = 'between';
$this->wheres[] = compact('column', 'type', 'boolean', 'not');
$this->addBinding($values, 'where');
return $this;
}
/**
* Add an or where between statement to the query.
*
* @param string $column
* @param array $values
* @return \Illuminate\Database\Query\Builder|static
*/
public function orWhereBetween($column, array $values)
{
return $this->whereBetween($column, $values, 'or');
}
/**
* Add a where not between statement to the query.
*
* @param string $column
* @param array $values
* @param string $boolean
* @return \Illuminate\Database\Query\Builder|static
*/
public function whereNotBetween($column, array $values, $boolean = 'and')
{
return $this->whereBetween($column, $values, $boolean, true);
}
/**
* Add an or where not between statement to the query.
*
* @param string $column
* @param array $values
* @return \Illuminate\Database\Query\Builder|static
*/
public function orWhereNotBetween($column, array $values)
{
return $this->whereNotBetween($column, $values, 'or');
}
/**
* Add a nested where statement to the query.
*
* @param \Closure $callback
* @param string $boolean
* @return \Illuminate\Database\Query\Builder|static
*/
public function whereNested(Closure $callback, $boolean = 'and')
{
$query = $this->forNestedWhere();
call_user_func($callback, $query);
return $this->addNestedWhereQuery($query, $boolean);
}
/**
* Create a new query instance for nested where condition.
*
* @return \Illuminate\Database\Query\Builder
*/
public function forNestedWhere()
{
$query = $this->newQuery();
return $query->from($this->from);
}
/**
* Add another query builder as a nested where to the query builder.
*
* @param \Illuminate\Database\Query\Builder|static $query
* @param string $boolean
* @return $this
*/
public function addNestedWhereQuery($query, $boolean = 'and')
{
if (count($query->wheres)) {
$type = 'Nested';
$this->wheres[] = compact('type', 'query', 'boolean');
$this->addBinding($query->getBindings(), 'where');
}
return $this;
}
/**
* Add a full sub-select to the query.
*
* @param string $column
* @param string $operator
* @param \Closure $callback
* @param string $boolean
* @return $this
*/
protected function whereSub($column, $operator, Closure $callback, $boolean)
{
$type = 'Sub';
$query = $this->newQuery();
// Once we have the query instance we can simply execute it so it can add all
// of the sub-select's conditions to itself, and then we can cache it off
// in the array of where clauses for the "main" parent query instance.
call_user_func($callback, $query);
$this->wheres[] = compact('type', 'column', 'operator', 'query', 'boolean');
$this->addBinding($query->getBindings(), 'where');
return $this;
}
/**
* Add an exists clause to the query.
*
* @param \Closure $callback
* @param string $boolean
* @param bool $not
* @return $this
*/
public function whereExists(Closure $callback, $boolean = 'and', $not = false)
{
$query = $this->newQuery();
// Similar to the sub-select clause, we will create a new query instance so
// the developer may cleanly specify the entire exists query and we will
// compile the whole thing in the grammar and insert it into the SQL.
call_user_func($callback, $query);
return $this->addWhereExistsQuery($query, $boolean, $not);
}
/**
* Add an or exists clause to the query.
*
* @param \Closure $callback
* @param bool $not
* @return \Illuminate\Database\Query\Builder|static
*/
public function orWhereExists(Closure $callback, $not = false)
{
return $this->whereExists($callback, 'or', $not);
}
/**
* Add a where not exists clause to the query.
*
* @param \Closure $callback
* @param string $boolean
* @return \Illuminate\Database\Query\Builder|static
*/
public function whereNotExists(Closure $callback, $boolean = 'and')
{
return $this->whereExists($callback, $boolean, true);
}
/**
* Add a where not exists clause to the query.
*
* @param \Closure $callback
* @return \Illuminate\Database\Query\Builder|static
*/
public function orWhereNotExists(Closure $callback)
{
return $this->orWhereExists($callback, true);
}
/**
* Add an exists clause to the query.
*
* @param \Illuminate\Database\Query\Builder $query
* @param string $boolean
* @param bool $not
* @return $this
*/
public function addWhereExistsQuery(Builder $query, $boolean = 'and', $not = false)
{
$type = $not ? 'NotExists' : 'Exists';
$this->wheres[] = compact('type', 'operator', 'query', 'boolean');
$this->addBinding($query->getBindings(), 'where');
return $this;
}
/**
* Add a "where in" clause to the query.
*
* @param string $column
* @param mixed $values
* @param string $boolean
* @param bool $not
* @return $this
*/
public function whereIn($column, $values, $boolean = 'and', $not = false)
{
$type = $not ? 'NotIn' : 'In';
if ($values instanceof static) {
return $this->whereInExistingQuery(
$column, $values, $boolean, $not
);
}
// If the value of the where in clause is actually a Closure, we will assume that
// the developer is using a full sub-select for this "in" statement, and will
// execute those Closures, then we can re-construct the entire sub-selects.
if ($values instanceof Closure) {
return $this->whereInSub($column, $values, $boolean, $not);
}
if ($values instanceof Arrayable) {
$values = $values->toArray();
}
$this->wheres[] = compact('type', 'column', 'values', 'boolean');
$this->addBinding($values, 'where');
return $this;
}
/**
* Add an "or where in" clause to the query.
*
* @param string $column
* @param mixed $values
* @return \Illuminate\Database\Query\Builder|static
*/
public function orWhereIn($column, $values)
{
return $this->whereIn($column, $values, 'or');
}
/**
* Add a "where not in" clause to the query.
*
* @param string $column
* @param mixed $values
* @param string $boolean
* @return \Illuminate\Database\Query\Builder|static
*/
public function whereNotIn($column, $values, $boolean = 'and')
{
return $this->whereIn($column, $values, $boolean, true);
}
/**
* Add an "or where not in" clause to the query.
*
* @param string $column
* @param mixed $values
* @return \Illuminate\Database\Query\Builder|static
*/
public function orWhereNotIn($column, $values)
{
return $this->whereNotIn($column, $values, 'or');
}
/**
* Add a where in with a sub-select to the query.
*
* @param string $column
* @param \Closure $callback
* @param string $boolean
* @param bool $not
* @return $this
*/
protected function whereInSub($column, Closure $callback, $boolean, $not)
{
$type = $not ? 'NotInSub' : 'InSub';
// To create the exists sub-select, we will actually create a query and call the
// provided callback with the query so the developer may set any of the query
// conditions they want for the in clause, then we'll put it in this array.
call_user_func($callback, $query = $this->newQuery());
$this->wheres[] = compact('type', 'column', 'query', 'boolean');
$this->addBinding($query->getBindings(), 'where');
return $this;
}
/**
* Add a external sub-select to the query.
*
* @param string $column
* @param \Illuminate\Database\Query\Builder|static $query
* @param string $boolean
* @param bool $not
* @return $this
*/
protected function whereInExistingQuery($column, $query, $boolean, $not)
{
$type = $not ? 'NotInSub' : 'InSub';
$this->wheres[] = compact('type', 'column', 'query', 'boolean');
$this->addBinding($query->getBindings(), 'where');
return $this;
}
/**
* Add a "where null" clause to the query.
*
* @param string $column
* @param string $boolean
* @param bool $not
* @return $this
*/
public function whereNull($column, $boolean = 'and', $not = false)
{
$type = $not ? 'NotNull' : 'Null';
$this->wheres[] = compact('type', 'column', 'boolean');
return $this;
}
/**
* Add an "or where null" clause to the query.
*
* @param string $column
* @return \Illuminate\Database\Query\Builder|static
*/
public function orWhereNull($column)
{
return $this->whereNull($column, 'or');
}
/**
* Add a "where not null" clause to the query.
*
* @param string $column
* @param string $boolean
* @return \Illuminate\Database\Query\Builder|static
*/
public function whereNotNull($column, $boolean = 'and')
{
return $this->whereNull($column, $boolean, true);
}
/**
* Add an "or where not null" clause to the query.
*
* @param string $column
* @return \Illuminate\Database\Query\Builder|static
*/
public function orWhereNotNull($column)
{
return $this->whereNotNull($column, 'or');
}
/**
* Add a "where date" statement to the query.
*
* @param string $column
* @param string $operator
* @param int $value
* @param string $boolean
* @return \Illuminate\Database\Query\Builder|static
*/
public function whereDate($column, $operator, $value, $boolean = 'and')
{
return $this->addDateBasedWhere('Date', $column, $operator, $value, $boolean);
}
/**
* Add an "or where date" statement to the query.
*
* @param string $column
* @param string $operator
* @param int $value
* @return \Illuminate\Database\Query\Builder|static
*/
public function orWhereDate($column, $operator, $value)
{
return $this->whereDate($column, $operator, $value, 'or');
}
/**
* Add a "where time" statement to the query.
*
* @param string $column
* @param string $operator
* @param int $value
* @param string $boolean
* @return \Illuminate\Database\Query\Builder|static
*/
public function whereTime($column, $operator, $value, $boolean = 'and')
{
return $this->addDateBasedWhere('Time', $column, $operator, $value, $boolean);
}
/**
* Add an "or where time" statement to the query.
*
* @param string $column
* @param string $operator
* @param int $value
* @return \Illuminate\Database\Query\Builder|static
*/
public function orWhereTime($column, $operator, $value)
{
return $this->whereTime($column, $operator, $value, 'or');
}
/**
* Add a "where day" statement to the query.
*
* @param string $column
* @param string $operator
* @param int $value
* @param string $boolean
* @return \Illuminate\Database\Query\Builder|static
*/
public function whereDay($column, $operator, $value, $boolean = 'and')
{
return $this->addDateBasedWhere('Day', $column, $operator, $value, $boolean);
}
/**
* Add a "where month" statement to the query.
*
* @param string $column
* @param string $operator
* @param int $value
* @param string $boolean
* @return \Illuminate\Database\Query\Builder|static
*/
public function whereMonth($column, $operator, $value, $boolean = 'and')
{
return $this->addDateBasedWhere('Month', $column, $operator, $value, $boolean);
}
/**
* Add a "where year" statement to the query.
*
* @param string $column
* @param string $operator
* @param int $value
* @param string $boolean
* @return \Illuminate\Database\Query\Builder|static
*/
public function whereYear($column, $operator, $value, $boolean = 'and')
{
return $this->addDateBasedWhere('Year', $column, $operator, $value, $boolean);
}
/**
* Add a date based (year, month, day, time) statement to the query.
*
* @param string $type
* @param string $column
* @param string $operator
* @param int $value
* @param string $boolean
* @return $this
*/
protected function addDateBasedWhere($type, $column, $operator, $value, $boolean = 'and')
{
$this->wheres[] = compact('column', 'type', 'boolean', 'operator', 'value');
$this->addBinding($value, 'where');
return $this;
}
/**
* Handles dynamic "where" clauses to the query.
*
* @param string $method
* @param string $parameters
* @return $this
*/
public function dynamicWhere($method, $parameters)
{
$finder = substr($method, 5);
$segments = preg_split('/(And|Or)(?=[A-Z])/', $finder, -1, PREG_SPLIT_DELIM_CAPTURE);
// The connector variable will determine which connector will be used for the
// query condition. We will change it as we come across new boolean values
// in the dynamic method strings, which could contain a number of these.
$connector = 'and';
$index = 0;
foreach ($segments as $segment) {
// If the segment is not a boolean connector, we can assume it is a column's name
// and we will add it to the query as a new constraint as a where clause, then
// we can keep iterating through the dynamic method string's segments again.
if ($segment != 'And' && $segment != 'Or') {
$this->addDynamic($segment, $connector, $parameters, $index);
$index++;
}
// Otherwise, we will store the connector so we know how the next where clause we
// find in the query should be connected to the previous ones, meaning we will
// have the proper boolean connector to connect the next where clause found.
else {
$connector = $segment;
}
}
return $this;
}
/**
* Add a single dynamic where clause statement to the query.
*
* @param string $segment
* @param string $connector
* @param array $parameters
* @param int $index
* @return void
*/
protected function addDynamic($segment, $connector, $parameters, $index)
{
// Once we have parsed out the columns and formatted the boolean operators we
// are ready to add it to this query as a where clause just like any other
// clause on the query. Then we'll increment the parameter index values.
$bool = strtolower($connector);
$this->where(Str::snake($segment), '=', $parameters[$index], $bool);
}
/**
* Add a "group by" clause to the query.
*
* @param array|string $column,...
* @return $this
*/
public function groupBy()
{
foreach (func_get_args() as $arg) {
$this->groups = array_merge((array) $this->groups, is_array($arg) ? $arg : [$arg]);
}
return $this;
}
/**
* Add a "having" clause to the query.
*
* @param string $column
* @param string $operator
* @param string $value
* @param string $boolean
* @return $this
*/
public function having($column, $operator = null, $value = null, $boolean = 'and')
{
$type = 'basic';
$this->havings[] = compact('type', 'column', 'operator', 'value', 'boolean');
if (! $value instanceof Expression) {
$this->addBinding($value, 'having');
}
return $this;
}
/**
* Add a "or having" clause to the query.
*
* @param string $column
* @param string $operator
* @param string $value
* @return \Illuminate\Database\Query\Builder|static
*/
public function orHaving($column, $operator = null, $value = null)
{
return $this->having($column, $operator, $value, 'or');
}
/**
* Add a raw having clause to the query.
*
* @param string $sql
* @param array $bindings
* @param string $boolean
* @return $this
*/
public function havingRaw($sql, array $bindings = [], $boolean = 'and')
{
$type = 'raw';
$this->havings[] = compact('type', 'sql', 'boolean');
$this->addBinding($bindings, 'having');
return $this;
}
/**
* Add a raw or having clause to the query.
*
* @param string $sql
* @param array $bindings
* @return \Illuminate\Database\Query\Builder|static
*/
public function orHavingRaw($sql, array $bindings = [])
{
return $this->havingRaw($sql, $bindings, 'or');
}
/**
* Add an "order by" clause to the query.
*
* @param string $column
* @param string $direction
* @return $this
*/
public function orderBy($column, $direction = 'asc')
{
$this->{$this->unions ? 'unionOrders' : 'orders'}[] = [
'column' => $column,
'direction' => strtolower($direction) == 'asc' ? 'asc' : 'desc',
];
return $this;
}
/**
* Add an "order by" clause for a timestamp to the query.
*
* @param string $column
* @return \Illuminate\Database\Query\Builder|static
*/
public function latest($column = 'created_at')
{
return $this->orderBy($column, 'desc');
}
/**
* Add an "order by" clause for a timestamp to the query.
*
* @param string $column
* @return \Illuminate\Database\Query\Builder|static
*/
public function oldest($column = 'created_at')
{
return $this->orderBy($column, 'asc');
}
/**
* Put the query's results in random order.
*
* @param string $seed
* @return $this
*/
public function inRandomOrder($seed = '')
{
return $this->orderByRaw($this->grammar->compileRandom($seed));
}
/**
* Add a raw "order by" clause to the query.
*
* @param string $sql
* @param array $bindings
* @return $this
*/
public function orderByRaw($sql, $bindings = [])
{
$property = $this->unions ? 'unionOrders' : 'orders';
$type = 'raw';
$this->{$property}[] = compact('type', 'sql');
$this->addBinding($bindings, 'order');
return $this;
}
/**
* Set the "offset" value of the query.
*
* @param int $value
* @return $this
*/
public function offset($value)
{
$property = $this->unions ? 'unionOffset' : 'offset';
$this->$property = max(0, $value);
return $this;
}
/**
* Alias to set the "offset" value of the query.
*
* @param int $value
* @return \Illuminate\Database\Query\Builder|static
*/
public function skip($value)
{
return $this->offset($value);
}
/**
* Set the "limit" value of the query.
*
* @param int $value
* @return $this
*/
public function limit($value)
{
$property = $this->unions ? 'unionLimit' : 'limit';
if ($value >= 0) {
$this->$property = $value;
}
return $this;
}
/**
* Alias to set the "limit" value of the query.
*
* @param int $value
* @return \Illuminate\Database\Query\Builder|static
*/
public function take($value)
{
return $this->limit($value);
}
/**
* Set the limit and offset for a given page.
*
* @param int $page
* @param int $perPage
* @return \Illuminate\Database\Query\Builder|static
*/
public function forPage($page, $perPage = 15)
{
return $this->skip(($page - 1) * $perPage)->take($perPage);
}
/**
* Constrain the query to the next "page" of results after a given ID.
*
* @param int $perPage
* @param int $lastId
* @param string $column
* @return \Illuminate\Database\Query\Builder|static
*/
public function forPageAfterId($perPage = 15, $lastId = 0, $column = 'id')
{
$this->orders = Collection::make($this->orders)
->reject(function ($order) use ($column) {
return $order['column'] === $column;
})->values()->all();
return $this->where($column, '>', $lastId)
->orderBy($column, 'asc')
->take($perPage);
}
/**
* Add a union statement to the query.
*
* @param \Illuminate\Database\Query\Builder|\Closure $query
* @param bool $all
* @return \Illuminate\Database\Query\Builder|static
*/
public function union($query, $all = false)
{
if ($query instanceof Closure) {
call_user_func($query, $query = $this->newQuery());
}
$this->unions[] = compact('query', 'all');
$this->addBinding($query->getBindings(), 'union');
return $this;
}
/**
* Add a union all statement to the query.
*
* @param \Illuminate\Database\Query\Builder|\Closure $query
* @return \Illuminate\Database\Query\Builder|static
*/
public function unionAll($query)
{
return $this->union($query, true);
}
/**
* Lock the selected rows in the table.
*
* @param bool $value
* @return $this
*/
public function lock($value = true)
{
$this->lock = $value;
if ($this->lock) {
$this->useWritePdo();
}
return $this;
}
/**
* Lock the selected rows in the table for updating.
*
* @return \Illuminate\Database\Query\Builder
*/
public function lockForUpdate()
{
return $this->lock(true);
}
/**
* Share lock the selected rows in the table.
*
* @return \Illuminate\Database\Query\Builder
*/
public function sharedLock()
{
return $this->lock(false);
}
/**
* Get the SQL representation of the query.
*
* @return string
*/
public function toSql()
{
return $this->grammar->compileSelect($this);
}
/**
* Execute a query for a single record by ID.
*
* @param int $id
* @param array $columns
* @return mixed|static
*/
public function find($id, $columns = ['*'])
{
return $this->where('id', '=', $id)->first($columns);
}
/**
* Get a single column's value from the first result of a query.
*
* @param string $column
* @return mixed
*/
public function value($column)
{
$result = (array) $this->first([$column]);
return count($result) > 0 ? reset($result) : null;
}
/**
* Execute the query and get the first result.
*
* @param array $columns
* @return mixed|static
*/
public function first($columns = ['*'])
{
$results = $this->take(1)->get($columns);
return count($results) > 0 ? reset($results) : null;
}
/**
* Execute the query as a "select" statement.
*
* @param array $columns
* @return array|static[]
*/
public function get($columns = ['*'])
{
$original = $this->columns;
if (is_null($original)) {
$this->columns = $columns;
}
$results = $this->processor->processSelect($this, $this->runSelect());
$this->columns = $original;
return $results;
}
/**
* Run the query as a "select" statement against the connection.
*
* @return array
*/
protected function runSelect()
{
return $this->connection->select($this->toSql(), $this->getBindings(), ! $this->useWritePdo);
}
/**
* Paginate the given query into a simple paginator.
*
* @param int $perPage
* @param array $columns
* @param string $pageName
* @param int|null $page
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
*/
public function paginate($perPage = 15, $columns = ['*'], $pageName = 'page', $page = null)
{
$page = $page ?: Paginator::resolveCurrentPage($pageName);
$total = $this->getCountForPagination($columns);
$results = $total ? $this->forPage($page, $perPage)->get($columns) : [];
return new LengthAwarePaginator($results, $total, $perPage, $page, [
'path' => Paginator::resolveCurrentPath(),
'pageName' => $pageName,
]);
}
/**
* Get a paginator only supporting simple next and previous links.
*
* This is more efficient on larger data-sets, etc.
*
* @param int $perPage
* @param array $columns
* @param string $pageName
* @param int|null $page
* @return \Illuminate\Contracts\Pagination\Paginator
*/
public function simplePaginate($perPage = 15, $columns = ['*'], $pageName = 'page', $page = null)
{
$page = $page ?: Paginator::resolveCurrentPage($pageName);
$this->skip(($page - 1) * $perPage)->take($perPage + 1);
return new Paginator($this->get($columns), $perPage, $page, [
'path' => Paginator::resolveCurrentPath(),
'pageName' => $pageName,
]);
}
/**
* Get the count of the total records for the paginator.
*
* @param array $columns
* @return int
*/
public function getCountForPagination($columns = ['*'])
{
$this->backupFieldsForCount();
$this->aggregate = ['function' => 'count', 'columns' => $this->clearSelectAliases($columns)];
$results = $this->get();
$this->aggregate = null;
$this->restoreFieldsForCount();
if (isset($this->groups)) {
return count($results);
}
return isset($results[0]) ? (int) array_change_key_case((array) $results[0])['aggregate'] : 0;
}
/**
* Backup some fields for the pagination count.
*
* @return void
*/
protected function backupFieldsForCount()
{
foreach (['orders', 'limit', 'offset', 'columns'] as $field) {
$this->backups[$field] = $this->{$field};
$this->{$field} = null;
}
foreach (['order', 'select'] as $key) {
$this->bindingBackups[$key] = $this->bindings[$key];
$this->bindings[$key] = [];
}
}
/**
* Remove the column aliases since they will break count queries.
*
* @param array $columns
* @return array
*/
protected function clearSelectAliases(array $columns)
{
return array_map(function ($column) {
return is_string($column) && ($aliasPosition = strpos(strtolower($column), ' as ')) !== false
? substr($column, 0, $aliasPosition) : $column;
}, $columns);
}
/**
* Restore some fields after the pagination count.
*
* @return void
*/
protected function restoreFieldsForCount()
{
foreach (['orders', 'limit', 'offset', 'columns'] as $field) {
$this->{$field} = $this->backups[$field];
}
foreach (['order', 'select'] as $key) {
$this->bindings[$key] = $this->bindingBackups[$key];
}
$this->backups = [];
$this->bindingBackups = [];
}
/**
* Get a generator for the given query.
*
* @return \Generator
*/
public function cursor()
{
if (is_null($this->columns)) {
$this->columns = ['*'];
}
return $this->connection->cursor(
$this->toSql(), $this->getBindings(), ! $this->useWritePdo
);
}
/**
* Chunk the results of the query.
*
* @param int $count
* @param callable $callback
* @return bool
*/
public function chunk($count, callable $callback)
{
$results = $this->forPage($page = 1, $count)->get();
while (count($results) > 0) {
// On each chunk result set, we will pass them to the callback and then let the
// developer take care of everything within the callback, which allows us to
// keep the memory low for spinning through large result sets for working.
if (call_user_func($callback, $results) === false) {
return false;
}
$page++;
$results = $this->forPage($page, $count)->get();
}
return true;
}
/**
* Chunk the results of a query by comparing numeric IDs.
*
* @param int $count
* @param callable $callback
* @param string $column
* @param string $alias
* @return bool
*/
public function chunkById($count, callable $callback, $column = 'id', $alias = null)
{
$lastId = null;
$alias = $alias ?: $column;
$results = $this->forPageAfterId($count, 0, $column)->get();
while (! empty($results)) {
if (call_user_func($callback, $results) === false) {
return false;
}
$lastId = last($results)->{$alias};
$results = $this->forPageAfterId($count, $lastId, $column)->get();
}
return true;
}
/**
* Execute a callback over each item while chunking.
*
* @param callable $callback
* @param int $count
* @return bool
*
* @throws \RuntimeException
*/
public function each(callable $callback, $count = 1000)
{
if (is_null($this->orders) && is_null($this->unionOrders)) {
throw new RuntimeException('You must specify an orderBy clause when using the "each" function.');
}
return $this->chunk($count, function ($results) use ($callback) {
foreach ($results as $key => $value) {
if ($callback($value, $key) === false) {
return false;
}
}
});
}
/**
* Get an array with the values of a given column.
*
* @param string $column
* @param string|null $key
* @return array
*/
public function pluck($column, $key = null)
{
$results = $this->get(is_null($key) ? [$column] : [$column, $key]);
// If the columns are qualified with a table or have an alias, we cannot use
// those directly in the "pluck" operations since the results from the DB
// are only keyed by the column itself. We'll strip the table out here.
return Arr::pluck(
$results,
$this->stripTableForPluck($column),
$this->stripTableForPluck($key)
);
}
/**
* Alias for the "pluck" method.
*
* @param string $column
* @param string|null $key
* @return array
*
* @deprecated since version 5.2. Use the "pluck" method directly.
*/
public function lists($column, $key = null)
{
return $this->pluck($column, $key);
}
/**
* Strip off the table name or alias from a column identifier.
*
* @param string $column
* @return string|null
*/
protected function stripTableForPluck($column)
{
return is_null($column) ? $column : last(preg_split('~\.| ~', $column));
}
/**
* Concatenate values of a given column as a string.
*
* @param string $column
* @param string $glue
* @return string
*/
public function implode($column, $glue = '')
{
return implode($glue, $this->pluck($column));
}
/**
* Determine if any rows exist for the current query.
*
* @return bool
*/
public function exists()
{
$sql = $this->grammar->compileExists($this);
$results = $this->connection->select($sql, $this->getBindings(), ! $this->useWritePdo);
if (isset($results[0])) {
$results = (array) $results[0];
return (bool) $results['exists'];
}
return false;
}
/**
* Retrieve the "count" result of the query.
*
* @param string $columns
* @return int
*/
public function count($columns = '*')
{
if (! is_array($columns)) {
$columns = [$columns];
}
return (int) $this->aggregate(__FUNCTION__, $columns);
}
/**
* Retrieve the minimum value of a given column.
*
* @param string $column
* @return mixed
*/
public function min($column)
{
return $this->aggregate(__FUNCTION__, [$column]);
}
/**
* Retrieve the maximum value of a given column.
*
* @param string $column
* @return mixed
*/
public function max($column)
{
return $this->aggregate(__FUNCTION__, [$column]);
}
/**
* Retrieve the sum of the values of a given column.
*
* @param string $column
* @return mixed
*/
public function sum($column)
{
return $this->aggregate(__FUNCTION__, [$column]);
}
/**
* Retrieve the average of the values of a given column.
*
* @param string $column
* @return mixed
*/
public function avg($column)
{
return $this->aggregate(__FUNCTION__, [$column]);
}
/**
* Alias for the "avg" method.
*
* @param string $column
* @return mixed
*/
public function average($column)
{
return $this->avg($column);
}
/**
* Execute an aggregate function on the database.
*
* @param string $function
* @param array $columns
* @return mixed
*/
public function aggregate($function, $columns = ['*'])
{
$this->aggregate = compact('function', 'columns');
$previousColumns = $this->columns;
// We will also back up the select bindings since the select clause will be
// removed when performing the aggregate function. Once the query is run
// we will add the bindings back onto this query so they can get used.
$previousSelectBindings = $this->bindings['select'];
$this->bindings['select'] = [];
$results = $this->get($columns);
// Once we have executed the query, we will reset the aggregate property so
// that more select queries can be executed against the database without
// the aggregate value getting in the way when the grammar builds it.
$this->aggregate = null;
$this->columns = $previousColumns;
$this->bindings['select'] = $previousSelectBindings;
if (isset($results[0])) {
return array_change_key_case((array) $results[0])['aggregate'];
}
}
/**
* Execute a numeric aggregate function on the database.
*
* @param string $function
* @param array $columns
* @return float|int
*/
public function numericAggregate($function, $columns = ['*'])
{
$result = $this->aggregate($function, $columns);
if (! $result) {
return 0;
}
if (is_int($result) || is_float($result)) {
return $result;
}
if (strpos((string) $result, '.') === false) {
return (int) $result;
}
return (float) $result;
}
/**
* Insert a new record into the database.
*
* @param array $values
* @return bool
*/
public function insert(array $values)
{
if (empty($values)) {
return true;
}
// Since every insert gets treated like a batch insert, we will make sure the
// bindings are structured in a way that is convenient for building these
// inserts statements by verifying the elements are actually an array.
if (! is_array(reset($values))) {
$values = [$values];
}
// Since every insert gets treated like a batch insert, we will make sure the
// bindings are structured in a way that is convenient for building these
// inserts statements by verifying the elements are actually an array.
else {
foreach ($values as $key => $value) {
ksort($value);
$values[$key] = $value;
}
}
// We'll treat every insert like a batch insert so we can easily insert each
// of the records into the database consistently. This will make it much
// easier on the grammars to just handle one type of record insertion.
$bindings = [];
foreach ($values as $record) {
foreach ($record as $value) {
$bindings[] = $value;
}
}
$sql = $this->grammar->compileInsert($this, $values);
// Once we have compiled the insert statement's SQL we can execute it on the
// connection and return a result as a boolean success indicator as that
// is the same type of result returned by the raw connection instance.
$bindings = $this->cleanBindings($bindings);
return $this->connection->insert($sql, $bindings);
}
/**
* Insert a new record and get the value of the primary key.
*
* @param array $values
* @param string $sequence
* @return int
*/
public function insertGetId(array $values, $sequence = null)
{
$sql = $this->grammar->compileInsertGetId($this, $values, $sequence);
$values = $this->cleanBindings($values);
return $this->processor->processInsertGetId($this, $sql, $values, $sequence);
}
/**
* Update a record in the database.
*
* @param array $values
* @return int
*/
public function update(array $values)
{
$bindings = array_values(array_merge($values, $this->getBindings()));
$sql = $this->grammar->compileUpdate($this, $values);
return $this->connection->update($sql, $this->cleanBindings(
$this->grammar->prepareBindingsForUpdate($bindings, $values)
));
}
/**
* Insert or update a record matching the attributes, and fill it with values.
*
* @param array $attributes
* @param array $values
* @return bool
*/
public function updateOrInsert(array $attributes, array $values = [])
{
if (! $this->where($attributes)->exists()) {
return $this->insert(array_merge($attributes, $values));
}
return (bool) $this->where($attributes)->take(1)->update($values);
}
/**
* Increment a column's value by a given amount.
*
* @param string $column
* @param int $amount
* @param array $extra
* @return int
*/
public function increment($column, $amount = 1, array $extra = [])
{
if (! is_numeric($amount)) {
throw new InvalidArgumentException('Non-numeric value passed to increment method.');
}
$wrapped = $this->grammar->wrap($column);
$columns = array_merge([$column => $this->raw("$wrapped + $amount")], $extra);
return $this->update($columns);
}
/**
* Decrement a column's value by a given amount.
*
* @param string $column
* @param int $amount
* @param array $extra
* @return int
*/
public function decrement($column, $amount = 1, array $extra = [])
{
if (! is_numeric($amount)) {
throw new InvalidArgumentException('Non-numeric value passed to decrement method.');
}
$wrapped = $this->grammar->wrap($column);
$columns = array_merge([$column => $this->raw("$wrapped - $amount")], $extra);
return $this->update($columns);
}
/**
* Delete a record from the database.
*
* @param mixed $id
* @return int
*/
public function delete($id = null)
{
// If an ID is passed to the method, we will set the where clause to check
// the ID to allow developers to simply and quickly remove a single row
// from their database without manually specifying the where clauses.
if (! is_null($id)) {
$this->where('id', '=', $id);
}
$sql = $this->grammar->compileDelete($this);
return $this->connection->delete($sql, $this->getBindings());
}
/**
* Run a truncate statement on the table.
*
* @return void
*/
public function truncate()
{
foreach ($this->grammar->compileTruncate($this) as $sql => $bindings) {
$this->connection->statement($sql, $bindings);
}
}
/**
* Get a new instance of the query builder.
*
* @return \Illuminate\Database\Query\Builder
*/
public function newQuery()
{
return new static($this->connection, $this->grammar, $this->processor);
}
/**
* Merge an array of where clauses and bindings.
*
* @param array $wheres
* @param array $bindings
* @return void
*/
public function mergeWheres($wheres, $bindings)
{
$this->wheres = array_merge((array) $this->wheres, (array) $wheres);
$this->bindings['where'] = array_values(array_merge($this->bindings['where'], (array) $bindings));
}
/**
* Remove all of the expressions from a list of bindings.
*
* @param array $bindings
* @return array
*/
protected function cleanBindings(array $bindings)
{
return array_values(array_filter($bindings, function ($binding) {
return ! $binding instanceof Expression;
}));
}
/**
* Create a raw database expression.
*
* @param mixed $value
* @return \Illuminate\Database\Query\Expression
*/
public function raw($value)
{
return $this->connection->raw($value);
}
/**
* Get the current query value bindings in a flattened array.
*
* @return array
*/
public function getBindings()
{
return Arr::flatten($this->bindings);
}
/**
* Get the raw array of bindings.
*
* @return array
*/
public function getRawBindings()
{
return $this->bindings;
}
/**
* Set the bindings on the query builder.
*
* @param array $bindings
* @param string $type
* @return $this
*
* @throws \InvalidArgumentException
*/
public function setBindings(array $bindings, $type = 'where')
{
if (! array_key_exists($type, $this->bindings)) {
throw new InvalidArgumentException("Invalid binding type: {$type}.");
}
$this->bindings[$type] = $bindings;
return $this;
}
/**
* Add a binding to the query.
*
* @param mixed $value
* @param string $type
* @return $this
*
* @throws \InvalidArgumentException
*/
public function addBinding($value, $type = 'where')
{
if (! array_key_exists($type, $this->bindings)) {
throw new InvalidArgumentException("Invalid binding type: {$type}.");
}
if (is_array($value)) {
$this->bindings[$type] = array_values(array_merge($this->bindings[$type], $value));
} else {
$this->bindings[$type][] = $value;
}
return $this;
}
/**
* Merge an array of bindings into our bindings.
*
* @param \Illuminate\Database\Query\Builder $query
* @return $this
*/
public function mergeBindings(Builder $query)
{
$this->bindings = array_merge_recursive($this->bindings, $query->bindings);
return $this;
}
/**
* Get the database connection instance.
*
* @return \Illuminate\Database\ConnectionInterface
*/
public function getConnection()
{
return $this->connection;
}
/**
* Get the database query processor instance.
*
* @return \Illuminate\Database\Query\Processors\Processor
*/
public function getProcessor()
{
return $this->processor;
}
/**
* Get the query grammar instance.
*
* @return \Illuminate\Database\Query\Grammars\Grammar
*/
public function getGrammar()
{
return $this->grammar;
}
/**
* Use the write pdo for query.
*
* @return $this
*/
public function useWritePdo()
{
$this->useWritePdo = true;
return $this;
}
/**
* Handle dynamic method calls into the method.
*
* @param string $method
* @param array $parameters
* @return mixed
*
* @throws \BadMethodCallException
*/
public function __call($method, $parameters)
{
if (static::hasMacro($method)) {
return $this->macroCall($method, $parameters);
}
if (Str::startsWith($method, 'where')) {
return $this->dynamicWhere($method, $parameters);
}
$className = static::class;
throw new BadMethodCallException("Call to undefined method {$className}::{$method}()");
}
}
Query/Grammars/SQLiteGrammar.php 0000666 00000010046 13436755161 0012623 0 ustar 00 ', '<=', '>=', '<>', '!=',
'like', 'not like', 'between', 'ilike',
'&', '|', '<<', '>>',
];
/**
* Compile an insert statement into SQL.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $values
* @return string
*/
public function compileInsert(Builder $query, array $values)
{
// Essentially we will force every insert to be treated as a batch insert which
// simply makes creating the SQL easier for us since we can utilize the same
// basic routine regardless of an amount of records given to us to insert.
$table = $this->wrapTable($query->from);
if (! is_array(reset($values))) {
$values = [$values];
}
// If there is only one record being inserted, we will just use the usual query
// grammar insert builder because no special syntax is needed for the single
// row inserts in SQLite. However, if there are multiples, we'll continue.
if (count($values) == 1) {
return parent::compileInsert($query, reset($values));
}
$names = $this->columnize(array_keys(reset($values)));
$columns = [];
// SQLite requires us to build the multi-row insert as a listing of select with
// unions joining them together. So we'll build out this list of columns and
// then join them all together with select unions to complete the queries.
foreach (array_keys(reset($values)) as $column) {
$columns[] = '? as '.$this->wrap($column);
}
$columns = array_fill(0, count($values), implode(', ', $columns));
return "insert into $table ($names) select ".implode(' union all select ', $columns);
}
/**
* Compile a truncate table statement into SQL.
*
* @param \Illuminate\Database\Query\Builder $query
* @return array
*/
public function compileTruncate(Builder $query)
{
$sql = ['delete from sqlite_sequence where name = ?' => [$query->from]];
$sql['delete from '.$this->wrapTable($query->from)] = [];
return $sql;
}
/**
* Compile a "where date" clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereDate(Builder $query, $where)
{
return $this->dateBasedWhere('%Y-%m-%d', $query, $where);
}
/**
* Compile a "where day" clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereDay(Builder $query, $where)
{
return $this->dateBasedWhere('%d', $query, $where);
}
/**
* Compile a "where month" clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereMonth(Builder $query, $where)
{
return $this->dateBasedWhere('%m', $query, $where);
}
/**
* Compile a "where year" clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereYear(Builder $query, $where)
{
return $this->dateBasedWhere('%Y', $query, $where);
}
/**
* Compile a date based where clause.
*
* @param string $type
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function dateBasedWhere($type, Builder $query, $where)
{
$value = str_pad($where['value'], 2, '0', STR_PAD_LEFT);
$value = $this->parameter($value);
return 'strftime(\''.$type.'\', '.$this->wrap($where['column']).') '.$where['operator'].' '.$value;
}
}
Query/Grammars/MySqlGrammar.php 0000666 00000015043 13436755161 0012531 0 ustar 00 unions) {
$sql = '('.$sql.') '.$this->compileUnions($query);
}
return $sql;
}
/**
* Compile a single union statement.
*
* @param array $union
* @return string
*/
protected function compileUnion(array $union)
{
$joiner = $union['all'] ? ' union all ' : ' union ';
return $joiner.'('.$union['query']->toSql().')';
}
/**
* Compile the random statement into SQL.
*
* @param string $seed
* @return string
*/
public function compileRandom($seed)
{
return 'RAND('.$seed.')';
}
/**
* Compile the lock into SQL.
*
* @param \Illuminate\Database\Query\Builder $query
* @param bool|string $value
* @return string
*/
protected function compileLock(Builder $query, $value)
{
if (is_string($value)) {
return $value;
}
return $value ? 'for update' : 'lock in share mode';
}
/**
* Compile an update statement into SQL.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $values
* @return string
*/
public function compileUpdate(Builder $query, $values)
{
$table = $this->wrapTable($query->from);
$columns = [];
// Each one of the columns in the update statements needs to be wrapped in the
// keyword identifiers, also a place-holder needs to be created for each of
// the values in the list of bindings so we can make the sets statements.
foreach ($values as $key => $value) {
if ($this->isJsonSelector($key)) {
$columns[] = $this->compileJsonUpdateColumn(
$key, new JsonExpression($value)
);
} else {
$columns[] = $this->wrap($key).' = '.$this->parameter($value);
}
}
$columns = implode(', ', $columns);
// If the query has any "join" clauses, we will setup the joins on the builder
// and compile them so we can attach them to this update, as update queries
// can get join statements to attach to other tables when they're needed.
if (isset($query->joins)) {
$joins = ' '.$this->compileJoins($query, $query->joins);
} else {
$joins = '';
}
// Of course, update queries may also be constrained by where clauses so we'll
// need to compile the where clauses and attach it to the query so only the
// intended records are updated by the SQL statements we generate to run.
$where = $this->compileWheres($query);
$sql = rtrim("update {$table}{$joins} set $columns $where");
if (isset($query->orders)) {
$sql .= ' '.$this->compileOrders($query, $query->orders);
}
if (isset($query->limit)) {
$sql .= ' '.$this->compileLimit($query, $query->limit);
}
return rtrim($sql);
}
/**
* Prepares a JSON column being updated using the JSON_SET function.
*
* @param string $key
* @param \Illuminate\Database\JsonExpression $value
* @return string
*/
protected function compileJsonUpdateColumn($key, JsonExpression $value)
{
$path = explode('->', $key);
$field = $this->wrapValue(array_shift($path));
$accessor = '"$.'.implode('.', $path).'"';
return "{$field} = json_set({$field}, {$accessor}, {$value->getValue()})";
}
/**
* Prepare the bindings for an update statement.
*
* @param array $bindings
* @param array $values
* @return array
*/
public function prepareBindingsForUpdate(array $bindings, array $values)
{
$index = 0;
foreach ($values as $column => $value) {
if ($this->isJsonSelector($column) && is_bool($value)) {
unset($bindings[$index]);
}
$index++;
}
return $bindings;
}
/**
* Compile a delete statement into SQL.
*
* @param \Illuminate\Database\Query\Builder $query
* @return string
*/
public function compileDelete(Builder $query)
{
$table = $this->wrapTable($query->from);
$where = is_array($query->wheres) ? $this->compileWheres($query) : '';
if (isset($query->joins)) {
$joins = ' '.$this->compileJoins($query, $query->joins);
$sql = trim("delete $table from {$table}{$joins} $where");
} else {
$sql = trim("delete from $table $where");
if (isset($query->orders)) {
$sql .= ' '.$this->compileOrders($query, $query->orders);
}
if (isset($query->limit)) {
$sql .= ' '.$this->compileLimit($query, $query->limit);
}
}
return $sql;
}
/**
* Wrap a single string in keyword identifiers.
*
* @param string $value
* @return string
*/
protected function wrapValue($value)
{
if ($value === '*') {
return $value;
}
if ($this->isJsonSelector($value)) {
return $this->wrapJsonSelector($value);
}
return '`'.str_replace('`', '``', $value).'`';
}
/**
* Wrap the given JSON selector.
*
* @param string $value
* @return string
*/
protected function wrapJsonSelector($value)
{
$path = explode('->', $value);
$field = $this->wrapValue(array_shift($path));
return $field.'->'.'"$.'.implode('.', $path).'"';
}
/**
* Determine if the given string is a JSON selector.
*
* @param string $value
* @return bool
*/
protected function isJsonSelector($value)
{
return Str::contains($value, '->');
}
}
Query/Grammars/PostgresGrammar.php 0000666 00000016503 13436755161 0013274 0 ustar 00 ', '<=', '>=', '<>', '!=',
'like', 'not like', 'between', 'ilike',
'&', '|', '#', '<<', '>>',
'@>', '<@', '?', '?|', '?&', '||', '-', '-', '#-',
];
/**
* Compile the lock into SQL.
*
* @param \Illuminate\Database\Query\Builder $query
* @param bool|string $value
* @return string
*/
protected function compileLock(Builder $query, $value)
{
if (is_string($value)) {
return $value;
}
return $value ? 'for update' : 'for share';
}
/**
* Compile a "where date" clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereDate(Builder $query, $where)
{
$value = $this->parameter($where['value']);
return $this->wrap($where['column']).'::date '.$where['operator'].' '.$value;
}
/**
* Compile a date based where clause.
*
* @param string $type
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function dateBasedWhere($type, Builder $query, $where)
{
$value = $this->parameter($where['value']);
return 'extract('.$type.' from '.$this->wrap($where['column']).') '.$where['operator'].' '.$value;
}
/**
* Compile an update statement into SQL.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $values
* @return string
*/
public function compileUpdate(Builder $query, $values)
{
$table = $this->wrapTable($query->from);
// Each one of the columns in the update statements needs to be wrapped in the
// keyword identifiers, also a place-holder needs to be created for each of
// the values in the list of bindings so we can make the sets statements.
$columns = $this->compileUpdateColumns($values);
$from = $this->compileUpdateFrom($query);
$where = $this->compileUpdateWheres($query);
return trim("update {$table} set {$columns}{$from} $where");
}
/**
* Compile the columns for the update statement.
*
* @param array $values
* @return string
*/
protected function compileUpdateColumns($values)
{
$columns = [];
// When gathering the columns for an update statement, we'll wrap each of the
// columns and convert it to a parameter value. Then we will concatenate a
// list of the columns that can be added into this update query clauses.
foreach ($values as $key => $value) {
$columns[] = $this->wrap($key).' = '.$this->parameter($value);
}
return implode(', ', $columns);
}
/**
* Compile the "from" clause for an update with a join.
*
* @param \Illuminate\Database\Query\Builder $query
* @return string|null
*/
protected function compileUpdateFrom(Builder $query)
{
if (! isset($query->joins)) {
return '';
}
$froms = [];
// When using Postgres, updates with joins list the joined tables in the from
// clause, which is different than other systems like MySQL. Here, we will
// compile out the tables that are joined and add them to a from clause.
foreach ($query->joins as $join) {
$froms[] = $this->wrapTable($join->table);
}
if (count($froms) > 0) {
return ' from '.implode(', ', $froms);
}
}
/**
* Compile the additional where clauses for updates with joins.
*
* @param \Illuminate\Database\Query\Builder $query
* @return string
*/
protected function compileUpdateWheres(Builder $query)
{
$baseWhere = $this->compileWheres($query);
if (! isset($query->joins)) {
return $baseWhere;
}
// Once we compile the join constraints, we will either use them as the where
// clause or append them to the existing base where clauses. If we need to
// strip the leading boolean we will do so when using as the only where.
$joinWhere = $this->compileUpdateJoinWheres($query);
if (trim($baseWhere) == '') {
return 'where '.$this->removeLeadingBoolean($joinWhere);
}
return $baseWhere.' '.$joinWhere;
}
/**
* Compile the "join" clauses for an update.
*
* @param \Illuminate\Database\Query\Builder $query
* @return string
*/
protected function compileUpdateJoinWheres(Builder $query)
{
$joinWheres = [];
// Here we will just loop through all of the join constraints and compile them
// all out then implode them. This should give us "where" like syntax after
// everything has been built and then we will join it to the real wheres.
foreach ($query->joins as $join) {
foreach ($join->clauses as $clause) {
$joinWheres[] = $this->compileJoinConstraint($clause);
}
}
return implode(' ', $joinWheres);
}
/**
* Compile an insert and get ID statement into SQL.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $values
* @param string $sequence
* @return string
*/
public function compileInsertGetId(Builder $query, $values, $sequence)
{
if (is_null($sequence)) {
$sequence = 'id';
}
return $this->compileInsert($query, $values).' returning '.$this->wrap($sequence);
}
/**
* Compile a truncate table statement into SQL.
*
* @param \Illuminate\Database\Query\Builder $query
* @return array
*/
public function compileTruncate(Builder $query)
{
return ['truncate '.$this->wrapTable($query->from).' restart identity' => []];
}
/**
* Wrap a single string in keyword identifiers.
*
* @param string $value
* @return string
*/
protected function wrapValue($value)
{
if ($value === '*') {
return $value;
}
if (Str::contains($value, '->')) {
return $this->wrapJsonSelector($value);
}
return '"'.str_replace('"', '""', $value).'"';
}
/**
* Wrap the given JSON selector.
*
* @param string $value
* @return string
*/
protected function wrapJsonSelector($value)
{
$path = explode('->', $value);
$field = $this->wrapValue(array_shift($path));
$wrappedPath = $this->wrapJsonPathAttributes($path);
$attribute = array_pop($wrappedPath);
if (! empty($wrappedPath)) {
return $field.'->'.implode('->', $wrappedPath).'->>'.$attribute;
}
return $field.'->>'.$attribute;
}
/**
* Wrap the attributes of the give JSON path.
*
* @param array $path
* @return array
*/
protected function wrapJsonPathAttributes($path)
{
return array_map(function ($attribute) {
return "'$attribute'";
}, $path);
}
}
Query/Grammars/SqlServerGrammar.php 0000666 00000024143 13436755161 0013413 0 ustar 00 ', '<=', '>=', '!<', '!>', '<>', '!=',
'like', 'not like', 'between', 'ilike',
'&', '&=', '|', '|=', '^', '^=',
];
/**
* Compile a select query into SQL.
*
* @param \Illuminate\Database\Query\Builder $query
* @return string
*/
public function compileSelect(Builder $query)
{
$original = $query->columns;
if (is_null($query->columns)) {
$query->columns = ['*'];
}
$components = $this->compileComponents($query);
// If an offset is present on the query, we will need to wrap the query in
// a big "ANSI" offset syntax block. This is very nasty compared to the
// other database systems but is necessary for implementing features.
if ($query->offset > 0) {
return $this->compileAnsiOffset($query, $components);
}
$sql = $this->concatenate($components);
$query->columns = $original;
return $sql;
}
/**
* Compile the "select *" portion of the query.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $columns
* @return string|null
*/
protected function compileColumns(Builder $query, $columns)
{
if (! is_null($query->aggregate)) {
return;
}
$select = $query->distinct ? 'select distinct ' : 'select ';
// If there is a limit on the query, but not an offset, we will add the top
// clause to the query, which serves as a "limit" type clause within the
// SQL Server system similar to the limit keywords available in MySQL.
if ($query->limit > 0 && $query->offset <= 0) {
$select .= 'top '.$query->limit.' ';
}
return $select.$this->columnize($columns);
}
/**
* Compile the "from" portion of the query.
*
* @param \Illuminate\Database\Query\Builder $query
* @param string $table
* @return string
*/
protected function compileFrom(Builder $query, $table)
{
$from = parent::compileFrom($query, $table);
if (is_string($query->lock)) {
return $from.' '.$query->lock;
}
if (! is_null($query->lock)) {
return $from.' with(rowlock,'.($query->lock ? 'updlock,' : '').'holdlock)';
}
return $from;
}
/**
* Create a full ANSI offset clause for the query.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $components
* @return string
*/
protected function compileAnsiOffset(Builder $query, $components)
{
// An ORDER BY clause is required to make this offset query work, so if one does
// not exist we'll just create a dummy clause to trick the database and so it
// does not complain about the queries for not having an "order by" clause.
if (! isset($components['orders'])) {
$components['orders'] = 'order by (select 0)';
}
// We need to add the row number to the query so we can compare it to the offset
// and limit values given for the statements. So we will add an expression to
// the "select" that will give back the row numbers on each of the records.
$orderings = $components['orders'];
$components['columns'] .= $this->compileOver($orderings);
unset($components['orders']);
// Next we need to calculate the constraints that should be placed on the query
// to get the right offset and limit from our query but if there is no limit
// set we will just handle the offset only since that is all that matters.
$constraint = $this->compileRowConstraint($query);
$sql = $this->concatenate($components);
// We are now ready to build the final SQL query so we'll create a common table
// expression from the query and get the records with row numbers within our
// given limit and offset value that we just put on as a query constraint.
return $this->compileTableExpression($sql, $constraint);
}
/**
* Compile the over statement for a table expression.
*
* @param string $orderings
* @return string
*/
protected function compileOver($orderings)
{
return ", row_number() over ({$orderings}) as row_num";
}
/**
* Compile the limit / offset row constraint for a query.
*
* @param \Illuminate\Database\Query\Builder $query
* @return string
*/
protected function compileRowConstraint($query)
{
$start = $query->offset + 1;
if ($query->limit > 0) {
$finish = $query->offset + $query->limit;
return "between {$start} and {$finish}";
}
return ">= {$start}";
}
/**
* Compile a common table expression for a query.
*
* @param string $sql
* @param string $constraint
* @return string
*/
protected function compileTableExpression($sql, $constraint)
{
return "select * from ({$sql}) as temp_table where row_num {$constraint}";
}
/**
* Compile the random statement into SQL.
*
* @param string $seed
* @return string
*/
public function compileRandom($seed)
{
return 'NEWID()';
}
/**
* Compile the "limit" portions of the query.
*
* @param \Illuminate\Database\Query\Builder $query
* @param int $limit
* @return string
*/
protected function compileLimit(Builder $query, $limit)
{
return '';
}
/**
* Compile the "offset" portions of the query.
*
* @param \Illuminate\Database\Query\Builder $query
* @param int $offset
* @return string
*/
protected function compileOffset(Builder $query, $offset)
{
return '';
}
/**
* Compile a truncate table statement into SQL.
*
* @param \Illuminate\Database\Query\Builder $query
* @return array
*/
public function compileTruncate(Builder $query)
{
return ['truncate table '.$this->wrapTable($query->from) => []];
}
/**
* Compile an exists statement into SQL.
*
* @param \Illuminate\Database\Query\Builder $query
* @return string
*/
public function compileExists(Builder $query)
{
$existsQuery = clone $query;
$existsQuery->columns = [];
return $this->compileSelect($existsQuery->selectRaw('1 [exists]')->limit(1));
}
/**
* Compile a "where date" clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereDate(Builder $query, $where)
{
$value = $this->parameter($where['value']);
return 'cast('.$this->wrap($where['column']).' as date) '.$where['operator'].' '.$value;
}
/**
* Determine if the grammar supports savepoints.
*
* @return bool
*/
public function supportsSavepoints()
{
return false;
}
/**
* Get the format for database stored dates.
*
* @return string
*/
public function getDateFormat()
{
return 'Y-m-d H:i:s.000';
}
/**
* Wrap a single string in keyword identifiers.
*
* @param string $value
* @return string
*/
protected function wrapValue($value)
{
if ($value === '*') {
return $value;
}
return '['.str_replace(']', ']]', $value).']';
}
/**
* Compile an update statement into SQL.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $values
* @return string
*/
public function compileUpdate(Builder $query, $values)
{
$table = $alias = $this->wrapTable($query->from);
if (strpos(strtolower($table), '] as [') !== false) {
$segments = explode('] as [', $table);
$alias = '['.$segments[1];
}
// Each one of the columns in the update statements needs to be wrapped in the
// keyword identifiers, also a place-holder needs to be created for each of
// the values in the list of bindings so we can make the sets statements.
$columns = [];
foreach ($values as $key => $value) {
$columns[] = $this->wrap($key).' = '.$this->parameter($value);
}
$columns = implode(', ', $columns);
// If the query has any "join" clauses, we will setup the joins on the builder
// and compile them so we can attach them to this update, as update queries
// can get join statements to attach to other tables when they're needed.
if (isset($query->joins)) {
$joins = ' '.$this->compileJoins($query, $query->joins);
} else {
$joins = '';
}
// Of course, update queries may also be constrained by where clauses so we'll
// need to compile the where clauses and attach it to the query so only the
// intended records are updated by the SQL statements we generate to run.
$where = $this->compileWheres($query);
if (! empty($joins)) {
return trim("update {$alias} set {$columns} from {$table}{$joins} {$where}");
}
return trim("update {$table}{$joins} set $columns $where");
}
/**
* Wrap a table in keyword identifiers.
*
* @param \Illuminate\Database\Query\Expression|string $table
* @return string
*/
public function wrapTable($table)
{
return $this->wrapTableValuedFunction(parent::wrapTable($table));
}
/**
* Wrap a table in keyword identifiers.
*
* @param string $table
* @return string
*/
protected function wrapTableValuedFunction($table)
{
if (preg_match('/^(.+?)(\(.*?\))]$/', $table, $matches) === 1) {
$table = $matches[1].']'.$matches[2];
}
return $table;
}
}
Query/Grammars/Grammar.php 0000666 00000061276 13436755161 0011554 0 ustar 00 columns;
if (is_null($query->columns)) {
$query->columns = ['*'];
}
$sql = trim($this->concatenate($this->compileComponents($query)));
$query->columns = $original;
return $sql;
}
/**
* Compile the components necessary for a select clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @return array
*/
protected function compileComponents(Builder $query)
{
$sql = [];
foreach ($this->selectComponents as $component) {
// To compile the query, we'll spin through each component of the query and
// see if that component exists. If it does we'll just call the compiler
// function for the component which is responsible for making the SQL.
if (! is_null($query->$component)) {
$method = 'compile'.ucfirst($component);
$sql[$component] = $this->$method($query, $query->$component);
}
}
return $sql;
}
/**
* Compile an aggregated select clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $aggregate
* @return string
*/
protected function compileAggregate(Builder $query, $aggregate)
{
$column = $this->columnize($aggregate['columns']);
// If the query has a "distinct" constraint and we're not asking for all columns
// we need to prepend "distinct" onto the column name so that the query takes
// it into account when it performs the aggregating operations on the data.
if ($query->distinct && $column !== '*') {
$column = 'distinct '.$column;
}
return 'select '.$aggregate['function'].'('.$column.') as aggregate';
}
/**
* Compile the "select *" portion of the query.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $columns
* @return string|null
*/
protected function compileColumns(Builder $query, $columns)
{
// If the query is actually performing an aggregating select, we will let that
// compiler handle the building of the select clauses, as it will need some
// more syntax that is best handled by that function to keep things neat.
if (! is_null($query->aggregate)) {
return;
}
$select = $query->distinct ? 'select distinct ' : 'select ';
return $select.$this->columnize($columns);
}
/**
* Compile the "from" portion of the query.
*
* @param \Illuminate\Database\Query\Builder $query
* @param string $table
* @return string
*/
protected function compileFrom(Builder $query, $table)
{
return 'from '.$this->wrapTable($table);
}
/**
* Compile the "join" portions of the query.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $joins
* @return string
*/
protected function compileJoins(Builder $query, $joins)
{
$sql = [];
foreach ($joins as $join) {
$table = $this->wrapTable($join->table);
$type = $join->type;
// Cross joins generate a cartesian product between this first table and a joined
// table. In case the user didn't specify any "on" clauses on the join we will
// append this SQL and jump right back into the next iteration of this loop.
if ($type === 'cross' && ! $join->clauses) {
$sql[] = "cross join $table";
continue;
}
// First we need to build all of the "on" clauses for the join. There may be many
// of these clauses so we will need to iterate through each one and build them
// separately, then we'll join them up into a single string when we're done.
$clauses = [];
foreach ($join->clauses as $clause) {
$clauses[] = $this->compileJoinConstraint($clause);
}
// Once we have constructed the clauses, we'll need to take the boolean connector
// off of the first clause as it obviously will not be required on that clause
// because it leads the rest of the clauses, thus not requiring any boolean.
$clauses[0] = $this->removeLeadingBoolean($clauses[0]);
$clauses = implode(' ', $clauses);
// Once we have everything ready to go, we will just concatenate all the parts to
// build the final join statement SQL for the query and we can then return the
// final clause back to the callers as a single, stringified join statement.
$sql[] = "$type join $table on $clauses";
}
return implode(' ', $sql);
}
/**
* Create a join clause constraint segment.
*
* @param array $clause
* @return string
*/
protected function compileJoinConstraint(array $clause)
{
if ($clause['nested']) {
return $this->compileNestedJoinConstraint($clause);
}
$first = $this->wrap($clause['first']);
if ($clause['where']) {
if ($clause['operator'] === 'in' || $clause['operator'] === 'not in') {
$second = '('.implode(', ', array_fill(0, $clause['second'], '?')).')';
} else {
$second = '?';
}
} else {
$second = $this->wrap($clause['second']);
}
return "{$clause['boolean']} $first {$clause['operator']} $second";
}
/**
* Create a nested join clause constraint segment.
*
* @param array $clause
* @return string
*/
protected function compileNestedJoinConstraint(array $clause)
{
$clauses = [];
foreach ($clause['join']->clauses as $nestedClause) {
$clauses[] = $this->compileJoinConstraint($nestedClause);
}
$clauses[0] = $this->removeLeadingBoolean($clauses[0]);
$clauses = implode(' ', $clauses);
return "{$clause['boolean']} ({$clauses})";
}
/**
* Compile the "where" portions of the query.
*
* @param \Illuminate\Database\Query\Builder $query
* @return string
*/
protected function compileWheres(Builder $query)
{
$sql = [];
if (is_null($query->wheres)) {
return '';
}
// Each type of where clauses has its own compiler function which is responsible
// for actually creating the where clauses SQL. This helps keep the code nice
// and maintainable since each clause has a very small method that it uses.
foreach ($query->wheres as $where) {
$method = "where{$where['type']}";
$sql[] = $where['boolean'].' '.$this->$method($query, $where);
}
// If we actually have some where clauses, we will strip off the first boolean
// operator, which is added by the query builders for convenience so we can
// avoid checking for the first clauses in each of the compilers methods.
if (count($sql) > 0) {
$sql = implode(' ', $sql);
return 'where '.$this->removeLeadingBoolean($sql);
}
return '';
}
/**
* Compile a nested where clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereNested(Builder $query, $where)
{
$nested = $where['query'];
return '('.substr($this->compileWheres($nested), 6).')';
}
/**
* Compile a where condition with a sub-select.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereSub(Builder $query, $where)
{
$select = $this->compileSelect($where['query']);
return $this->wrap($where['column']).' '.$where['operator']." ($select)";
}
/**
* Compile a basic where clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereBasic(Builder $query, $where)
{
$value = $this->parameter($where['value']);
return $this->wrap($where['column']).' '.$where['operator'].' '.$value;
}
/**
* Compile a where clause comparing two columns..
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereColumn(Builder $query, $where)
{
$second = $this->wrap($where['second']);
return $this->wrap($where['first']).' '.$where['operator'].' '.$second;
}
/**
* Compile a "between" where clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereBetween(Builder $query, $where)
{
$between = $where['not'] ? 'not between' : 'between';
return $this->wrap($where['column']).' '.$between.' ? and ?';
}
/**
* Compile a where exists clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereExists(Builder $query, $where)
{
return 'exists ('.$this->compileSelect($where['query']).')';
}
/**
* Compile a where exists clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereNotExists(Builder $query, $where)
{
return 'not exists ('.$this->compileSelect($where['query']).')';
}
/**
* Compile a "where in" clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereIn(Builder $query, $where)
{
if (empty($where['values'])) {
return '0 = 1';
}
$values = $this->parameterize($where['values']);
return $this->wrap($where['column']).' in ('.$values.')';
}
/**
* Compile a "where not in" clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereNotIn(Builder $query, $where)
{
if (empty($where['values'])) {
return '1 = 1';
}
$values = $this->parameterize($where['values']);
return $this->wrap($where['column']).' not in ('.$values.')';
}
/**
* Compile a where in sub-select clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereInSub(Builder $query, $where)
{
$select = $this->compileSelect($where['query']);
return $this->wrap($where['column']).' in ('.$select.')';
}
/**
* Compile a where not in sub-select clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereNotInSub(Builder $query, $where)
{
$select = $this->compileSelect($where['query']);
return $this->wrap($where['column']).' not in ('.$select.')';
}
/**
* Compile a "where null" clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereNull(Builder $query, $where)
{
return $this->wrap($where['column']).' is null';
}
/**
* Compile a "where not null" clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereNotNull(Builder $query, $where)
{
return $this->wrap($where['column']).' is not null';
}
/**
* Compile a "where date" clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereDate(Builder $query, $where)
{
return $this->dateBasedWhere('date', $query, $where);
}
/**
* Compile a "where time" clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereTime(Builder $query, $where)
{
return $this->dateBasedWhere('time', $query, $where);
}
/**
* Compile a "where day" clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereDay(Builder $query, $where)
{
return $this->dateBasedWhere('day', $query, $where);
}
/**
* Compile a "where month" clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereMonth(Builder $query, $where)
{
return $this->dateBasedWhere('month', $query, $where);
}
/**
* Compile a "where year" clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereYear(Builder $query, $where)
{
return $this->dateBasedWhere('year', $query, $where);
}
/**
* Compile a date based where clause.
*
* @param string $type
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function dateBasedWhere($type, Builder $query, $where)
{
$value = $this->parameter($where['value']);
return $type.'('.$this->wrap($where['column']).') '.$where['operator'].' '.$value;
}
/**
* Compile a raw where clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereRaw(Builder $query, $where)
{
return $where['sql'];
}
/**
* Compile the "group by" portions of the query.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $groups
* @return string
*/
protected function compileGroups(Builder $query, $groups)
{
return 'group by '.$this->columnize($groups);
}
/**
* Compile the "having" portions of the query.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $havings
* @return string
*/
protected function compileHavings(Builder $query, $havings)
{
$sql = implode(' ', array_map([$this, 'compileHaving'], $havings));
return 'having '.$this->removeLeadingBoolean($sql);
}
/**
* Compile a single having clause.
*
* @param array $having
* @return string
*/
protected function compileHaving(array $having)
{
// If the having clause is "raw", we can just return the clause straight away
// without doing any more processing on it. Otherwise, we will compile the
// clause into SQL based on the components that make it up from builder.
if ($having['type'] === 'raw') {
return $having['boolean'].' '.$having['sql'];
}
return $this->compileBasicHaving($having);
}
/**
* Compile a basic having clause.
*
* @param array $having
* @return string
*/
protected function compileBasicHaving($having)
{
$column = $this->wrap($having['column']);
$parameter = $this->parameter($having['value']);
return $having['boolean'].' '.$column.' '.$having['operator'].' '.$parameter;
}
/**
* Compile the "order by" portions of the query.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $orders
* @return string
*/
protected function compileOrders(Builder $query, $orders)
{
return 'order by '.implode(', ', array_map(function ($order) {
if (isset($order['sql'])) {
return $order['sql'];
}
return $this->wrap($order['column']).' '.$order['direction'];
}, $orders));
}
/**
* Compile the random statement into SQL.
*
* @param string $seed
* @return string
*/
public function compileRandom($seed)
{
return 'RANDOM()';
}
/**
* Compile the "limit" portions of the query.
*
* @param \Illuminate\Database\Query\Builder $query
* @param int $limit
* @return string
*/
protected function compileLimit(Builder $query, $limit)
{
return 'limit '.(int) $limit;
}
/**
* Compile the "offset" portions of the query.
*
* @param \Illuminate\Database\Query\Builder $query
* @param int $offset
* @return string
*/
protected function compileOffset(Builder $query, $offset)
{
return 'offset '.(int) $offset;
}
/**
* Compile the "union" queries attached to the main query.
*
* @param \Illuminate\Database\Query\Builder $query
* @return string
*/
protected function compileUnions(Builder $query)
{
$sql = '';
foreach ($query->unions as $union) {
$sql .= $this->compileUnion($union);
}
if (isset($query->unionOrders)) {
$sql .= ' '.$this->compileOrders($query, $query->unionOrders);
}
if (isset($query->unionLimit)) {
$sql .= ' '.$this->compileLimit($query, $query->unionLimit);
}
if (isset($query->unionOffset)) {
$sql .= ' '.$this->compileOffset($query, $query->unionOffset);
}
return ltrim($sql);
}
/**
* Compile a single union statement.
*
* @param array $union
* @return string
*/
protected function compileUnion(array $union)
{
$joiner = $union['all'] ? ' union all ' : ' union ';
return $joiner.$union['query']->toSql();
}
/**
* Compile an exists statement into SQL.
*
* @param \Illuminate\Database\Query\Builder $query
* @return string
*/
public function compileExists(Builder $query)
{
$select = $this->compileSelect($query);
return "select exists($select) as {$this->wrap('exists')}";
}
/**
* Compile an insert statement into SQL.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $values
* @return string
*/
public function compileInsert(Builder $query, array $values)
{
// Essentially we will force every insert to be treated as a batch insert which
// simply makes creating the SQL easier for us since we can utilize the same
// basic routine regardless of an amount of records given to us to insert.
$table = $this->wrapTable($query->from);
if (! is_array(reset($values))) {
$values = [$values];
}
$columns = $this->columnize(array_keys(reset($values)));
// We need to build a list of parameter place-holders of values that are bound
// to the query. Each insert should have the exact same amount of parameter
// bindings so we will loop through the record and parameterize them all.
$parameters = [];
foreach ($values as $record) {
$parameters[] = '('.$this->parameterize($record).')';
}
$parameters = implode(', ', $parameters);
return "insert into $table ($columns) values $parameters";
}
/**
* Compile an insert and get ID statement into SQL.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $values
* @param string $sequence
* @return string
*/
public function compileInsertGetId(Builder $query, $values, $sequence)
{
return $this->compileInsert($query, $values);
}
/**
* Compile an update statement into SQL.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $values
* @return string
*/
public function compileUpdate(Builder $query, $values)
{
$table = $this->wrapTable($query->from);
// Each one of the columns in the update statements needs to be wrapped in the
// keyword identifiers, also a place-holder needs to be created for each of
// the values in the list of bindings so we can make the sets statements.
$columns = [];
foreach ($values as $key => $value) {
$columns[] = $this->wrap($key).' = '.$this->parameter($value);
}
$columns = implode(', ', $columns);
// If the query has any "join" clauses, we will setup the joins on the builder
// and compile them so we can attach them to this update, as update queries
// can get join statements to attach to other tables when they're needed.
if (isset($query->joins)) {
$joins = ' '.$this->compileJoins($query, $query->joins);
} else {
$joins = '';
}
// Of course, update queries may also be constrained by where clauses so we'll
// need to compile the where clauses and attach it to the query so only the
// intended records are updated by the SQL statements we generate to run.
$where = $this->compileWheres($query);
return trim("update {$table}{$joins} set $columns $where");
}
/**
* Prepare the bindings for an update statement.
*
* @param array $bindings
* @param array $values
* @return array
*/
public function prepareBindingsForUpdate(array $bindings, array $values)
{
return $bindings;
}
/**
* Compile a delete statement into SQL.
*
* @param \Illuminate\Database\Query\Builder $query
* @return string
*/
public function compileDelete(Builder $query)
{
$table = $this->wrapTable($query->from);
$where = is_array($query->wheres) ? $this->compileWheres($query) : '';
return trim("delete from $table ".$where);
}
/**
* Compile a truncate table statement into SQL.
*
* @param \Illuminate\Database\Query\Builder $query
* @return array
*/
public function compileTruncate(Builder $query)
{
return ['truncate '.$this->wrapTable($query->from) => []];
}
/**
* Compile the lock into SQL.
*
* @param \Illuminate\Database\Query\Builder $query
* @param bool|string $value
* @return string
*/
protected function compileLock(Builder $query, $value)
{
return is_string($value) ? $value : '';
}
/**
* Determine if the grammar supports savepoints.
*
* @return bool
*/
public function supportsSavepoints()
{
return true;
}
/**
* Compile the SQL statement to define a savepoint.
*
* @param string $name
* @return string
*/
public function compileSavepoint($name)
{
return 'SAVEPOINT '.$name;
}
/**
* Compile the SQL statement to execute a savepoint rollback.
*
* @param string $name
* @return string
*/
public function compileSavepointRollBack($name)
{
return 'ROLLBACK TO SAVEPOINT '.$name;
}
/**
* Concatenate an array of segments, removing empties.
*
* @param array $segments
* @return string
*/
protected function concatenate($segments)
{
return implode(' ', array_filter($segments, function ($value) {
return (string) $value !== '';
}));
}
/**
* Remove the leading boolean from a statement.
*
* @param string $value
* @return string
*/
protected function removeLeadingBoolean($value)
{
return preg_replace('/and |or /i', '', $value, 1);
}
/**
* Get the gramar specific operators.
*
* @return array
*/
public function getOperators()
{
return $this->operators;
}
}
Query/Expression.php 0000666 00000001266 13436755161 0010545 0 ustar 00 value = $value;
}
/**
* Get the value of the expression.
*
* @return mixed
*/
public function getValue()
{
return $this->value;
}
/**
* Get the value of the expression.
*
* @return string
*/
public function __toString()
{
return (string) $this->getValue();
}
}
Seeder.php 0000666 00000003563 13436755161 0006512 0 ustar 00 resolve($class)->run();
if (isset($this->command)) {
$this->command->getOutput()->writeln("Seeded: $class");
}
}
/**
* Resolve an instance of the given seeder class.
*
* @param string $class
* @return \Illuminate\Database\Seeder
*/
protected function resolve($class)
{
if (isset($this->container)) {
$instance = $this->container->make($class);
$instance->setContainer($this->container);
} else {
$instance = new $class;
}
if (isset($this->command)) {
$instance->setCommand($this->command);
}
return $instance;
}
/**
* Set the IoC container instance.
*
* @param \Illuminate\Container\Container $container
* @return $this
*/
public function setContainer(Container $container)
{
$this->container = $container;
return $this;
}
/**
* Set the console command instance.
*
* @param \Illuminate\Console\Command $command
* @return $this
*/
public function setCommand(Command $command)
{
$this->command = $command;
return $this;
}
}
composer.json 0000666 00000002612 13436755161 0007306 0 ustar 00 {
"name": "illuminate/database",
"description": "The Illuminate Database package.",
"license": "MIT",
"homepage": "http://laravel.com",
"support": {
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
"keywords": ["laravel", "database", "sql", "orm"],
"authors": [
{
"name": "Taylor Otwell",
"email": "taylor@laravel.com"
}
],
"require": {
"php": ">=5.5.9",
"illuminate/container": "5.2.*",
"illuminate/contracts": "5.2.*",
"illuminate/support": "5.2.*",
"nesbot/carbon": "~1.20"
},
"autoload": {
"psr-4": {
"Illuminate\\Database\\": ""
}
},
"extra": {
"branch-alias": {
"dev-master": "5.2-dev"
}
},
"suggest": {
"doctrine/dbal": "Required to rename columns and drop SQLite columns (~2.4).",
"fzaninotto/faker": "Required to use the eloquent factory builder (~1.4).",
"illuminate/console": "Required to use the database commands (5.2.*).",
"illuminate/events": "Required to use the observers with Eloquent (5.2.*).",
"illuminate/filesystem": "Required to use the migrations (5.2.*).",
"illuminate/pagination": "Required to paginate the result set (5.2.*)."
},
"minimum-stability": "dev"
}
DatabaseManager.php 0000666 00000021042 13436755161 0010272 0 ustar 00 app = $app;
$this->factory = $factory;
}
/**
* Get a database connection instance.
*
* @param string $name
* @return \Illuminate\Database\Connection
*/
public function connection($name = null)
{
list($name, $type) = $this->parseConnectionName($name);
// If we haven't created this connection, we'll create it based on the config
// provided in the application. Once we've created the connections we will
// set the "fetch mode" for PDO which determines the query return types.
if (! isset($this->connections[$name])) {
$connection = $this->makeConnection($name);
$this->setPdoForType($connection, $type);
$this->connections[$name] = $this->prepare($connection);
}
return $this->connections[$name];
}
/**
* Parse the connection into an array of the name and read / write type.
*
* @param string $name
* @return array
*/
protected function parseConnectionName($name)
{
$name = $name ?: $this->getDefaultConnection();
return Str::endsWith($name, ['::read', '::write'])
? explode('::', $name, 2) : [$name, null];
}
/**
* Disconnect from the given database and remove from local cache.
*
* @param string $name
* @return void
*/
public function purge($name = null)
{
$this->disconnect($name);
unset($this->connections[$name]);
}
/**
* Disconnect from the given database.
*
* @param string $name
* @return void
*/
public function disconnect($name = null)
{
if (isset($this->connections[$name = $name ?: $this->getDefaultConnection()])) {
$this->connections[$name]->disconnect();
}
}
/**
* Reconnect to the given database.
*
* @param string $name
* @return \Illuminate\Database\Connection
*/
public function reconnect($name = null)
{
$this->disconnect($name = $name ?: $this->getDefaultConnection());
if (! isset($this->connections[$name])) {
return $this->connection($name);
}
return $this->refreshPdoConnections($name);
}
/**
* Refresh the PDO connections on a given connection.
*
* @param string $name
* @return \Illuminate\Database\Connection
*/
protected function refreshPdoConnections($name)
{
$fresh = $this->makeConnection($name);
return $this->connections[$name]
->setPdo($fresh->getPdo())
->setReadPdo($fresh->getReadPdo());
}
/**
* Make the database connection instance.
*
* @param string $name
* @return \Illuminate\Database\Connection
*/
protected function makeConnection($name)
{
$config = $this->getConfig($name);
// First we will check by the connection name to see if an extension has been
// registered specifically for that connection. If it has we will call the
// Closure and pass it the config allowing it to resolve the connection.
if (isset($this->extensions[$name])) {
return call_user_func($this->extensions[$name], $config, $name);
}
$driver = $config['driver'];
// Next we will check to see if an extension has been registered for a driver
// and will call the Closure if so, which allows us to have a more generic
// resolver for the drivers themselves which applies to all connections.
if (isset($this->extensions[$driver])) {
return call_user_func($this->extensions[$driver], $config, $name);
}
return $this->factory->make($config, $name);
}
/**
* Prepare the database connection instance.
*
* @param \Illuminate\Database\Connection $connection
* @return \Illuminate\Database\Connection
*/
protected function prepare(Connection $connection)
{
$connection->setFetchMode($this->app['config']['database.fetch']);
if ($this->app->bound('events')) {
$connection->setEventDispatcher($this->app['events']);
}
// Here we'll set a reconnector callback. This reconnector can be any callable
// so we will set a Closure to reconnect from this manager with the name of
// the connection, which will allow us to reconnect from the connections.
$connection->setReconnector(function ($connection) {
$this->reconnect($connection->getName());
});
return $connection;
}
/**
* Prepare the read write mode for database connection instance.
*
* @param \Illuminate\Database\Connection $connection
* @param string $type
* @return \Illuminate\Database\Connection
*/
protected function setPdoForType(Connection $connection, $type = null)
{
if ($type == 'read') {
$connection->setPdo($connection->getReadPdo());
} elseif ($type == 'write') {
$connection->setReadPdo($connection->getPdo());
}
return $connection;
}
/**
* Get the configuration for a connection.
*
* @param string $name
* @return array
*
* @throws \InvalidArgumentException
*/
protected function getConfig($name)
{
$name = $name ?: $this->getDefaultConnection();
// To get the database connection configuration, we will just pull each of the
// connection configurations and get the configurations for the given name.
// If the configuration doesn't exist, we'll throw an exception and bail.
$connections = $this->app['config']['database.connections'];
if (is_null($config = Arr::get($connections, $name))) {
throw new InvalidArgumentException("Database [$name] not configured.");
}
return $config;
}
/**
* Get the default connection name.
*
* @return string
*/
public function getDefaultConnection()
{
return $this->app['config']['database.default'];
}
/**
* Set the default connection name.
*
* @param string $name
* @return void
*/
public function setDefaultConnection($name)
{
$this->app['config']['database.default'] = $name;
}
/**
* Get all of the support drivers.
*
* @return array
*/
public function supportedDrivers()
{
return ['mysql', 'pgsql', 'sqlite', 'sqlsrv'];
}
/**
* Get all of the drivers that are actually available.
*
* @return array
*/
public function availableDrivers()
{
return array_intersect($this->supportedDrivers(), str_replace('dblib', 'sqlsrv', PDO::getAvailableDrivers()));
}
/**
* Register an extension connection resolver.
*
* @param string $name
* @param callable $resolver
* @return void
*/
public function extend($name, callable $resolver)
{
$this->extensions[$name] = $resolver;
}
/**
* Return all of the created connections.
*
* @return array
*/
public function getConnections()
{
return $this->connections;
}
/**
* Dynamically pass methods to the default connection.
*
* @param string $method
* @param array $parameters
* @return mixed
*/
public function __call($method, $parameters)
{
return call_user_func_array([$this->connection(), $method], $parameters);
}
}
SQLiteConnection.php 0000666 00000002423 13436755161 0010456 0 ustar 00 withTablePrefix(new QueryGrammar);
}
/**
* Get the default schema grammar instance.
*
* @return \Illuminate\Database\Schema\Grammars\SQLiteGrammar
*/
protected function getDefaultSchemaGrammar()
{
return $this->withTablePrefix(new SchemaGrammar);
}
/**
* Get the default post processor instance.
*
* @return \Illuminate\Database\Query\Processors\SQLiteProcessor
*/
protected function getDefaultPostProcessor()
{
return new SQLiteProcessor;
}
/**
* Get the Doctrine DBAL driver.
*
* @return \Doctrine\DBAL\Driver\PDOSqlite\Driver
*/
protected function getDoctrineDriver()
{
return new DoctrineDriver;
}
}
SqlServerConnection.php 0000666 00000005012 13436755161 0011240 0 ustar 00 getDriverName() == 'sqlsrv') {
return parent::transaction($callback);
}
$this->getPdo()->exec('BEGIN TRAN');
// We'll simply execute the given callback within a try / catch block
// and if we catch any exception we can rollback the transaction
// so that none of the changes are persisted to the database.
try {
$result = $callback($this);
$this->getPdo()->exec('COMMIT TRAN');
}
// If we catch an exception, we will roll back so nothing gets messed
// up in the database. Then we'll re-throw the exception so it can
// be handled how the developer sees fit for their applications.
catch (Exception $e) {
$this->getPdo()->exec('ROLLBACK TRAN');
throw $e;
} catch (Throwable $e) {
$this->getPdo()->exec('ROLLBACK TRAN');
throw $e;
}
return $result;
}
/**
* Get the default query grammar instance.
*
* @return \Illuminate\Database\Query\Grammars\SqlServerGrammar
*/
protected function getDefaultQueryGrammar()
{
return $this->withTablePrefix(new QueryGrammar);
}
/**
* Get the default schema grammar instance.
*
* @return \Illuminate\Database\Schema\Grammars\SqlServerGrammar
*/
protected function getDefaultSchemaGrammar()
{
return $this->withTablePrefix(new SchemaGrammar);
}
/**
* Get the default post processor instance.
*
* @return \Illuminate\Database\Query\Processors\SqlServerProcessor
*/
protected function getDefaultPostProcessor()
{
return new SqlServerProcessor;
}
/**
* Get the Doctrine DBAL driver.
*
* @return \Doctrine\DBAL\Driver\PDOSqlsrv\Driver
*/
protected function getDoctrineDriver()
{
return new DoctrineDriver;
}
}
DetectsLostConnections.php 0000666 00000001544 13436755161 0011740 0 ustar 00 getMessage();
return Str::contains($message, [
'server has gone away',
'no connection to the server',
'Lost connection',
'is dead or not enabled',
'Error while sending',
'decryption failed or bad record mac',
'server closed the connection unexpectedly',
'SSL connection has been closed unexpectedly',
'Error writing data to the connection',
'Resource deadlock avoided',
]);
}
}
Grammar.php 0000666 00000010614 13436755161 0006664 0 ustar 00 isExpression($table)) {
return $this->getValue($table);
}
return $this->wrap($this->tablePrefix.$table, true);
}
/**
* Wrap a value in keyword identifiers.
*
* @param \Illuminate\Database\Query\Expression|string $value
* @param bool $prefixAlias
* @return string
*/
public function wrap($value, $prefixAlias = false)
{
if ($this->isExpression($value)) {
return $this->getValue($value);
}
// If the value being wrapped has a column alias we will need to separate out
// the pieces so we can wrap each of the segments of the expression on it
// own, and then joins them both back together with the "as" connector.
if (strpos(strtolower($value), ' as ') !== false) {
$segments = explode(' ', $value);
if ($prefixAlias) {
$segments[2] = $this->tablePrefix.$segments[2];
}
return $this->wrap($segments[0]).' as '.$this->wrapValue($segments[2]);
}
$wrapped = [];
$segments = explode('.', $value);
// If the value is not an aliased table expression, we'll just wrap it like
// normal, so if there is more than one segment, we will wrap the first
// segments as if it was a table and the rest as just regular values.
foreach ($segments as $key => $segment) {
if ($key == 0 && count($segments) > 1) {
$wrapped[] = $this->wrapTable($segment);
} else {
$wrapped[] = $this->wrapValue($segment);
}
}
return implode('.', $wrapped);
}
/**
* Wrap a single string in keyword identifiers.
*
* @param string $value
* @return string
*/
protected function wrapValue($value)
{
if ($value === '*') {
return $value;
}
return '"'.str_replace('"', '""', $value).'"';
}
/**
* Convert an array of column names into a delimited string.
*
* @param array $columns
* @return string
*/
public function columnize(array $columns)
{
return implode(', ', array_map([$this, 'wrap'], $columns));
}
/**
* Create query parameter place-holders for an array.
*
* @param array $values
* @return string
*/
public function parameterize(array $values)
{
return implode(', ', array_map([$this, 'parameter'], $values));
}
/**
* Get the appropriate query parameter place-holder for a value.
*
* @param mixed $value
* @return string
*/
public function parameter($value)
{
return $this->isExpression($value) ? $this->getValue($value) : '?';
}
/**
* Get the value of a raw expression.
*
* @param \Illuminate\Database\Query\Expression $expression
* @return string
*/
public function getValue($expression)
{
return $expression->getValue();
}
/**
* Determine if the given value is a raw expression.
*
* @param mixed $value
* @return bool
*/
public function isExpression($value)
{
return $value instanceof Expression;
}
/**
* Get the format for database stored dates.
*
* @return string
*/
public function getDateFormat()
{
return 'Y-m-d H:i:s';
}
/**
* Get the grammar's table prefix.
*
* @return string
*/
public function getTablePrefix()
{
return $this->tablePrefix;
}
/**
* Set the grammar's table prefix.
*
* @param string $prefix
* @return $this
*/
public function setTablePrefix($prefix)
{
$this->tablePrefix = $prefix;
return $this;
}
}
Migrations/Migrator.php 0000666 00000026711 13436755161 0011203 0 ustar 00 files = $files;
$this->resolver = $resolver;
$this->repository = $repository;
}
/**
* Run the outstanding migrations at a given path.
*
* @param string $path
* @param array $options
* @return void
*/
public function run($path, array $options = [])
{
$this->notes = [];
$files = $this->getMigrationFiles($path);
// Once we grab all of the migration files for the path, we will compare them
// against the migrations that have already been run for this package then
// run each of the outstanding migrations against a database connection.
$ran = $this->repository->getRan();
$migrations = array_diff($files, $ran);
$this->requireFiles($path, $migrations);
$this->runMigrationList($migrations, $options);
}
/**
* Run an array of migrations.
*
* @param array $migrations
* @param array $options
* @return void
*/
public function runMigrationList($migrations, array $options = [])
{
// First we will just make sure that there are any migrations to run. If there
// aren't, we will just make a note of it to the developer so they're aware
// that all of the migrations have been run against this database system.
if (count($migrations) == 0) {
$this->note('Nothing to migrate.');
return;
}
$batch = $this->repository->getNextBatchNumber();
$pretend = Arr::get($options, 'pretend', false);
$step = Arr::get($options, 'step', false);
// Once we have the array of migrations, we will spin through them and run the
// migrations "up" so the changes are made to the databases. We'll then log
// that the migration was run so we don't repeat it next time we execute.
foreach ($migrations as $file) {
$this->runUp($file, $batch, $pretend);
// If we are stepping through the migrations, then we will increment the
// batch value for each individual migration that is run. That way we
// can run "artisan migrate:rollback" and undo them one at a time.
if ($step) {
$batch++;
}
}
}
/**
* Run "up" a migration instance.
*
* @param string $file
* @param int $batch
* @param bool $pretend
* @return void
*/
protected function runUp($file, $batch, $pretend)
{
// First we will resolve a "real" instance of the migration class from this
// migration file name. Once we have the instances we can run the actual
// command such as "up" or "down", or we can just simulate the action.
$migration = $this->resolve($file);
if ($pretend) {
return $this->pretendToRun($migration, 'up');
}
$migration->up();
// Once we have run a migrations class, we will log that it was run in this
// repository so that we don't try to run it next time we do a migration
// in the application. A migration repository keeps the migrate order.
$this->repository->log($file, $batch);
$this->note("Migrated: $file");
}
/**
* Rollback the last migration operation.
*
* @param bool $pretend
* @return int
*/
public function rollback($pretend = false)
{
$this->notes = [];
// We want to pull in the last batch of migrations that ran on the previous
// migration operation. We'll then reverse those migrations and run each
// of them "down" to reverse the last migration "operation" which ran.
$migrations = $this->repository->getLast();
$count = count($migrations);
if ($count === 0) {
$this->note('Nothing to rollback.');
} else {
// We need to reverse these migrations so that they are "downed" in reverse
// to what they run on "up". It lets us backtrack through the migrations
// and properly reverse the entire database schema operation that ran.
foreach ($migrations as $migration) {
$this->runDown((object) $migration, $pretend);
}
}
return $count;
}
/**
* Rolls all of the currently applied migrations back.
*
* @param bool $pretend
* @return int
*/
public function reset($pretend = false)
{
$this->notes = [];
$migrations = array_reverse($this->repository->getRan());
$count = count($migrations);
if ($count === 0) {
$this->note('Nothing to rollback.');
} else {
foreach ($migrations as $migration) {
$this->runDown((object) ['migration' => $migration], $pretend);
}
}
return $count;
}
/**
* Run "down" a migration instance.
*
* @param object $migration
* @param bool $pretend
* @return void
*/
protected function runDown($migration, $pretend)
{
$file = $migration->migration;
// First we will get the file name of the migration so we can resolve out an
// instance of the migration. Once we get an instance we can either run a
// pretend execution of the migration or we can run the real migration.
$instance = $this->resolve($file);
if ($pretend) {
return $this->pretendToRun($instance, 'down');
}
$instance->down();
// Once we have successfully run the migration "down" we will remove it from
// the migration repository so it will be considered to have not been run
// by the application then will be able to fire by any later operation.
$this->repository->delete($migration);
$this->note("Rolled back: $file");
}
/**
* Get all of the migration files in a given path.
*
* @param string $path
* @return array
*/
public function getMigrationFiles($path)
{
$files = $this->files->glob($path.'/*_*.php');
// Once we have the array of files in the directory we will just remove the
// extension and take the basename of the file which is all we need when
// finding the migrations that haven't been run against the databases.
if ($files === false) {
return [];
}
$files = array_map(function ($file) {
return str_replace('.php', '', basename($file));
}, $files);
// Once we have all of the formatted file names we will sort them and since
// they all start with a timestamp this should give us the migrations in
// the order they were actually created by the application developers.
sort($files);
return $files;
}
/**
* Require in all the migration files in a given path.
*
* @param string $path
* @param array $files
* @return void
*/
public function requireFiles($path, array $files)
{
foreach ($files as $file) {
$this->files->requireOnce($path.'/'.$file.'.php');
}
}
/**
* Pretend to run the migrations.
*
* @param object $migration
* @param string $method
* @return void
*/
protected function pretendToRun($migration, $method)
{
foreach ($this->getQueries($migration, $method) as $query) {
$name = get_class($migration);
$this->note("{$name}: {$query['query']}");
}
}
/**
* Get all of the queries that would be run for a migration.
*
* @param object $migration
* @param string $method
* @return array
*/
protected function getQueries($migration, $method)
{
$connection = $migration->getConnection();
// Now that we have the connections we can resolve it and pretend to run the
// queries against the database returning the array of raw SQL statements
// that would get fired against the database system for this migration.
$db = $this->resolveConnection($connection);
return $db->pretend(function () use ($migration, $method) {
$migration->$method();
});
}
/**
* Resolve a migration instance from a file.
*
* @param string $file
* @return object
*/
public function resolve($file)
{
$file = implode('_', array_slice(explode('_', $file), 4));
$class = Str::studly($file);
return new $class;
}
/**
* Raise a note event for the migrator.
*
* @param string $message
* @return void
*/
protected function note($message)
{
$this->notes[] = $message;
}
/**
* Get the notes for the last operation.
*
* @return array
*/
public function getNotes()
{
return $this->notes;
}
/**
* Resolve the database connection instance.
*
* @param string $connection
* @return \Illuminate\Database\Connection
*/
public function resolveConnection($connection)
{
return $this->resolver->connection($connection);
}
/**
* Set the default connection name.
*
* @param string $name
* @return void
*/
public function setConnection($name)
{
if (! is_null($name)) {
$this->resolver->setDefaultConnection($name);
}
$this->repository->setSource($name);
$this->connection = $name;
}
/**
* Get the migration repository instance.
*
* @return \Illuminate\Database\Migrations\MigrationRepositoryInterface
*/
public function getRepository()
{
return $this->repository;
}
/**
* Determine if the migration repository exists.
*
* @return bool
*/
public function repositoryExists()
{
return $this->repository->repositoryExists();
}
/**
* Get the file system instance.
*
* @return \Illuminate\Filesystem\Filesystem
*/
public function getFilesystem()
{
return $this->files;
}
}
Migrations/DatabaseMigrationRepository.php 0000666 00000010042 13436755161 0015063 0 ustar 00 table = $table;
$this->resolver = $resolver;
}
/**
* Get the ran migrations.
*
* @return array
*/
public function getRan()
{
return $this->table()
->orderBy('batch', 'asc')
->orderBy('migration', 'asc')
->pluck('migration');
}
/**
* Get the last migration batch.
*
* @return array
*/
public function getLast()
{
$query = $this->table()->where('batch', $this->getLastBatchNumber());
return $query->orderBy('migration', 'desc')->get();
}
/**
* Log that a migration was run.
*
* @param string $file
* @param int $batch
* @return void
*/
public function log($file, $batch)
{
$record = ['migration' => $file, 'batch' => $batch];
$this->table()->insert($record);
}
/**
* Remove a migration from the log.
*
* @param object $migration
* @return void
*/
public function delete($migration)
{
$this->table()->where('migration', $migration->migration)->delete();
}
/**
* Get the next migration batch number.
*
* @return int
*/
public function getNextBatchNumber()
{
return $this->getLastBatchNumber() + 1;
}
/**
* Get the last migration batch number.
*
* @return int
*/
public function getLastBatchNumber()
{
return $this->table()->max('batch');
}
/**
* Create the migration repository data store.
*
* @return void
*/
public function createRepository()
{
$schema = $this->getConnection()->getSchemaBuilder();
$schema->create($this->table, function ($table) {
// The migrations table is responsible for keeping track of which of the
// migrations have actually run for the application. We'll create the
// table to hold the migration file's path as well as the batch ID.
$table->string('migration');
$table->integer('batch');
});
}
/**
* Determine if the migration repository exists.
*
* @return bool
*/
public function repositoryExists()
{
$schema = $this->getConnection()->getSchemaBuilder();
return $schema->hasTable($this->table);
}
/**
* Get a query builder for the migration table.
*
* @return \Illuminate\Database\Query\Builder
*/
protected function table()
{
return $this->getConnection()->table($this->table);
}
/**
* Get the connection resolver instance.
*
* @return \Illuminate\Database\ConnectionResolverInterface
*/
public function getConnectionResolver()
{
return $this->resolver;
}
/**
* Resolve the database connection instance.
*
* @return \Illuminate\Database\Connection
*/
public function getConnection()
{
return $this->resolver->connection($this->connection);
}
/**
* Set the information source to gather data.
*
* @param string $name
* @return void
*/
public function setSource($name)
{
$this->connection = $name;
}
}
Migrations/Migration.php 0000666 00000000561 13436755161 0011343 0 ustar 00 connection;
}
}
Migrations/MigrationCreator.php 0000666 00000011434 13436755161 0012664 0 ustar 00 files = $files;
}
/**
* Create a new migration at the given path.
*
* @param string $name
* @param string $path
* @param string $table
* @param bool $create
* @return string
* @throws \Exception
*/
public function create($name, $path, $table = null, $create = false)
{
$this->ensureMigrationDoesntAlreadyExist($name);
$path = $this->getPath($name, $path);
// First we will get the stub file for the migration, which serves as a type
// of template for the migration. Once we have those we will populate the
// various place-holders, save the file, and run the post create event.
$stub = $this->getStub($table, $create);
$this->files->put($path, $this->populateStub($name, $stub, $table));
$this->firePostCreateHooks();
return $path;
}
/**
* Ensure that a migration with the given name doesn't already exist.
*
* @param string $name
* @return void
*
* @throws \InvalidArgumentException
*/
protected function ensureMigrationDoesntAlreadyExist($name)
{
if (class_exists($className = $this->getClassName($name))) {
throw new InvalidArgumentException("A $className migration already exists.");
}
}
/**
* Get the migration stub file.
*
* @param string $table
* @param bool $create
* @return string
*/
protected function getStub($table, $create)
{
if (is_null($table)) {
return $this->files->get($this->getStubPath().'/blank.stub');
}
// We also have stubs for creating new tables and modifying existing tables
// to save the developer some typing when they are creating a new tables
// or modifying existing tables. We'll grab the appropriate stub here.
else {
$stub = $create ? 'create.stub' : 'update.stub';
return $this->files->get($this->getStubPath()."/{$stub}");
}
}
/**
* Populate the place-holders in the migration stub.
*
* @param string $name
* @param string $stub
* @param string $table
* @return string
*/
protected function populateStub($name, $stub, $table)
{
$stub = str_replace('DummyClass', $this->getClassName($name), $stub);
// Here we will replace the table place-holders with the table specified by
// the developer, which is useful for quickly creating a tables creation
// or update migration from the console instead of typing it manually.
if (! is_null($table)) {
$stub = str_replace('DummyTable', $table, $stub);
}
return $stub;
}
/**
* Get the class name of a migration name.
*
* @param string $name
* @return string
*/
protected function getClassName($name)
{
return Str::studly($name);
}
/**
* Fire the registered post create hooks.
*
* @return void
*/
protected function firePostCreateHooks()
{
foreach ($this->postCreate as $callback) {
call_user_func($callback);
}
}
/**
* Register a post migration create hook.
*
* @param \Closure $callback
* @return void
*/
public function afterCreate(Closure $callback)
{
$this->postCreate[] = $callback;
}
/**
* Get the full path name to the migration.
*
* @param string $name
* @param string $path
* @return string
*/
protected function getPath($name, $path)
{
return $path.'/'.$this->getDatePrefix().'_'.$name.'.php';
}
/**
* Get the date prefix for the migration.
*
* @return string
*/
protected function getDatePrefix()
{
return date('Y_m_d_His');
}
/**
* Get the path to the stubs.
*
* @return string
*/
public function getStubPath()
{
return __DIR__.'/stubs';
}
/**
* Get the filesystem instance.
*
* @return \Illuminate\Filesystem\Filesystem
*/
public function getFilesystem()
{
return $this->files;
}
}
Migrations/stubs/create.stub 0000666 00000001037 13436755161 0012202 0 ustar 00 increments('id');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('DummyTable');
}
}
Migrations/stubs/blank.stub 0000666 00000000572 13436755161 0012031 0 ustar 00 pdo = $pdo;
// First we will setup the default properties. We keep track of the DB
// name we are connected to since it is needed when some reflective
// type commands are run such as checking whether a table exists.
$this->database = $database;
$this->tablePrefix = $tablePrefix;
$this->config = $config;
// We need to initialize a query grammar and the query post processors
// which are both very important parts of the database abstractions
// so we initialize these to their default values while starting.
$this->useDefaultQueryGrammar();
$this->useDefaultPostProcessor();
}
/**
* Set the query grammar to the default implementation.
*
* @return void
*/
public function useDefaultQueryGrammar()
{
$this->queryGrammar = $this->getDefaultQueryGrammar();
}
/**
* Get the default query grammar instance.
*
* @return \Illuminate\Database\Query\Grammars\Grammar
*/
protected function getDefaultQueryGrammar()
{
return new QueryGrammar;
}
/**
* Set the schema grammar to the default implementation.
*
* @return void
*/
public function useDefaultSchemaGrammar()
{
$this->schemaGrammar = $this->getDefaultSchemaGrammar();
}
/**
* Get the default schema grammar instance.
*
* @return \Illuminate\Database\Schema\Grammars\Grammar
*/
protected function getDefaultSchemaGrammar()
{
//
}
/**
* Set the query post processor to the default implementation.
*
* @return void
*/
public function useDefaultPostProcessor()
{
$this->postProcessor = $this->getDefaultPostProcessor();
}
/**
* Get the default post processor instance.
*
* @return \Illuminate\Database\Query\Processors\Processor
*/
protected function getDefaultPostProcessor()
{
return new Processor;
}
/**
* Get a schema builder instance for the connection.
*
* @return \Illuminate\Database\Schema\Builder
*/
public function getSchemaBuilder()
{
if (is_null($this->schemaGrammar)) {
$this->useDefaultSchemaGrammar();
}
return new SchemaBuilder($this);
}
/**
* Begin a fluent query against a database table.
*
* @param string $table
* @return \Illuminate\Database\Query\Builder
*/
public function table($table)
{
return $this->query()->from($table);
}
/**
* Get a new query builder instance.
*
* @return \Illuminate\Database\Query\Builder
*/
public function query()
{
return new QueryBuilder(
$this, $this->getQueryGrammar(), $this->getPostProcessor()
);
}
/**
* Get a new raw query expression.
*
* @param mixed $value
* @return \Illuminate\Database\Query\Expression
*/
public function raw($value)
{
return new Expression($value);
}
/**
* Run a select statement and return a single result.
*
* @param string $query
* @param array $bindings
* @return mixed
*/
public function selectOne($query, $bindings = [])
{
$records = $this->select($query, $bindings);
return count($records) > 0 ? reset($records) : null;
}
/**
* Run a select statement against the database.
*
* @param string $query
* @param array $bindings
* @return array
*/
public function selectFromWriteConnection($query, $bindings = [])
{
return $this->select($query, $bindings, false);
}
/**
* Run a select statement against the database.
*
* @param string $query
* @param array $bindings
* @param bool $useReadPdo
* @return array
*/
public function select($query, $bindings = [], $useReadPdo = true)
{
return $this->run($query, $bindings, function ($me, $query, $bindings) use ($useReadPdo) {
if ($me->pretending()) {
return [];
}
// For select statements, we'll simply execute the query and return an array
// of the database result set. Each element in the array will be a single
// row from the database table, and will either be an array or objects.
$statement = $this->getPdoForSelect($useReadPdo)->prepare($query);
$statement->execute($me->prepareBindings($bindings));
$fetchMode = $me->getFetchMode();
$fetchArgument = $me->getFetchArgument();
$fetchConstructorArgument = $me->getFetchConstructorArgument();
if ($fetchMode === PDO::FETCH_CLASS && ! isset($fetchArgument)) {
$fetchArgument = 'StdClass';
$fetchConstructorArgument = null;
}
return isset($fetchArgument)
? $statement->fetchAll($fetchMode, $fetchArgument, $fetchConstructorArgument)
: $statement->fetchAll($fetchMode);
});
}
/**
* Run a select statement against the database and returns a generator.
*
* @param string $query
* @param array $bindings
* @param bool $useReadPdo
* @return \Generator
*/
public function cursor($query, $bindings = [], $useReadPdo = true)
{
$statement = $this->run($query, $bindings, function ($me, $query, $bindings) use ($useReadPdo) {
if ($me->pretending()) {
return [];
}
$statement = $this->getPdoForSelect($useReadPdo)->prepare($query);
$fetchMode = $me->getFetchMode();
$fetchArgument = $me->getFetchArgument();
$fetchConstructorArgument = $me->getFetchConstructorArgument();
if ($fetchMode === PDO::FETCH_CLASS && ! isset($fetchArgument)) {
$fetchArgument = 'StdClass';
$fetchConstructorArgument = null;
}
if (isset($fetchArgument)) {
$statement->setFetchMode($fetchMode, $fetchArgument, $fetchConstructorArgument);
} else {
$statement->setFetchMode($fetchMode);
}
$statement->execute($me->prepareBindings($bindings));
return $statement;
});
while ($record = $statement->fetch()) {
yield $record;
}
}
/**
* Get the PDO connection to use for a select query.
*
* @param bool $useReadPdo
* @return \PDO
*/
protected function getPdoForSelect($useReadPdo = true)
{
return $useReadPdo ? $this->getReadPdo() : $this->getPdo();
}
/**
* Run an insert statement against the database.
*
* @param string $query
* @param array $bindings
* @return bool
*/
public function insert($query, $bindings = [])
{
return $this->statement($query, $bindings);
}
/**
* Run an update statement against the database.
*
* @param string $query
* @param array $bindings
* @return int
*/
public function update($query, $bindings = [])
{
return $this->affectingStatement($query, $bindings);
}
/**
* Run a delete statement against the database.
*
* @param string $query
* @param array $bindings
* @return int
*/
public function delete($query, $bindings = [])
{
return $this->affectingStatement($query, $bindings);
}
/**
* Execute an SQL statement and return the boolean result.
*
* @param string $query
* @param array $bindings
* @return bool
*/
public function statement($query, $bindings = [])
{
return $this->run($query, $bindings, function ($me, $query, $bindings) {
if ($me->pretending()) {
return true;
}
$bindings = $me->prepareBindings($bindings);
return $me->getPdo()->prepare($query)->execute($bindings);
});
}
/**
* Run an SQL statement and get the number of rows affected.
*
* @param string $query
* @param array $bindings
* @return int
*/
public function affectingStatement($query, $bindings = [])
{
return $this->run($query, $bindings, function ($me, $query, $bindings) {
if ($me->pretending()) {
return 0;
}
// For update or delete statements, we want to get the number of rows affected
// by the statement and return that back to the developer. We'll first need
// to execute the statement and then we'll use PDO to fetch the affected.
$statement = $me->getPdo()->prepare($query);
$statement->execute($me->prepareBindings($bindings));
return $statement->rowCount();
});
}
/**
* Run a raw, unprepared query against the PDO connection.
*
* @param string $query
* @return bool
*/
public function unprepared($query)
{
return $this->run($query, [], function ($me, $query) {
if ($me->pretending()) {
return true;
}
return (bool) $me->getPdo()->exec($query);
});
}
/**
* Prepare the query bindings for execution.
*
* @param array $bindings
* @return array
*/
public function prepareBindings(array $bindings)
{
$grammar = $this->getQueryGrammar();
foreach ($bindings as $key => $value) {
// We need to transform all instances of DateTimeInterface into the actual
// date string. Each query grammar maintains its own date string format
// so we'll just ask the grammar for the format to get from the date.
if ($value instanceof DateTimeInterface) {
$bindings[$key] = $value->format($grammar->getDateFormat());
} elseif ($value === false) {
$bindings[$key] = 0;
}
}
return $bindings;
}
/**
* Execute a Closure within a transaction.
*
* @param \Closure $callback
* @return mixed
*
* @throws \Exception|\Throwable
*/
public function transaction(Closure $callback)
{
$this->beginTransaction();
// We'll simply execute the given callback within a try / catch block
// and if we catch any exception we can rollback the transaction
// so that none of the changes are persisted to the database.
try {
$result = $callback($this);
$this->commit();
}
// If we catch an exception, we will roll back so nothing gets messed
// up in the database. Then we'll re-throw the exception so it can
// be handled how the developer sees fit for their applications.
catch (Exception $e) {
$this->rollBack();
throw $e;
} catch (Throwable $e) {
$this->rollBack();
throw $e;
}
return $result;
}
/**
* Start a new database transaction.
*
* @return void
* @throws Exception
*/
public function beginTransaction()
{
++$this->transactions;
if ($this->transactions == 1) {
try {
$this->getPdo()->beginTransaction();
} catch (Exception $e) {
--$this->transactions;
throw $e;
}
} elseif ($this->transactions > 1 && $this->queryGrammar->supportsSavepoints()) {
$this->getPdo()->exec(
$this->queryGrammar->compileSavepoint('trans'.$this->transactions)
);
}
$this->fireConnectionEvent('beganTransaction');
}
/**
* Commit the active database transaction.
*
* @return void
*/
public function commit()
{
if ($this->transactions == 1) {
$this->getPdo()->commit();
}
$this->transactions = max(0, $this->transactions - 1);
$this->fireConnectionEvent('committed');
}
/**
* Rollback the active database transaction.
*
* @return void
*/
public function rollBack()
{
if ($this->transactions == 1) {
$this->getPdo()->rollBack();
} elseif ($this->transactions > 1 && $this->queryGrammar->supportsSavepoints()) {
$this->getPdo()->exec(
$this->queryGrammar->compileSavepointRollBack('trans'.$this->transactions)
);
}
$this->transactions = max(0, $this->transactions - 1);
$this->fireConnectionEvent('rollingBack');
}
/**
* Get the number of active transactions.
*
* @return int
*/
public function transactionLevel()
{
return $this->transactions;
}
/**
* Execute the given callback in "dry run" mode.
*
* @param \Closure $callback
* @return array
*/
public function pretend(Closure $callback)
{
$loggingQueries = $this->loggingQueries;
$this->enableQueryLog();
$this->pretending = true;
$this->queryLog = [];
// Basically to make the database connection "pretend", we will just return
// the default values for all the query methods, then we will return an
// array of queries that were "executed" within the Closure callback.
$callback($this);
$this->pretending = false;
$this->loggingQueries = $loggingQueries;
return $this->queryLog;
}
/**
* Run a SQL statement and log its execution context.
*
* @param string $query
* @param array $bindings
* @param \Closure $callback
* @return mixed
*
* @throws \Illuminate\Database\QueryException
*/
protected function run($query, $bindings, Closure $callback)
{
$this->reconnectIfMissingConnection();
$start = microtime(true);
// Here we will run this query. If an exception occurs we'll determine if it was
// caused by a connection that has been lost. If that is the cause, we'll try
// to re-establish connection and re-run the query with a fresh connection.
try {
$result = $this->runQueryCallback($query, $bindings, $callback);
} catch (QueryException $e) {
if ($this->transactions >= 1) {
throw $e;
}
$result = $this->tryAgainIfCausedByLostConnection(
$e, $query, $bindings, $callback
);
}
// Once we have run the query we will calculate the time that it took to run and
// then log the query, bindings, and execution time so we will report them on
// the event that the developer needs them. We'll log time in milliseconds.
$time = $this->getElapsedTime($start);
$this->logQuery($query, $bindings, $time);
return $result;
}
/**
* Run a SQL statement.
*
* @param string $query
* @param array $bindings
* @param \Closure $callback
* @return mixed
*
* @throws \Illuminate\Database\QueryException
*/
protected function runQueryCallback($query, $bindings, Closure $callback)
{
// To execute the statement, we'll simply call the callback, which will actually
// run the SQL against the PDO connection. Then we can calculate the time it
// took to execute and log the query SQL, bindings and time in our memory.
try {
$result = $callback($this, $query, $bindings);
}
// If an exception occurs when attempting to run a query, we'll format the error
// message to include the bindings with SQL, which will make this exception a
// lot more helpful to the developer instead of just the database's errors.
catch (Exception $e) {
throw new QueryException(
$query, $this->prepareBindings($bindings), $e
);
}
return $result;
}
/**
* Handle a query exception that occurred during query execution.
*
* @param \Illuminate\Database\QueryException $e
* @param string $query
* @param array $bindings
* @param \Closure $callback
* @return mixed
*
* @throws \Illuminate\Database\QueryException
*/
protected function tryAgainIfCausedByLostConnection(QueryException $e, $query, $bindings, Closure $callback)
{
if ($this->causedByLostConnection($e->getPrevious())) {
$this->reconnect();
return $this->runQueryCallback($query, $bindings, $callback);
}
throw $e;
}
/**
* Disconnect from the underlying PDO connection.
*
* @return void
*/
public function disconnect()
{
$this->setPdo(null)->setReadPdo(null);
}
/**
* Reconnect to the database.
*
* @return void
*
* @throws \LogicException
*/
public function reconnect()
{
if (is_callable($this->reconnector)) {
return call_user_func($this->reconnector, $this);
}
throw new LogicException('Lost connection and no reconnector available.');
}
/**
* Reconnect to the database if a PDO connection is missing.
*
* @return void
*/
protected function reconnectIfMissingConnection()
{
if (is_null($this->getPdo()) || is_null($this->getReadPdo())) {
$this->reconnect();
}
}
/**
* Log a query in the connection's query log.
*
* @param string $query
* @param array $bindings
* @param float|null $time
* @return void
*/
public function logQuery($query, $bindings, $time = null)
{
if (isset($this->events)) {
$this->events->fire(new Events\QueryExecuted(
$query, $bindings, $time, $this
));
}
if ($this->loggingQueries) {
$this->queryLog[] = compact('query', 'bindings', 'time');
}
}
/**
* Register a database query listener with the connection.
*
* @param \Closure $callback
* @return void
*/
public function listen(Closure $callback)
{
if (isset($this->events)) {
$this->events->listen(Events\QueryExecuted::class, $callback);
}
}
/**
* Fire an event for this connection.
*
* @param string $event
* @return void
*/
protected function fireConnectionEvent($event)
{
if (! isset($this->events)) {
return;
}
switch ($event) {
case 'beganTransaction':
return $this->events->fire(new Events\TransactionBeginning($this));
case 'committed':
return $this->events->fire(new Events\TransactionCommitted($this));
case 'rollingBack':
return $this->events->fire(new Events\TransactionRolledBack($this));
}
}
/**
* Get the elapsed time since a given starting point.
*
* @param int $start
* @return float
*/
protected function getElapsedTime($start)
{
return round((microtime(true) - $start) * 1000, 2);
}
/**
* Is Doctrine available?
*
* @return bool
*/
public function isDoctrineAvailable()
{
return class_exists('Doctrine\DBAL\Connection');
}
/**
* Get a Doctrine Schema Column instance.
*
* @param string $table
* @param string $column
* @return \Doctrine\DBAL\Schema\Column
*/
public function getDoctrineColumn($table, $column)
{
$schema = $this->getDoctrineSchemaManager();
return $schema->listTableDetails($table)->getColumn($column);
}
/**
* Get the Doctrine DBAL schema manager for the connection.
*
* @return \Doctrine\DBAL\Schema\AbstractSchemaManager
*/
public function getDoctrineSchemaManager()
{
return $this->getDoctrineDriver()->getSchemaManager($this->getDoctrineConnection());
}
/**
* Get the Doctrine DBAL database connection instance.
*
* @return \Doctrine\DBAL\Connection
*/
public function getDoctrineConnection()
{
if (is_null($this->doctrineConnection)) {
$driver = $this->getDoctrineDriver();
$data = ['pdo' => $this->getPdo(), 'dbname' => $this->getConfig('database')];
$this->doctrineConnection = new DoctrineConnection($data, $driver);
}
return $this->doctrineConnection;
}
/**
* Get the current PDO connection.
*
* @return \PDO
*/
public function getPdo()
{
if ($this->pdo instanceof Closure) {
return $this->pdo = call_user_func($this->pdo);
}
return $this->pdo;
}
/**
* Get the current PDO connection used for reading.
*
* @return \PDO
*/
public function getReadPdo()
{
if ($this->transactions >= 1) {
return $this->getPdo();
}
return $this->readPdo ?: $this->getPdo();
}
/**
* Set the PDO connection.
*
* @param \PDO|null $pdo
* @return $this
*
* @throws \RuntimeException
*/
public function setPdo($pdo)
{
if ($this->transactions >= 1) {
throw new RuntimeException("Can't swap PDO instance while within transaction.");
}
$this->pdo = $pdo;
return $this;
}
/**
* Set the PDO connection used for reading.
*
* @param \PDO|null $pdo
* @return $this
*/
public function setReadPdo($pdo)
{
$this->readPdo = $pdo;
return $this;
}
/**
* Set the reconnect instance on the connection.
*
* @param callable $reconnector
* @return $this
*/
public function setReconnector(callable $reconnector)
{
$this->reconnector = $reconnector;
return $this;
}
/**
* Get the database connection name.
*
* @return string|null
*/
public function getName()
{
return $this->getConfig('name');
}
/**
* Get an option from the configuration options.
*
* @param string $option
* @return mixed
*/
public function getConfig($option)
{
return Arr::get($this->config, $option);
}
/**
* Get the PDO driver name.
*
* @return string
*/
public function getDriverName()
{
return $this->getConfig('driver');
}
/**
* Get the query grammar used by the connection.
*
* @return \Illuminate\Database\Query\Grammars\Grammar
*/
public function getQueryGrammar()
{
return $this->queryGrammar;
}
/**
* Set the query grammar used by the connection.
*
* @param \Illuminate\Database\Query\Grammars\Grammar $grammar
* @return void
*/
public function setQueryGrammar(Query\Grammars\Grammar $grammar)
{
$this->queryGrammar = $grammar;
}
/**
* Get the schema grammar used by the connection.
*
* @return \Illuminate\Database\Schema\Grammars\Grammar
*/
public function getSchemaGrammar()
{
return $this->schemaGrammar;
}
/**
* Set the schema grammar used by the connection.
*
* @param \Illuminate\Database\Schema\Grammars\Grammar $grammar
* @return void
*/
public function setSchemaGrammar(Schema\Grammars\Grammar $grammar)
{
$this->schemaGrammar = $grammar;
}
/**
* Get the query post processor used by the connection.
*
* @return \Illuminate\Database\Query\Processors\Processor
*/
public function getPostProcessor()
{
return $this->postProcessor;
}
/**
* Set the query post processor used by the connection.
*
* @param \Illuminate\Database\Query\Processors\Processor $processor
* @return void
*/
public function setPostProcessor(Processor $processor)
{
$this->postProcessor = $processor;
}
/**
* Get the event dispatcher used by the connection.
*
* @return \Illuminate\Contracts\Events\Dispatcher
*/
public function getEventDispatcher()
{
return $this->events;
}
/**
* Set the event dispatcher instance on the connection.
*
* @param \Illuminate\Contracts\Events\Dispatcher $events
* @return void
*/
public function setEventDispatcher(Dispatcher $events)
{
$this->events = $events;
}
/**
* Determine if the connection in a "dry run".
*
* @return bool
*/
public function pretending()
{
return $this->pretending === true;
}
/**
* Get the default fetch mode for the connection.
*
* @return int
*/
public function getFetchMode()
{
return $this->fetchMode;
}
/**
* Get the fetch argument to be applied when selecting.
*
* @return mixed
*/
public function getFetchArgument()
{
return $this->fetchArgument;
}
/**
* Get custom constructor arguments for the PDO::FETCH_CLASS fetch mode.
*
* @return array
*/
public function getFetchConstructorArgument()
{
return $this->fetchConstructorArgument;
}
/**
* Set the default fetch mode for the connection, and optional arguments for the given fetch mode.
*
* @param int $fetchMode
* @param mixed $fetchArgument
* @param array $fetchConstructorArgument
* @return int
*/
public function setFetchMode($fetchMode, $fetchArgument = null, array $fetchConstructorArgument = [])
{
$this->fetchMode = $fetchMode;
$this->fetchArgument = $fetchArgument;
$this->fetchConstructorArgument = $fetchConstructorArgument;
}
/**
* Get the connection query log.
*
* @return array
*/
public function getQueryLog()
{
return $this->queryLog;
}
/**
* Clear the query log.
*
* @return void
*/
public function flushQueryLog()
{
$this->queryLog = [];
}
/**
* Enable the query log on the connection.
*
* @return void
*/
public function enableQueryLog()
{
$this->loggingQueries = true;
}
/**
* Disable the query log on the connection.
*
* @return void
*/
public function disableQueryLog()
{
$this->loggingQueries = false;
}
/**
* Determine whether we're logging queries.
*
* @return bool
*/
public function logging()
{
return $this->loggingQueries;
}
/**
* Get the name of the connected database.
*
* @return string
*/
public function getDatabaseName()
{
return $this->database;
}
/**
* Set the name of the connected database.
*
* @param string $database
* @return string
*/
public function setDatabaseName($database)
{
$this->database = $database;
}
/**
* Get the table prefix for the connection.
*
* @return string
*/
public function getTablePrefix()
{
return $this->tablePrefix;
}
/**
* Set the table prefix in use by the connection.
*
* @param string $prefix
* @return void
*/
public function setTablePrefix($prefix)
{
$this->tablePrefix = $prefix;
$this->getQueryGrammar()->setTablePrefix($prefix);
}
/**
* Set the table prefix and return the grammar.
*
* @param \Illuminate\Database\Grammar $grammar
* @return \Illuminate\Database\Grammar
*/
public function withTablePrefix(Grammar $grammar)
{
$grammar->setTablePrefix($this->tablePrefix);
return $grammar;
}
}
ConnectionResolver.php 0000666 00000003564 13436755161 0011125 0 ustar 00 $connection) {
$this->addConnection($name, $connection);
}
}
/**
* Get a database connection instance.
*
* @param string $name
* @return \Illuminate\Database\ConnectionInterface
*/
public function connection($name = null)
{
if (is_null($name)) {
$name = $this->getDefaultConnection();
}
return $this->connections[$name];
}
/**
* Add a connection to the resolver.
*
* @param string $name
* @param \Illuminate\Database\ConnectionInterface $connection
* @return void
*/
public function addConnection($name, ConnectionInterface $connection)
{
$this->connections[$name] = $connection;
}
/**
* Check if a connection has been registered.
*
* @param string $name
* @return bool
*/
public function hasConnection($name)
{
return isset($this->connections[$name]);
}
/**
* Get the default connection name.
*
* @return string
*/
public function getDefaultConnection()
{
return $this->default;
}
/**
* Set the default connection name.
*
* @param string $name
* @return void
*/
public function setDefaultConnection($name)
{
$this->default = $name;
}
}