diff options
author | Marvin Borner | 2018-06-08 20:03:25 +0200 |
---|---|---|
committer | Marvin Borner | 2018-06-08 20:03:25 +0200 |
commit | 92b7dd3335a6572debeacfb5faa82c63a5e67888 (patch) | |
tree | 7ebbca22595d542ec5e2912a24a0400ac8f6b113 /main/app/sprinkles/core/src/Database | |
parent | 22a1bb27f94ea33042b0bdd35bef1a5cfa96cc0d (diff) |
Some minor fixes
Diffstat (limited to 'main/app/sprinkles/core/src/Database')
15 files changed, 1867 insertions, 1867 deletions
diff --git a/main/app/sprinkles/core/src/Database/Builder.php b/main/app/sprinkles/core/src/Database/Builder.php index cebc318..1ed26ff 100644 --- a/main/app/sprinkles/core/src/Database/Builder.php +++ b/main/app/sprinkles/core/src/Database/Builder.php @@ -1,200 +1,200 @@ -<?php -/** - * UserFrosting (http://www.userfrosting.com) - * - * @link https://github.com/userfrosting/UserFrosting - * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License) - */ - -namespace UserFrosting\Sprinkle\Core\Database; - -use Illuminate\Database\Capsule\Manager as DB; -use Illuminate\Database\Query\Builder as LaravelBuilder; - -/** - * UFBuilder Class - * - * The base Eloquent data model, from which all UserFrosting data classes extend. - * @author Alex Weissman (https://alexanderweissman.com) - */ -class Builder extends LaravelBuilder -{ - protected $excludedColumns = NULL; - - /** - * Perform a "begins with" pattern match on a specified column in a query. - * - * @param $query - * @param $field string The column to match - * @param $value string The value to match - */ - public function beginsWith($field, $value) { - return $this->where($field, 'LIKE', "$value%"); - } - - /** - * Perform an "ends with" pattern match on a specified column in a query. - * - * @param $query - * @param $field string The column to match - * @param $value string The value to match - */ - public function endsWith($field, $value) { - return $this->where($field, 'LIKE', "%$value"); - } - - /** - * Add columns to be excluded from the query. - * - * @param $value array|string The column(s) to exclude - * @return $this - */ - public function exclude($column) { - $column = is_array($column) ? $column : func_get_args(); - - $this->excludedColumns = array_merge((array)$this->excludedColumns, $column); - - return $this; - } - - /** - * Perform a pattern match on a specified column in a query. - * @param $query - * @param $field string The column to match - * @param $value string The value to match - */ - public function like($field, $value) { - return $this->where($field, 'LIKE', "%$value%"); - } - - /** - * Perform a pattern match on a specified column in a query. - * @param $query - * @param $field string The column to match - * @param $value string The value to match - */ - public function orLike($field, $value) { - return $this->orWhere($field, 'LIKE', "%$value%"); - } - - /** - * Execute the query as a "select" statement. - * - * @param array $columns - * @return \Illuminate\Support\Collection - */ - public function get($columns = ['*']) { - $original = $this->columns; - - if (is_null($original)) { - $this->columns = $columns; - } - - // Exclude any explicitly excluded columns - if (!is_null($this->excludedColumns)) { - $this->removeExcludedSelectColumns(); - } - - $results = $this->processor->processSelect($this, $this->runSelect()); - - $this->columns = $original; - - return collect($results); - } - - /** - * Remove excluded columns from the select column list. - */ - protected function removeExcludedSelectColumns() { - // Convert current column list and excluded column list to fully-qualified list - $this->columns = $this->convertColumnsToFullyQualified($this->columns); - $excludedColumns = $this->convertColumnsToFullyQualified($this->excludedColumns); - - // Remove any explicitly referenced excludable columns - $this->columns = array_diff($this->columns, $excludedColumns); - - // Replace any remaining wildcard columns (*, table.*, etc) with a list - // of fully-qualified column names - $this->columns = $this->replaceWildcardColumns($this->columns); - - $this->columns = array_diff($this->columns, $excludedColumns); - } - - /** - * Find any wildcard columns ('*'), remove it from the column list and replace with an explicit list of columns. - * - * @param array $columns - * @return array - */ - protected function replaceWildcardColumns(array $columns) { - $wildcardTables = $this->findWildcardTables($columns); - - foreach ($wildcardTables as $wildColumn => $table) { - $schemaColumns = $this->getQualifiedColumnNames($table); - - // Remove the `*` or `.*` column and replace with the individual schema columns - $columns = array_diff($columns, [$wildColumn]); - $columns = array_merge($columns, $schemaColumns); - } - - return $columns; - } - - /** - * Return a list of wildcard columns from the list of columns, mapping columns to their corresponding tables. - * - * @param array $columns - * @return array - */ - protected function findWildcardTables(array $columns) { - $tables = []; - - foreach ($columns as $column) { - if ($column == '*') { - $tables[$column] = $this->from; - continue; - } - - if (substr($column, -1) == '*') { - $tableName = explode('.', $column)[0]; - if ($tableName) { - $tables[$column] = $tableName; - } - } - } - - return $tables; - } - - /** - * Gets the fully qualified column names for a specified table. - * - * @param string $table - * @return array - */ - protected function getQualifiedColumnNames($table = NULL) { - $schema = $this->getConnection()->getSchemaBuilder(); - - return $this->convertColumnsToFullyQualified($schema->getColumnListing($table), $table); - } - - /** - * Fully qualify any unqualified columns in a list with this builder's table name. - * - * @param array $columns - * @return array - */ - protected function convertColumnsToFullyQualified($columns, $table = NULL) { - if (is_null($table)) { - $table = $this->from; - } - - array_walk($columns, function (&$item, $key) use ($table) { - if (strpos($item, '.') === FALSE) { - $item = "$table.$item"; - } - }); - - return $columns; - } -} +<?php
+/**
+ * UserFrosting (http://www.userfrosting.com)
+ *
+ * @link https://github.com/userfrosting/UserFrosting
+ * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License)
+ */
+
+namespace UserFrosting\Sprinkle\Core\Database;
+
+use Illuminate\Database\Capsule\Manager as DB;
+use Illuminate\Database\Query\Builder as LaravelBuilder;
+
+/**
+ * UFBuilder Class
+ *
+ * The base Eloquent data model, from which all UserFrosting data classes extend.
+ * @author Alex Weissman (https://alexanderweissman.com)
+ */
+class Builder extends LaravelBuilder
+{
+ protected $excludedColumns = NULL;
+
+ /**
+ * Perform a "begins with" pattern match on a specified column in a query.
+ *
+ * @param $query
+ * @param $field string The column to match
+ * @param $value string The value to match
+ */
+ public function beginsWith($field, $value) {
+ return $this->where($field, 'LIKE', "$value%");
+ }
+
+ /**
+ * Perform an "ends with" pattern match on a specified column in a query.
+ *
+ * @param $query
+ * @param $field string The column to match
+ * @param $value string The value to match
+ */
+ public function endsWith($field, $value) {
+ return $this->where($field, 'LIKE', "%$value");
+ }
+
+ /**
+ * Add columns to be excluded from the query.
+ *
+ * @param $value array|string The column(s) to exclude
+ * @return $this
+ */
+ public function exclude($column) {
+ $column = is_array($column) ? $column : func_get_args();
+
+ $this->excludedColumns = array_merge((array)$this->excludedColumns, $column);
+
+ return $this;
+ }
+
+ /**
+ * Perform a pattern match on a specified column in a query.
+ * @param $query
+ * @param $field string The column to match
+ * @param $value string The value to match
+ */
+ public function like($field, $value) {
+ return $this->where($field, 'LIKE', "%$value%");
+ }
+
+ /**
+ * Perform a pattern match on a specified column in a query.
+ * @param $query
+ * @param $field string The column to match
+ * @param $value string The value to match
+ */
+ public function orLike($field, $value) {
+ return $this->orWhere($field, 'LIKE', "%$value%");
+ }
+
+ /**
+ * Execute the query as a "select" statement.
+ *
+ * @param array $columns
+ * @return \Illuminate\Support\Collection
+ */
+ public function get($columns = ['*']) {
+ $original = $this->columns;
+
+ if (is_null($original)) {
+ $this->columns = $columns;
+ }
+
+ // Exclude any explicitly excluded columns
+ if (!is_null($this->excludedColumns)) {
+ $this->removeExcludedSelectColumns();
+ }
+
+ $results = $this->processor->processSelect($this, $this->runSelect());
+
+ $this->columns = $original;
+
+ return collect($results);
+ }
+
+ /**
+ * Remove excluded columns from the select column list.
+ */
+ protected function removeExcludedSelectColumns() {
+ // Convert current column list and excluded column list to fully-qualified list
+ $this->columns = $this->convertColumnsToFullyQualified($this->columns);
+ $excludedColumns = $this->convertColumnsToFullyQualified($this->excludedColumns);
+
+ // Remove any explicitly referenced excludable columns
+ $this->columns = array_diff($this->columns, $excludedColumns);
+
+ // Replace any remaining wildcard columns (*, table.*, etc) with a list
+ // of fully-qualified column names
+ $this->columns = $this->replaceWildcardColumns($this->columns);
+
+ $this->columns = array_diff($this->columns, $excludedColumns);
+ }
+
+ /**
+ * Find any wildcard columns ('*'), remove it from the column list and replace with an explicit list of columns.
+ *
+ * @param array $columns
+ * @return array
+ */
+ protected function replaceWildcardColumns(array $columns) {
+ $wildcardTables = $this->findWildcardTables($columns);
+
+ foreach ($wildcardTables as $wildColumn => $table) {
+ $schemaColumns = $this->getQualifiedColumnNames($table);
+
+ // Remove the `*` or `.*` column and replace with the individual schema columns
+ $columns = array_diff($columns, [$wildColumn]);
+ $columns = array_merge($columns, $schemaColumns);
+ }
+
+ return $columns;
+ }
+
+ /**
+ * Return a list of wildcard columns from the list of columns, mapping columns to their corresponding tables.
+ *
+ * @param array $columns
+ * @return array
+ */
+ protected function findWildcardTables(array $columns) {
+ $tables = [];
+
+ foreach ($columns as $column) {
+ if ($column == '*') {
+ $tables[$column] = $this->from;
+ continue;
+ }
+
+ if (substr($column, -1) == '*') {
+ $tableName = explode('.', $column)[0];
+ if ($tableName) {
+ $tables[$column] = $tableName;
+ }
+ }
+ }
+
+ return $tables;
+ }
+
+ /**
+ * Gets the fully qualified column names for a specified table.
+ *
+ * @param string $table
+ * @return array
+ */
+ protected function getQualifiedColumnNames($table = NULL) {
+ $schema = $this->getConnection()->getSchemaBuilder();
+
+ return $this->convertColumnsToFullyQualified($schema->getColumnListing($table), $table);
+ }
+
+ /**
+ * Fully qualify any unqualified columns in a list with this builder's table name.
+ *
+ * @param array $columns
+ * @return array
+ */
+ protected function convertColumnsToFullyQualified($columns, $table = NULL) {
+ if (is_null($table)) {
+ $table = $this->from;
+ }
+
+ array_walk($columns, function (&$item, $key) use ($table) {
+ if (strpos($item, '.') === FALSE) {
+ $item = "$table.$item";
+ }
+ });
+
+ return $columns;
+ }
+}
diff --git a/main/app/sprinkles/core/src/Database/DatabaseInvalidException.php b/main/app/sprinkles/core/src/Database/DatabaseInvalidException.php index 0eba67b..ec30aa6 100644 --- a/main/app/sprinkles/core/src/Database/DatabaseInvalidException.php +++ b/main/app/sprinkles/core/src/Database/DatabaseInvalidException.php @@ -1,21 +1,21 @@ -<?php -/** - * UserFrosting (http://www.userfrosting.com) - * - * @link https://github.com/userfrosting/UserFrosting - * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License) - */ - -namespace UserFrosting\Sprinkle\Core\Database; - -use UserFrosting\Support\Exception\ForbiddenException; - -/** - * Invalid database exception. Used when the database cannot be accessed. - * - * @author Alex Weissman (https://alexanderweissman.com) - */ -class DatabaseInvalidException extends ForbiddenException -{ - protected $defaultMessage = 'DB_INVALID'; -} +<?php
+/**
+ * UserFrosting (http://www.userfrosting.com)
+ *
+ * @link https://github.com/userfrosting/UserFrosting
+ * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License)
+ */
+
+namespace UserFrosting\Sprinkle\Core\Database;
+
+use UserFrosting\Support\Exception\ForbiddenException;
+
+/**
+ * Invalid database exception. Used when the database cannot be accessed.
+ *
+ * @author Alex Weissman (https://alexanderweissman.com)
+ */
+class DatabaseInvalidException extends ForbiddenException
+{
+ protected $defaultMessage = 'DB_INVALID';
+}
diff --git a/main/app/sprinkles/core/src/Database/Migrations/v400/SessionsTable.php b/main/app/sprinkles/core/src/Database/Migrations/v400/SessionsTable.php index 82d6534..b5fe437 100644 --- a/main/app/sprinkles/core/src/Database/Migrations/v400/SessionsTable.php +++ b/main/app/sprinkles/core/src/Database/Migrations/v400/SessionsTable.php @@ -1,47 +1,47 @@ -<?php -/** - * UserFrosting (http://www.userfrosting.com) - * - * @link https://github.com/userfrosting/UserFrosting - * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License) - */ - -namespace UserFrosting\Sprinkle\Core\Database\Migrations\v400; - -use Illuminate\Database\Schema\Blueprint; -use Illuminate\Database\Schema\Builder; -use UserFrosting\System\Bakery\Migration; - -/** - * Sessions table migration - * Version 4.0.0 - * - * See https://laravel.com/docs/5.4/migrations#tables - * @extends Migration - * @author Alex Weissman (https://alexanderweissman.com) - */ -class SessionsTable extends Migration -{ - /** - * {@inheritDoc} - */ - public function up() { - if (!$this->schema->hasTable('sessions')) { - $this->schema->create('sessions', function (Blueprint $table) { - $table->string('id')->unique(); - $table->integer('user_id')->nullable(); - $table->string('ip_address', 45)->nullable(); - $table->text('user_agent')->nullable(); - $table->text('payload'); - $table->integer('last_activity'); - }); - } - } - - /** - * {@inheritDoc} - */ - public function down() { - $this->schema->drop('sessions'); - } -} +<?php
+/**
+ * UserFrosting (http://www.userfrosting.com)
+ *
+ * @link https://github.com/userfrosting/UserFrosting
+ * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License)
+ */
+
+namespace UserFrosting\Sprinkle\Core\Database\Migrations\v400;
+
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Database\Schema\Builder;
+use UserFrosting\System\Bakery\Migration;
+
+/**
+ * Sessions table migration
+ * Version 4.0.0
+ *
+ * See https://laravel.com/docs/5.4/migrations#tables
+ * @extends Migration
+ * @author Alex Weissman (https://alexanderweissman.com)
+ */
+class SessionsTable extends Migration
+{
+ /**
+ * {@inheritDoc}
+ */
+ public function up() {
+ if (!$this->schema->hasTable('sessions')) {
+ $this->schema->create('sessions', function (Blueprint $table) {
+ $table->string('id')->unique();
+ $table->integer('user_id')->nullable();
+ $table->string('ip_address', 45)->nullable();
+ $table->text('user_agent')->nullable();
+ $table->text('payload');
+ $table->integer('last_activity');
+ });
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function down() {
+ $this->schema->drop('sessions');
+ }
+}
diff --git a/main/app/sprinkles/core/src/Database/Migrations/v400/ThrottlesTable.php b/main/app/sprinkles/core/src/Database/Migrations/v400/ThrottlesTable.php index f74fee8..676b44e 100644 --- a/main/app/sprinkles/core/src/Database/Migrations/v400/ThrottlesTable.php +++ b/main/app/sprinkles/core/src/Database/Migrations/v400/ThrottlesTable.php @@ -1,51 +1,51 @@ -<?php -/** - * UserFrosting (http://www.userfrosting.com) - * - * @link https://github.com/userfrosting/UserFrosting - * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License) - */ - -namespace UserFrosting\Sprinkle\Core\Database\Migrations\v400; - -use Illuminate\Database\Schema\Blueprint; -use Illuminate\Database\Schema\Builder; -use UserFrosting\System\Bakery\Migration; - -/** - * Throttles table migration - * Version 4.0.0 - * - * @extends Migration - * @author Alex Weissman (https://alexanderweissman.com) - */ -class ThrottlesTable extends Migration -{ - /** - * {@inheritDoc} - */ - public function up() { - if (!$this->schema->hasTable('throttles')) { - $this->schema->create('throttles', function (Blueprint $table) { - $table->increments('id'); - $table->string('type'); - $table->string('ip')->nullable(); - $table->text('request_data')->nullable(); - $table->timestamps(); - - $table->engine = 'InnoDB'; - $table->collation = 'utf8_unicode_ci'; - $table->charset = 'utf8'; - $table->index('type'); - $table->index('ip'); - }); - } - } - - /** - * {@inheritDoc} - */ - public function down() { - $this->schema->drop('throttles'); - } -} +<?php
+/**
+ * UserFrosting (http://www.userfrosting.com)
+ *
+ * @link https://github.com/userfrosting/UserFrosting
+ * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License)
+ */
+
+namespace UserFrosting\Sprinkle\Core\Database\Migrations\v400;
+
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Database\Schema\Builder;
+use UserFrosting\System\Bakery\Migration;
+
+/**
+ * Throttles table migration
+ * Version 4.0.0
+ *
+ * @extends Migration
+ * @author Alex Weissman (https://alexanderweissman.com)
+ */
+class ThrottlesTable extends Migration
+{
+ /**
+ * {@inheritDoc}
+ */
+ public function up() {
+ if (!$this->schema->hasTable('throttles')) {
+ $this->schema->create('throttles', function (Blueprint $table) {
+ $table->increments('id');
+ $table->string('type');
+ $table->string('ip')->nullable();
+ $table->text('request_data')->nullable();
+ $table->timestamps();
+
+ $table->engine = 'InnoDB';
+ $table->collation = 'utf8_unicode_ci';
+ $table->charset = 'utf8';
+ $table->index('type');
+ $table->index('ip');
+ });
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function down() {
+ $this->schema->drop('throttles');
+ }
+}
diff --git a/main/app/sprinkles/core/src/Database/Models/Concerns/HasRelationships.php b/main/app/sprinkles/core/src/Database/Models/Concerns/HasRelationships.php index 919c108..ccccf32 100644 --- a/main/app/sprinkles/core/src/Database/Models/Concerns/HasRelationships.php +++ b/main/app/sprinkles/core/src/Database/Models/Concerns/HasRelationships.php @@ -1,272 +1,272 @@ -<?php -/** - * UserFrosting (http://www.userfrosting.com) - * - * @link https://github.com/userfrosting/UserFrosting - * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License) - */ - -namespace UserFrosting\Sprinkle\Core\Database\Models\Concerns; - -use Illuminate\Support\Arr; -use Illuminate\Support\Str; - -use Illuminate\Database\Eloquent\Relations\MorphMany; -use Illuminate\Database\Eloquent\Relations\MorphToMany; - -use UserFrosting\Sprinkle\Core\Database\Relations\BelongsToManyConstrained; -use UserFrosting\Sprinkle\Core\Database\Relations\BelongsToManyThrough; -use UserFrosting\Sprinkle\Core\Database\Relations\BelongsToManyUnique; -use UserFrosting\Sprinkle\Core\Database\Relations\HasManySyncable; -use UserFrosting\Sprinkle\Core\Database\Relations\MorphManySyncable; -use UserFrosting\Sprinkle\Core\Database\Relations\MorphToManyUnique; - -/** - * HasRelationships trait - * - * Extends Laravel's Model class to add some additional relationships. - * @author Alex Weissman (https://alexanderweissman.com) - */ -trait HasRelationships -{ - /** - * The many to many relationship methods. - * - * @var array - */ - public static $manyMethodsExtended = ['belongsToMany', 'morphToMany', 'morphedByMany', 'morphToManyUnique']; - - /** - * Overrides the default Eloquent hasMany relationship to return a HasManySyncable. - * - * {@inheritDoc} - * @return \UserFrosting\Sprinkle\Core\Database\Relations\HasManySyncable - */ - public function hasMany($related, $foreignKey = NULL, $localKey = NULL) { - $instance = $this->newRelatedInstance($related); - - $foreignKey = $foreignKey ?: $this->getForeignKey(); - - $localKey = $localKey ?: $this->getKeyName(); - - return new HasManySyncable( - $instance->newQuery(), $this, $instance->getTable() . '.' . $foreignKey, $localKey - ); - } - - /** - * Overrides the default Eloquent morphMany relationship to return a MorphManySyncable. - * - * {@inheritDoc} - * @return \UserFrosting\Sprinkle\Core\Database\Relations\MorphManySyncable - */ - public function morphMany($related, $name, $type = NULL, $id = NULL, $localKey = NULL) { - $instance = $this->newRelatedInstance($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 MorphManySyncable($instance->newQuery(), $this, $table . '.' . $type, $table . '.' . $id, $localKey); - } - - /** - * Define a many-to-many 'through' relationship. - * This is basically hasManyThrough for many-to-many relationships. - * - * @param string $related - * @param string $through - * @param string $firstJoiningTable - * @param string $firstForeignKey - * @param string $firstRelatedKey - * @param string $secondJoiningTable - * @param string $secondForeignKey - * @param string $secondRelatedKey - * @param string $throughRelation - * @param string $relation - * @return \UserFrosting\Sprinkle\Core\Database\Relations\BelongsToManyThrough - */ - public function belongsToManyThrough( - $related, - $through, - $firstJoiningTable = NULL, - $firstForeignKey = NULL, - $firstRelatedKey = NULL, - $secondJoiningTable = NULL, - $secondForeignKey = NULL, - $secondRelatedKey = NULL, - $throughRelation = 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->guessBelongsToManyRelation(); - } - - // Create models for through and related - $through = new $through; - $related = $this->newRelatedInstance($related); - - if (is_null($throughRelation)) { - $throughRelation = $through->getTable(); - } - - // If no table names were provided, we can guess it by concatenating the parent - // and through table names. The two model names are transformed to snake case - // from their default CamelCase also. - if (is_null($firstJoiningTable)) { - $firstJoiningTable = $this->joiningTable($through); - } - - if (is_null($secondJoiningTable)) { - $secondJoiningTable = $through->joiningTable($related); - } - - $firstForeignKey = $firstForeignKey ?: $this->getForeignKey(); - $firstRelatedKey = $firstRelatedKey ?: $through->getForeignKey(); - $secondForeignKey = $secondForeignKey ?: $through->getForeignKey(); - $secondRelatedKey = $secondRelatedKey ?: $related->getForeignKey(); - - // This relationship maps the top model (this) to the through model. - $intermediateRelationship = $this->belongsToMany($through, $firstJoiningTable, $firstForeignKey, $firstRelatedKey, $throughRelation) - ->withPivot($firstForeignKey); - - // Now we set up the relationship with the related model. - $query = new BelongsToManyThrough( - $related->newQuery(), $this, $intermediateRelationship, $secondJoiningTable, $secondForeignKey, $secondRelatedKey, $relation - ); - - return $query; - } - - /** - * Define a unique many-to-many relationship. Similar to a regular many-to-many relationship, but removes duplicate child objects. - * Can also be used to implement ternary relationships. - * - * {@inheritDoc} - * @return \UserFrosting\Sprinkle\Core\Database\Relations\BelongsToManyUnique - */ - public function belongsToManyUnique($related, $table = NULL, $foreignKey = NULL, $relatedKey = 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->guessBelongsToManyRelation(); - } - - // 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. - $instance = $this->newRelatedInstance($related); - - $foreignKey = $foreignKey ?: $this->getForeignKey(); - - $relatedKey = $relatedKey ?: $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); - } - - return new BelongsToManyUnique( - $instance->newQuery(), $this, $table, $foreignKey, $relatedKey, $relation - ); - } - - /** - * Define a unique morphs-to-many relationship. Similar to a regular morphs-to-many relationship, but removes duplicate child objects. - * - * {@inheritDoc} - * @return \UserFrosting\Sprinkle\Core\Database\Relations\MorphToManyUnique - */ - public function morphToManyUnique($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 MorphToManyUnique( - $query, $this, $name, $table, $foreignKey, - $otherKey, $caller, $inverse - ); - } - - /** - * Define a constrained many-to-many relationship. - * This is similar to a regular many-to-many, but constrains the child results to match an additional constraint key in the parent object. - * This has been superseded by the belongsToManyUnique relationship's `withTernary` method since 4.1.7. - * - * @deprecated since 4.1.6 - * @param string $related - * @param string $constraintKey - * @param string $table - * @param string $foreignKey - * @param string $relatedKey - * @param string $relation - * @return \UserFrosting\Sprinkle\Core\Database\Relations\BelongsToManyConstrained - */ - public function belongsToManyConstrained($related, $constraintKey, $table = NULL, $foreignKey = NULL, $relatedKey = 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->guessBelongsToManyRelation(); - } - - // 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. - $instance = $this->newRelatedInstance($related); - - $foreignKey = $foreignKey ?: $this->getForeignKey(); - - $relatedKey = $relatedKey ?: $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); - } - - return new BelongsToManyConstrained( - $instance->newQuery(), $this, $constraintKey, $table, $foreignKey, $relatedKey, $relation - ); - } - - /** - * 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, HasRelationships::$manyMethodsExtended) && $caller != $self; - }); - - return !is_null($caller) ? $caller['function'] : NULL; - } -} +<?php
+/**
+ * UserFrosting (http://www.userfrosting.com)
+ *
+ * @link https://github.com/userfrosting/UserFrosting
+ * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License)
+ */
+
+namespace UserFrosting\Sprinkle\Core\Database\Models\Concerns;
+
+use Illuminate\Support\Arr;
+use Illuminate\Support\Str;
+
+use Illuminate\Database\Eloquent\Relations\MorphMany;
+use Illuminate\Database\Eloquent\Relations\MorphToMany;
+
+use UserFrosting\Sprinkle\Core\Database\Relations\BelongsToManyConstrained;
+use UserFrosting\Sprinkle\Core\Database\Relations\BelongsToManyThrough;
+use UserFrosting\Sprinkle\Core\Database\Relations\BelongsToManyUnique;
+use UserFrosting\Sprinkle\Core\Database\Relations\HasManySyncable;
+use UserFrosting\Sprinkle\Core\Database\Relations\MorphManySyncable;
+use UserFrosting\Sprinkle\Core\Database\Relations\MorphToManyUnique;
+
+/**
+ * HasRelationships trait
+ *
+ * Extends Laravel's Model class to add some additional relationships.
+ * @author Alex Weissman (https://alexanderweissman.com)
+ */
+trait HasRelationships
+{
+ /**
+ * The many to many relationship methods.
+ *
+ * @var array
+ */
+ public static $manyMethodsExtended = ['belongsToMany', 'morphToMany', 'morphedByMany', 'morphToManyUnique'];
+
+ /**
+ * Overrides the default Eloquent hasMany relationship to return a HasManySyncable.
+ *
+ * {@inheritDoc}
+ * @return \UserFrosting\Sprinkle\Core\Database\Relations\HasManySyncable
+ */
+ public function hasMany($related, $foreignKey = NULL, $localKey = NULL) {
+ $instance = $this->newRelatedInstance($related);
+
+ $foreignKey = $foreignKey ?: $this->getForeignKey();
+
+ $localKey = $localKey ?: $this->getKeyName();
+
+ return new HasManySyncable(
+ $instance->newQuery(), $this, $instance->getTable() . '.' . $foreignKey, $localKey
+ );
+ }
+
+ /**
+ * Overrides the default Eloquent morphMany relationship to return a MorphManySyncable.
+ *
+ * {@inheritDoc}
+ * @return \UserFrosting\Sprinkle\Core\Database\Relations\MorphManySyncable
+ */
+ public function morphMany($related, $name, $type = NULL, $id = NULL, $localKey = NULL) {
+ $instance = $this->newRelatedInstance($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 MorphManySyncable($instance->newQuery(), $this, $table . '.' . $type, $table . '.' . $id, $localKey);
+ }
+
+ /**
+ * Define a many-to-many 'through' relationship.
+ * This is basically hasManyThrough for many-to-many relationships.
+ *
+ * @param string $related
+ * @param string $through
+ * @param string $firstJoiningTable
+ * @param string $firstForeignKey
+ * @param string $firstRelatedKey
+ * @param string $secondJoiningTable
+ * @param string $secondForeignKey
+ * @param string $secondRelatedKey
+ * @param string $throughRelation
+ * @param string $relation
+ * @return \UserFrosting\Sprinkle\Core\Database\Relations\BelongsToManyThrough
+ */
+ public function belongsToManyThrough(
+ $related,
+ $through,
+ $firstJoiningTable = NULL,
+ $firstForeignKey = NULL,
+ $firstRelatedKey = NULL,
+ $secondJoiningTable = NULL,
+ $secondForeignKey = NULL,
+ $secondRelatedKey = NULL,
+ $throughRelation = 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->guessBelongsToManyRelation();
+ }
+
+ // Create models for through and related
+ $through = new $through;
+ $related = $this->newRelatedInstance($related);
+
+ if (is_null($throughRelation)) {
+ $throughRelation = $through->getTable();
+ }
+
+ // If no table names were provided, we can guess it by concatenating the parent
+ // and through table names. The two model names are transformed to snake case
+ // from their default CamelCase also.
+ if (is_null($firstJoiningTable)) {
+ $firstJoiningTable = $this->joiningTable($through);
+ }
+
+ if (is_null($secondJoiningTable)) {
+ $secondJoiningTable = $through->joiningTable($related);
+ }
+
+ $firstForeignKey = $firstForeignKey ?: $this->getForeignKey();
+ $firstRelatedKey = $firstRelatedKey ?: $through->getForeignKey();
+ $secondForeignKey = $secondForeignKey ?: $through->getForeignKey();
+ $secondRelatedKey = $secondRelatedKey ?: $related->getForeignKey();
+
+ // This relationship maps the top model (this) to the through model.
+ $intermediateRelationship = $this->belongsToMany($through, $firstJoiningTable, $firstForeignKey, $firstRelatedKey, $throughRelation)
+ ->withPivot($firstForeignKey);
+
+ // Now we set up the relationship with the related model.
+ $query = new BelongsToManyThrough(
+ $related->newQuery(), $this, $intermediateRelationship, $secondJoiningTable, $secondForeignKey, $secondRelatedKey, $relation
+ );
+
+ return $query;
+ }
+
+ /**
+ * Define a unique many-to-many relationship. Similar to a regular many-to-many relationship, but removes duplicate child objects.
+ * Can also be used to implement ternary relationships.
+ *
+ * {@inheritDoc}
+ * @return \UserFrosting\Sprinkle\Core\Database\Relations\BelongsToManyUnique
+ */
+ public function belongsToManyUnique($related, $table = NULL, $foreignKey = NULL, $relatedKey = 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->guessBelongsToManyRelation();
+ }
+
+ // 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.
+ $instance = $this->newRelatedInstance($related);
+
+ $foreignKey = $foreignKey ?: $this->getForeignKey();
+
+ $relatedKey = $relatedKey ?: $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);
+ }
+
+ return new BelongsToManyUnique(
+ $instance->newQuery(), $this, $table, $foreignKey, $relatedKey, $relation
+ );
+ }
+
+ /**
+ * Define a unique morphs-to-many relationship. Similar to a regular morphs-to-many relationship, but removes duplicate child objects.
+ *
+ * {@inheritDoc}
+ * @return \UserFrosting\Sprinkle\Core\Database\Relations\MorphToManyUnique
+ */
+ public function morphToManyUnique($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 MorphToManyUnique(
+ $query, $this, $name, $table, $foreignKey,
+ $otherKey, $caller, $inverse
+ );
+ }
+
+ /**
+ * Define a constrained many-to-many relationship.
+ * This is similar to a regular many-to-many, but constrains the child results to match an additional constraint key in the parent object.
+ * This has been superseded by the belongsToManyUnique relationship's `withTernary` method since 4.1.7.
+ *
+ * @deprecated since 4.1.6
+ * @param string $related
+ * @param string $constraintKey
+ * @param string $table
+ * @param string $foreignKey
+ * @param string $relatedKey
+ * @param string $relation
+ * @return \UserFrosting\Sprinkle\Core\Database\Relations\BelongsToManyConstrained
+ */
+ public function belongsToManyConstrained($related, $constraintKey, $table = NULL, $foreignKey = NULL, $relatedKey = 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->guessBelongsToManyRelation();
+ }
+
+ // 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.
+ $instance = $this->newRelatedInstance($related);
+
+ $foreignKey = $foreignKey ?: $this->getForeignKey();
+
+ $relatedKey = $relatedKey ?: $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);
+ }
+
+ return new BelongsToManyConstrained(
+ $instance->newQuery(), $this, $constraintKey, $table, $foreignKey, $relatedKey, $relation
+ );
+ }
+
+ /**
+ * 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, HasRelationships::$manyMethodsExtended) && $caller != $self;
+ });
+
+ return !is_null($caller) ? $caller['function'] : NULL;
+ }
+}
diff --git a/main/app/sprinkles/core/src/Database/Models/Model.php b/main/app/sprinkles/core/src/Database/Models/Model.php index 28b6be0..38e49fd 100644 --- a/main/app/sprinkles/core/src/Database/Models/Model.php +++ b/main/app/sprinkles/core/src/Database/Models/Model.php @@ -1,133 +1,133 @@ -<?php -/** - * UserFrosting (http://www.userfrosting.com) - * - * @link https://github.com/userfrosting/UserFrosting - * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License) - */ - -namespace UserFrosting\Sprinkle\Core\Database\Models; - -use Illuminate\Database\Capsule\Manager as DB; -use Illuminate\Database\Eloquent\Model as LaravelModel; -use UserFrosting\Sprinkle\Core\Database\Models\Concerns\HasRelationships; - -/** - * Model Class - * - * UserFrosting's base data model, from which all UserFrosting data classes extend. - * @author Alex Weissman (https://alexanderweissman.com) - */ -abstract class Model extends LaravelModel -{ - use HasRelationships; - - /** - * @var ContainerInterface The DI container for your application. - */ - public static $ci; - - /** - * @var bool Disable timestamps for now. - */ - public $timestamps = FALSE; - - public function __construct(array $attributes = []) { - // Hacky way to force the DB service to load before attempting to use the model - static::$ci['db']; - - parent::__construct($attributes); - } - - /** - * Determine if an attribute exists on the model - even if it is null. - * - * @param string $key - * @return bool - */ - public function attributeExists($key) { - return array_key_exists($key, $this->attributes); - } - - /** - * Determines whether a model exists by checking a unique column, including checking soft-deleted records - * - * @param mixed $value - * @param string $identifier - * @param bool $checkDeleted set to true to include soft-deleted records - * @return \UserFrosting\Sprinkle\Core\Database\Models\Model|null - */ - public static function findUnique($value, $identifier, $checkDeleted = TRUE) { - $query = static::where($identifier, $value); - - if ($checkDeleted) { - $query = $query->withTrashed(); - } - - return $query->first(); - } - - /** - * Determine if an relation exists on the model - even if it is null. - * - * @param string $key - * @return bool - */ - public function relationExists($key) { - return array_key_exists($key, $this->relations); - } - - /** - * Store the object in the DB, creating a new row if one doesn't already exist. - * - * Calls save(), then returns the id of the new record in the database. - * @return int the id of this object. - */ - public function store() { - $this->save(); - - // Store function should always return the id of the object - return $this->id; - } - - /** - * Overrides Laravel's base Model to return our custom query builder object. - * - * @return \UserFrosting\Sprinkles\Core\Database\Builder - */ - protected function newBaseQueryBuilder() { - /** @var UserFrosting\Sprinkle\Core\Util\ClassMapper $classMapper */ - $classMapper = static::$ci->classMapper; - - $connection = $this->getConnection(); - - return $classMapper->createInstance( - 'query_builder', - $connection, - $connection->getQueryGrammar(), - $connection->getPostProcessor() - ); - } - - /** - * Get the properties of this object as an associative array. Alias for toArray(). - * - * @deprecated since 4.1.8 There is no point in having this alias. - * @return array - */ - public function export() { - return $this->toArray(); - } - - /** - * For raw array fetching. Must be static, otherwise PHP gets confused about where to find $table. - * - * @deprecated since 4.1.8 setFetchMode is no longer available as of Laravel 5.4. - * @link https://github.com/laravel/framework/issues/17728 - */ - public static function queryBuilder() { - // Set query builder to fetch result sets as associative arrays (instead of creating stdClass objects) - DB::connection()->setFetchMode(\PDO::FETCH_ASSOC); - return DB::table(static::$table); - } -} +<?php
+/**
+ * UserFrosting (http://www.userfrosting.com)
+ *
+ * @link https://github.com/userfrosting/UserFrosting
+ * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License)
+ */
+
+namespace UserFrosting\Sprinkle\Core\Database\Models;
+
+use Illuminate\Database\Capsule\Manager as DB;
+use Illuminate\Database\Eloquent\Model as LaravelModel;
+use UserFrosting\Sprinkle\Core\Database\Models\Concerns\HasRelationships;
+
+/**
+ * Model Class
+ *
+ * UserFrosting's base data model, from which all UserFrosting data classes extend.
+ * @author Alex Weissman (https://alexanderweissman.com)
+ */
+abstract class Model extends LaravelModel
+{
+ use HasRelationships;
+
+ /**
+ * @var ContainerInterface The DI container for your application.
+ */
+ public static $ci;
+
+ /**
+ * @var bool Disable timestamps for now.
+ */
+ public $timestamps = FALSE;
+
+ public function __construct(array $attributes = []) {
+ // Hacky way to force the DB service to load before attempting to use the model
+ static::$ci['db'];
+
+ parent::__construct($attributes);
+ }
+
+ /**
+ * Determine if an attribute exists on the model - even if it is null.
+ *
+ * @param string $key
+ * @return bool
+ */
+ public function attributeExists($key) {
+ return array_key_exists($key, $this->attributes);
+ }
+
+ /**
+ * Determines whether a model exists by checking a unique column, including checking soft-deleted records
+ *
+ * @param mixed $value
+ * @param string $identifier
+ * @param bool $checkDeleted set to true to include soft-deleted records
+ * @return \UserFrosting\Sprinkle\Core\Database\Models\Model|null
+ */
+ public static function findUnique($value, $identifier, $checkDeleted = TRUE) {
+ $query = static::where($identifier, $value);
+
+ if ($checkDeleted) {
+ $query = $query->withTrashed();
+ }
+
+ return $query->first();
+ }
+
+ /**
+ * Determine if an relation exists on the model - even if it is null.
+ *
+ * @param string $key
+ * @return bool
+ */
+ public function relationExists($key) {
+ return array_key_exists($key, $this->relations);
+ }
+
+ /**
+ * Store the object in the DB, creating a new row if one doesn't already exist.
+ *
+ * Calls save(), then returns the id of the new record in the database.
+ * @return int the id of this object.
+ */
+ public function store() {
+ $this->save();
+
+ // Store function should always return the id of the object
+ return $this->id;
+ }
+
+ /**
+ * Overrides Laravel's base Model to return our custom query builder object.
+ *
+ * @return \UserFrosting\Sprinkles\Core\Database\Builder
+ */
+ protected function newBaseQueryBuilder() {
+ /** @var UserFrosting\Sprinkle\Core\Util\ClassMapper $classMapper */
+ $classMapper = static::$ci->classMapper;
+
+ $connection = $this->getConnection();
+
+ return $classMapper->createInstance(
+ 'query_builder',
+ $connection,
+ $connection->getQueryGrammar(),
+ $connection->getPostProcessor()
+ );
+ }
+
+ /**
+ * Get the properties of this object as an associative array. Alias for toArray().
+ *
+ * @deprecated since 4.1.8 There is no point in having this alias.
+ * @return array
+ */
+ public function export() {
+ return $this->toArray();
+ }
+
+ /**
+ * For raw array fetching. Must be static, otherwise PHP gets confused about where to find $table.
+ *
+ * @deprecated since 4.1.8 setFetchMode is no longer available as of Laravel 5.4.
+ * @link https://github.com/laravel/framework/issues/17728
+ */
+ public static function queryBuilder() {
+ // Set query builder to fetch result sets as associative arrays (instead of creating stdClass objects)
+ DB::connection()->setFetchMode(\PDO::FETCH_ASSOC);
+ return DB::table(static::$table);
+ }
+}
diff --git a/main/app/sprinkles/core/src/Database/Models/Throttle.php b/main/app/sprinkles/core/src/Database/Models/Throttle.php index 82d2c87..5810e0d 100644 --- a/main/app/sprinkles/core/src/Database/Models/Throttle.php +++ b/main/app/sprinkles/core/src/Database/Models/Throttle.php @@ -1,37 +1,37 @@ -<?php -/** - * UserFrosting (http://www.userfrosting.com) - * - * @link https://github.com/userfrosting/UserFrosting - * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License) - */ - -namespace UserFrosting\Sprinkle\Core\Database\Models; - -/** - * Throttle Class - * - * Represents a throttleable request from a user agent. - * @author Alex Weissman (https://alexanderweissman.com) - * @property string type - * @property string ip - * @property string request_data - */ -class Throttle extends Model -{ - /** - * @var string The name of the table for the current model. - */ - protected $table = "throttles"; - - protected $fillable = [ - "type", - "ip", - "request_data" - ]; - - /** - * @var bool Enable timestamps for Throttles. - */ - public $timestamps = TRUE; -} +<?php
+/**
+ * UserFrosting (http://www.userfrosting.com)
+ *
+ * @link https://github.com/userfrosting/UserFrosting
+ * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License)
+ */
+
+namespace UserFrosting\Sprinkle\Core\Database\Models;
+
+/**
+ * Throttle Class
+ *
+ * Represents a throttleable request from a user agent.
+ * @author Alex Weissman (https://alexanderweissman.com)
+ * @property string type
+ * @property string ip
+ * @property string request_data
+ */
+class Throttle extends Model
+{
+ /**
+ * @var string The name of the table for the current model.
+ */
+ protected $table = "throttles";
+
+ protected $fillable = [
+ "type",
+ "ip",
+ "request_data"
+ ];
+
+ /**
+ * @var bool Enable timestamps for Throttles.
+ */
+ public $timestamps = TRUE;
+}
diff --git a/main/app/sprinkles/core/src/Database/Relations/BelongsToManyConstrained.php b/main/app/sprinkles/core/src/Database/Relations/BelongsToManyConstrained.php index cf79223..a207b75 100644 --- a/main/app/sprinkles/core/src/Database/Relations/BelongsToManyConstrained.php +++ b/main/app/sprinkles/core/src/Database/Relations/BelongsToManyConstrained.php @@ -1,118 +1,118 @@ -<?php -/** - * UserFrosting (http://www.userfrosting.com) - * - * @link https://github.com/userfrosting/UserFrosting - * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License) - */ - -namespace UserFrosting\Sprinkle\Core\Database\Relations; - -use Illuminate\Database\Eloquent\Model; -use Illuminate\Database\Eloquent\Builder; -use Illuminate\Database\Eloquent\Collection; -use Illuminate\Database\Eloquent\Relations\BelongsToMany; - -/** - * A BelongsToMany relationship that constrains on the value of an additional foreign key in the pivot table. - * This has been superseded by the BelongsToTernary relationship since 4.1.6. - * - * @deprecated since 4.1.6 - * @author Alex Weissman (https://alexanderweissman.com) - * @link https://github.com/laravel/framework/blob/5.4/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php - */ -class BelongsToManyConstrained extends BelongsToMany -{ - /** - * @var The pivot foreign key on which to constrain the result sets for this relation. - */ - protected $constraintKey; - - /** - * Create a new belongs to many constrained relationship instance. - * - * @param \Illuminate\Database\Eloquent\Builder $query - * @param \Illuminate\Database\Eloquent\Model $parent - * @param string $constraintKey - * @param string $table - * @param string $foreignKey - * @param string $relatedKey - * @param string $relationName - * @return void - */ - public function __construct(Builder $query, Model $parent, $constraintKey, $table, $foreignKey, $relatedKey, $relationName = NULL) { - $this->constraintKey = $constraintKey; - parent::__construct($query, $parent, $table, $foreignKey, $relatedKey, $relationName); - } - - /** - * Set the constraints for an eager load of the relation. - * - * @param array $models - * @return void - */ - public function addEagerConstraints(array $models) { - // To make the query more efficient, we only bother querying related models if their pivot key value - // matches the pivot key value of one of the parent models. - $pivotKeys = $this->getPivotKeys($models, $this->constraintKey); - $this->query->whereIn($this->getQualifiedForeignKeyName(), $this->getKeys($models)) - ->whereIn($this->constraintKey, $pivotKeys); - } - - /** - * Gets a list of unique pivot key values from an array of models. - */ - protected function getPivotKeys(array $models, $pivotKey) { - $pivotKeys = []; - foreach ($models as $model) { - $pivotKeys[] = $model->getRelation('pivot')->{$pivotKey}; - } - return array_unique($pivotKeys); - } - - /** - * Match the eagerly loaded results to their parents, constraining the results by matching the values of $constraintKey - * in the parent object to the child objects. - * - * @link Called in https://github.com/laravel/framework/blob/2f4135d8db5ded851d1f4f611124c53b768a3c08/src/Illuminate/Database/Eloquent/Builder.php - * @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) { - $pivotValue = $model->getRelation('pivot')->{$this->constraintKey}; - if (isset($dictionary[$key = $model->getKey()])) { - // Only match children if their pivot key value matches that of the parent model - $items = $this->findMatchingPivots($dictionary[$key], $pivotValue); - $model->setRelation( - $relation, $this->related->newCollection($items) - ); - } - } - - return $models; - } - - /** - * Filter an array of models, only taking models whose $constraintKey value matches $pivotValue. - * - * @param mixed $pivotValue - * @return array - */ - protected function findMatchingPivots($items, $pivotValue) { - $result = []; - foreach ($items as $item) { - if ($item->getRelation('pivot')->{$this->constraintKey} == $pivotValue) { - $result[] = $item; - } - } - return $result; - } -} +<?php
+/**
+ * UserFrosting (http://www.userfrosting.com)
+ *
+ * @link https://github.com/userfrosting/UserFrosting
+ * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License)
+ */
+
+namespace UserFrosting\Sprinkle\Core\Database\Relations;
+
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\Builder;
+use Illuminate\Database\Eloquent\Collection;
+use Illuminate\Database\Eloquent\Relations\BelongsToMany;
+
+/**
+ * A BelongsToMany relationship that constrains on the value of an additional foreign key in the pivot table.
+ * This has been superseded by the BelongsToTernary relationship since 4.1.6.
+ *
+ * @deprecated since 4.1.6
+ * @author Alex Weissman (https://alexanderweissman.com)
+ * @link https://github.com/laravel/framework/blob/5.4/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php
+ */
+class BelongsToManyConstrained extends BelongsToMany
+{
+ /**
+ * @var The pivot foreign key on which to constrain the result sets for this relation.
+ */
+ protected $constraintKey;
+
+ /**
+ * Create a new belongs to many constrained relationship instance.
+ *
+ * @param \Illuminate\Database\Eloquent\Builder $query
+ * @param \Illuminate\Database\Eloquent\Model $parent
+ * @param string $constraintKey
+ * @param string $table
+ * @param string $foreignKey
+ * @param string $relatedKey
+ * @param string $relationName
+ * @return void
+ */
+ public function __construct(Builder $query, Model $parent, $constraintKey, $table, $foreignKey, $relatedKey, $relationName = NULL) {
+ $this->constraintKey = $constraintKey;
+ parent::__construct($query, $parent, $table, $foreignKey, $relatedKey, $relationName);
+ }
+
+ /**
+ * Set the constraints for an eager load of the relation.
+ *
+ * @param array $models
+ * @return void
+ */
+ public function addEagerConstraints(array $models) {
+ // To make the query more efficient, we only bother querying related models if their pivot key value
+ // matches the pivot key value of one of the parent models.
+ $pivotKeys = $this->getPivotKeys($models, $this->constraintKey);
+ $this->query->whereIn($this->getQualifiedForeignKeyName(), $this->getKeys($models))
+ ->whereIn($this->constraintKey, $pivotKeys);
+ }
+
+ /**
+ * Gets a list of unique pivot key values from an array of models.
+ */
+ protected function getPivotKeys(array $models, $pivotKey) {
+ $pivotKeys = [];
+ foreach ($models as $model) {
+ $pivotKeys[] = $model->getRelation('pivot')->{$pivotKey};
+ }
+ return array_unique($pivotKeys);
+ }
+
+ /**
+ * Match the eagerly loaded results to their parents, constraining the results by matching the values of $constraintKey
+ * in the parent object to the child objects.
+ *
+ * @link Called in https://github.com/laravel/framework/blob/2f4135d8db5ded851d1f4f611124c53b768a3c08/src/Illuminate/Database/Eloquent/Builder.php
+ * @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) {
+ $pivotValue = $model->getRelation('pivot')->{$this->constraintKey};
+ if (isset($dictionary[$key = $model->getKey()])) {
+ // Only match children if their pivot key value matches that of the parent model
+ $items = $this->findMatchingPivots($dictionary[$key], $pivotValue);
+ $model->setRelation(
+ $relation, $this->related->newCollection($items)
+ );
+ }
+ }
+
+ return $models;
+ }
+
+ /**
+ * Filter an array of models, only taking models whose $constraintKey value matches $pivotValue.
+ *
+ * @param mixed $pivotValue
+ * @return array
+ */
+ protected function findMatchingPivots($items, $pivotValue) {
+ $result = [];
+ foreach ($items as $item) {
+ if ($item->getRelation('pivot')->{$this->constraintKey} == $pivotValue) {
+ $result[] = $item;
+ }
+ }
+ return $result;
+ }
+}
diff --git a/main/app/sprinkles/core/src/Database/Relations/BelongsToManyThrough.php b/main/app/sprinkles/core/src/Database/Relations/BelongsToManyThrough.php index 67304be..24aa4cf 100644 --- a/main/app/sprinkles/core/src/Database/Relations/BelongsToManyThrough.php +++ b/main/app/sprinkles/core/src/Database/Relations/BelongsToManyThrough.php @@ -1,223 +1,223 @@ -<?php -/** - * UserFrosting (http://www.userfrosting.com) - * - * @link https://github.com/userfrosting/UserFrosting - * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License) - */ - -namespace UserFrosting\Sprinkle\Core\Database\Relations; - -use Illuminate\Database\Eloquent\Model; -use Illuminate\Database\Eloquent\Builder; -use Illuminate\Database\Eloquent\Collection; -use Illuminate\Database\Eloquent\Relations\BelongsToMany; -use Illuminate\Database\Eloquent\Relations\Relation; -use UserFrosting\Sprinkle\Core\Database\Relations\Concerns\Unique; - -/** - * A BelongsToMany relationship that queries through an additional intermediate model. - * - * @author Alex Weissman (https://alexanderweissman.com) - * @link https://github.com/laravel/framework/blob/5.4/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php - */ -class BelongsToManyThrough extends BelongsToMany -{ - use Unique; - - /** - * The relation through which we are joining. - * - * @var Relation - */ - protected $intermediateRelation; - - /** - * Create a new belongs to many relationship instance. - * - * @param \Illuminate\Database\Eloquent\Builder $query - * @param \Illuminate\Database\Eloquent\Model $parent - * @param \Illuminate\Database\Eloquent\Relations\Relation $intermediateRelation - * @param string $table - * @param string $foreignKey - * @param string $relatedKey - * @param string $relationName - * @return void - */ - public function __construct(Builder $query, Model $parent, Relation $intermediateRelation, $table, $foreignKey, $relatedKey, $relationName = NULL) { - $this->intermediateRelation = $intermediateRelation; - - parent::__construct($query, $parent, $table, $foreignKey, $relatedKey, $relationName); - } - - /** - * Use the intermediate relationship to determine the "parent" pivot key name - * - * This is a crazy roundabout way to get the name of the intermediate relation's foreign key. - * It would be better if BelongsToMany had a simple accessor for its foreign key. - * @return string - */ - public function getParentKeyName() { - return $this->intermediateRelation->newExistingPivot()->getForeignKey(); - } - - /** - * Get the key for comparing against the parent key in "has" query. - * - * @see \Illuminate\Database\Eloquent\Relations\BelongsToMany - * @return string - */ - public function getExistenceCompareKey() { - return $this->intermediateRelation->getQualifiedForeignKeyName(); - } - - /** - * Add a "via" query to load the intermediate models through which the child models are related. - * - * @param string $viaRelationName - * @param callable $viaCallback - * @return $this - */ - public function withVia($viaRelationName = NULL, $viaCallback = NULL) { - $this->tertiaryRelated = $this->intermediateRelation->getRelated(); - - // Set tertiary key and related model - $this->tertiaryKey = $this->foreignKey; - - $this->tertiaryRelationName = is_null($viaRelationName) ? $this->intermediateRelation->getRelationName() . '_via' : $viaRelationName; - - $this->tertiaryCallback = is_null($viaCallback) - ? function () { - // - } - : $viaCallback; - - return $this; - } - - /** - * Set the constraints for an eager load of the relation. - * - * @param array $models - * @return void - */ - public function addEagerConstraints(array $models) { - // Constraint to only load models where the intermediate relation's foreign key matches the parent model - $intermediateForeignKeyName = $this->intermediateRelation->getQualifiedForeignKeyName(); - - return $this->query->whereIn($intermediateForeignKeyName, $this->getKeys($models)); - } - - /** - * Set the where clause for the relation query. - * - * @return $this - */ - protected function addWhereConstraints() { - $parentKeyName = $this->getParentKeyName(); - - $this->query->where( - $parentKeyName, '=', $this->parent->getKey() - ); - - return $this; - } - - /** - * 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) { - // Build dictionary of parent (e.g. user) to related (e.g. permission) models - list($dictionary, $nestedViaDictionary) = $this->buildDictionary($results, $this->getParentKeyName()); - - // 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()])) { - /** @var array */ - $items = $dictionary[$key]; - - // Eliminate any duplicates - $items = $this->related->newCollection($items)->unique(); - - // If set, match up the via models to the models in the related collection - if (!is_null($nestedViaDictionary)) { - $this->matchTertiaryModels($nestedViaDictionary[$key], $items); - } - - // Remove the tertiary pivot key from the condensed models - foreach ($items as $relatedModel) { - unset($relatedModel->pivot->{$this->foreignKey}); - } - - $model->setRelation( - $relation, $items - ); - } - } - - return $models; - } - - /** - * Unset tertiary pivots on a collection or array of models. - * - * @param \Illuminate\Database\Eloquent\Collection $models - * @return void - */ - protected function unsetTertiaryPivots(Collection $models) { - foreach ($models as $model) { - unset($model->pivot->{$this->foreignKey}); - } - } - - /** - * Set the join clause for the relation query. - * - * @param \Illuminate\Database\Eloquent\Builder|null $query - * @return $this - */ - protected function performJoin($query = NULL) { - $query = $query ?: $this->query; - - parent::performJoin($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. - $intermediateTable = $this->intermediateRelation->getTable(); - - $key = $this->intermediateRelation->getQualifiedRelatedKeyName(); - - $query->join($intermediateTable, $key, '=', $this->getQualifiedForeignKeyName()); - - return $this; - } - - /** - * Get the pivot columns for the relation. - * - * "pivot_" is prefixed to each column for easy removal later. - * - * @return array - */ - protected function aliasedPivotColumns() { - $defaults = [$this->foreignKey, $this->relatedKey]; - $aliasedPivotColumns = collect(array_merge($defaults, $this->pivotColumns))->map(function ($column) { - return $this->table . '.' . $column . ' as pivot_' . $column; - }); - - $parentKeyName = $this->getParentKeyName(); - - // Add pivot column for the intermediate relation - $aliasedPivotColumns[] = "{$this->intermediateRelation->getQualifiedForeignKeyName()} as pivot_$parentKeyName"; - - return $aliasedPivotColumns->unique()->all(); - } -} +<?php
+/**
+ * UserFrosting (http://www.userfrosting.com)
+ *
+ * @link https://github.com/userfrosting/UserFrosting
+ * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License)
+ */
+
+namespace UserFrosting\Sprinkle\Core\Database\Relations;
+
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\Builder;
+use Illuminate\Database\Eloquent\Collection;
+use Illuminate\Database\Eloquent\Relations\BelongsToMany;
+use Illuminate\Database\Eloquent\Relations\Relation;
+use UserFrosting\Sprinkle\Core\Database\Relations\Concerns\Unique;
+
+/**
+ * A BelongsToMany relationship that queries through an additional intermediate model.
+ *
+ * @author Alex Weissman (https://alexanderweissman.com)
+ * @link https://github.com/laravel/framework/blob/5.4/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php
+ */
+class BelongsToManyThrough extends BelongsToMany
+{
+ use Unique;
+
+ /**
+ * The relation through which we are joining.
+ *
+ * @var Relation
+ */
+ protected $intermediateRelation;
+
+ /**
+ * Create a new belongs to many relationship instance.
+ *
+ * @param \Illuminate\Database\Eloquent\Builder $query
+ * @param \Illuminate\Database\Eloquent\Model $parent
+ * @param \Illuminate\Database\Eloquent\Relations\Relation $intermediateRelation
+ * @param string $table
+ * @param string $foreignKey
+ * @param string $relatedKey
+ * @param string $relationName
+ * @return void
+ */
+ public function __construct(Builder $query, Model $parent, Relation $intermediateRelation, $table, $foreignKey, $relatedKey, $relationName = NULL) {
+ $this->intermediateRelation = $intermediateRelation;
+
+ parent::__construct($query, $parent, $table, $foreignKey, $relatedKey, $relationName);
+ }
+
+ /**
+ * Use the intermediate relationship to determine the "parent" pivot key name
+ *
+ * This is a crazy roundabout way to get the name of the intermediate relation's foreign key.
+ * It would be better if BelongsToMany had a simple accessor for its foreign key.
+ * @return string
+ */
+ public function getParentKeyName() {
+ return $this->intermediateRelation->newExistingPivot()->getForeignKey();
+ }
+
+ /**
+ * Get the key for comparing against the parent key in "has" query.
+ *
+ * @see \Illuminate\Database\Eloquent\Relations\BelongsToMany
+ * @return string
+ */
+ public function getExistenceCompareKey() {
+ return $this->intermediateRelation->getQualifiedForeignKeyName();
+ }
+
+ /**
+ * Add a "via" query to load the intermediate models through which the child models are related.
+ *
+ * @param string $viaRelationName
+ * @param callable $viaCallback
+ * @return $this
+ */
+ public function withVia($viaRelationName = NULL, $viaCallback = NULL) {
+ $this->tertiaryRelated = $this->intermediateRelation->getRelated();
+
+ // Set tertiary key and related model
+ $this->tertiaryKey = $this->foreignKey;
+
+ $this->tertiaryRelationName = is_null($viaRelationName) ? $this->intermediateRelation->getRelationName() . '_via' : $viaRelationName;
+
+ $this->tertiaryCallback = is_null($viaCallback)
+ ? function () {
+ //
+ }
+ : $viaCallback;
+
+ return $this;
+ }
+
+ /**
+ * Set the constraints for an eager load of the relation.
+ *
+ * @param array $models
+ * @return void
+ */
+ public function addEagerConstraints(array $models) {
+ // Constraint to only load models where the intermediate relation's foreign key matches the parent model
+ $intermediateForeignKeyName = $this->intermediateRelation->getQualifiedForeignKeyName();
+
+ return $this->query->whereIn($intermediateForeignKeyName, $this->getKeys($models));
+ }
+
+ /**
+ * Set the where clause for the relation query.
+ *
+ * @return $this
+ */
+ protected function addWhereConstraints() {
+ $parentKeyName = $this->getParentKeyName();
+
+ $this->query->where(
+ $parentKeyName, '=', $this->parent->getKey()
+ );
+
+ return $this;
+ }
+
+ /**
+ * 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) {
+ // Build dictionary of parent (e.g. user) to related (e.g. permission) models
+ list($dictionary, $nestedViaDictionary) = $this->buildDictionary($results, $this->getParentKeyName());
+
+ // 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()])) {
+ /** @var array */
+ $items = $dictionary[$key];
+
+ // Eliminate any duplicates
+ $items = $this->related->newCollection($items)->unique();
+
+ // If set, match up the via models to the models in the related collection
+ if (!is_null($nestedViaDictionary)) {
+ $this->matchTertiaryModels($nestedViaDictionary[$key], $items);
+ }
+
+ // Remove the tertiary pivot key from the condensed models
+ foreach ($items as $relatedModel) {
+ unset($relatedModel->pivot->{$this->foreignKey});
+ }
+
+ $model->setRelation(
+ $relation, $items
+ );
+ }
+ }
+
+ return $models;
+ }
+
+ /**
+ * Unset tertiary pivots on a collection or array of models.
+ *
+ * @param \Illuminate\Database\Eloquent\Collection $models
+ * @return void
+ */
+ protected function unsetTertiaryPivots(Collection $models) {
+ foreach ($models as $model) {
+ unset($model->pivot->{$this->foreignKey});
+ }
+ }
+
+ /**
+ * Set the join clause for the relation query.
+ *
+ * @param \Illuminate\Database\Eloquent\Builder|null $query
+ * @return $this
+ */
+ protected function performJoin($query = NULL) {
+ $query = $query ?: $this->query;
+
+ parent::performJoin($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.
+ $intermediateTable = $this->intermediateRelation->getTable();
+
+ $key = $this->intermediateRelation->getQualifiedRelatedKeyName();
+
+ $query->join($intermediateTable, $key, '=', $this->getQualifiedForeignKeyName());
+
+ return $this;
+ }
+
+ /**
+ * Get the pivot columns for the relation.
+ *
+ * "pivot_" is prefixed to each column for easy removal later.
+ *
+ * @return array
+ */
+ protected function aliasedPivotColumns() {
+ $defaults = [$this->foreignKey, $this->relatedKey];
+ $aliasedPivotColumns = collect(array_merge($defaults, $this->pivotColumns))->map(function ($column) {
+ return $this->table . '.' . $column . ' as pivot_' . $column;
+ });
+
+ $parentKeyName = $this->getParentKeyName();
+
+ // Add pivot column for the intermediate relation
+ $aliasedPivotColumns[] = "{$this->intermediateRelation->getQualifiedForeignKeyName()} as pivot_$parentKeyName";
+
+ return $aliasedPivotColumns->unique()->all();
+ }
+}
diff --git a/main/app/sprinkles/core/src/Database/Relations/BelongsToManyUnique.php b/main/app/sprinkles/core/src/Database/Relations/BelongsToManyUnique.php index d5d473d..1bde954 100644 --- a/main/app/sprinkles/core/src/Database/Relations/BelongsToManyUnique.php +++ b/main/app/sprinkles/core/src/Database/Relations/BelongsToManyUnique.php @@ -1,23 +1,23 @@ -<?php -/** - * UserFrosting (http://www.userfrosting.com) - * - * @link https://github.com/userfrosting/UserFrosting - * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License) - */ - -namespace UserFrosting\Sprinkle\Core\Database\Relations; - -use Illuminate\Database\Eloquent\Relations\BelongsToMany; -use UserFrosting\Sprinkle\Core\Database\Relations\Concerns\Unique; - -/** - * A BelongsToMany relationship that reduces the related members to a unique (by primary key) set. - * - * @author Alex Weissman (https://alexanderweissman.com) - * @link https://github.com/laravel/framework/blob/5.4/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php - */ -class BelongsToManyUnique extends BelongsToMany -{ - use Unique; -} +<?php
+/**
+ * UserFrosting (http://www.userfrosting.com)
+ *
+ * @link https://github.com/userfrosting/UserFrosting
+ * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License)
+ */
+
+namespace UserFrosting\Sprinkle\Core\Database\Relations;
+
+use Illuminate\Database\Eloquent\Relations\BelongsToMany;
+use UserFrosting\Sprinkle\Core\Database\Relations\Concerns\Unique;
+
+/**
+ * A BelongsToMany relationship that reduces the related members to a unique (by primary key) set.
+ *
+ * @author Alex Weissman (https://alexanderweissman.com)
+ * @link https://github.com/laravel/framework/blob/5.4/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php
+ */
+class BelongsToManyUnique extends BelongsToMany
+{
+ use Unique;
+}
diff --git a/main/app/sprinkles/core/src/Database/Relations/Concerns/Syncable.php b/main/app/sprinkles/core/src/Database/Relations/Concerns/Syncable.php index cb32d52..b52ab99 100644 --- a/main/app/sprinkles/core/src/Database/Relations/Concerns/Syncable.php +++ b/main/app/sprinkles/core/src/Database/Relations/Concerns/Syncable.php @@ -1,130 +1,130 @@ -<?php -/** - * UserFrosting (http://www.userfrosting.com) - * - * @link https://github.com/userfrosting/UserFrosting - * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License) - */ - -namespace UserFrosting\Sprinkle\Core\Database\Relations\Concerns; - -use Illuminate\Database\Eloquent\Model; -use Illuminate\Database\Eloquent\Builder; -use Illuminate\Database\Eloquent\Collection; - -/** - * Implements the `sync` method for HasMany relationships. - * - * @author Alex Weissman (https://alexanderweissman.com) - */ -trait Syncable -{ - /** - * Synchronizes an array of data for related models with a parent model. - * - * @param mixed[] $data - * @param bool $deleting Delete models from the database that are not represented in the input data. - * @param bool $forceCreate Ignore mass assignment restrictions on child models. - * @param string $relatedKeyName The primary key used to determine which child models are new, updated, or deleted. - */ - public function sync($data, $deleting = TRUE, $forceCreate = FALSE, $relatedKeyName = NULL) { - $changes = [ - 'created' => [], 'deleted' => [], 'updated' => [], - ]; - - if (is_null($relatedKeyName)) { - $relatedKeyName = $this->related->getKeyName(); - } - - // First we need to attach any of the associated models that are not currently - // in the child entity 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->newQuery()->pluck( - $relatedKeyName - )->all(); - - // Separate the submitted data into "update" and "new" - $updateRows = []; - $newRows = []; - foreach ($data as $row) { - // We determine "updateable" rows as those whose $relatedKeyName (usually 'id') is set, not empty, and - // match a related row in the database. - if (isset($row[$relatedKeyName]) && !empty($row[$relatedKeyName]) && in_array($row[$relatedKeyName], $current)) { - $id = $row[$relatedKeyName]; - $updateRows[$id] = $row; - } else { - $newRows[] = $row; - } - } - - // Next, we'll determine the rows in the database that aren't in the "update" list. - // These rows will be scheduled for deletion. Again, we determine based on the relatedKeyName (typically 'id'). - $updateIds = array_keys($updateRows); - $deleteIds = []; - foreach ($current as $currentId) { - if (!in_array($currentId, $updateIds)) { - $deleteIds[] = $currentId; - } - } - - // Delete any non-matching rows - if ($deleting && count($deleteIds) > 0) { - // Remove global scopes to avoid ambiguous keys - $this->getRelated() - ->withoutGlobalScopes() - ->whereIn($relatedKeyName, $deleteIds) - ->delete(); - - $changes['deleted'] = $this->castKeys($deleteIds); - } - - // Update the updatable rows - foreach ($updateRows as $id => $row) { - // Remove global scopes to avoid ambiguous keys - $this->getRelated() - ->withoutGlobalScopes() - ->where($relatedKeyName, $id) - ->update($row); - } - - $changes['updated'] = $this->castKeys($updateIds); - - // Insert the new rows - $newIds = []; - foreach ($newRows as $row) { - if ($forceCreate) { - $newModel = $this->forceCreate($row); - } else { - $newModel = $this->create($row); - } - $newIds[] = $newModel->$relatedKeyName; - } - - $changes['created'] = $this->castKeys($newIds); - - return $changes; - } - - - /** - * Cast the given keys to integers if they are numeric and string otherwise. - * - * @param array $keys - * @return array - */ - protected function castKeys(array $keys) { - return (array)array_map(function ($v) { - return $this->castKey($v); - }, $keys); - } - - /** - * Cast the given key to an integer if it is numeric. - * - * @param mixed $key - * @return mixed - */ - protected function castKey($key) { - return is_numeric($key) ? (int)$key : (string)$key; - } -} +<?php
+/**
+ * UserFrosting (http://www.userfrosting.com)
+ *
+ * @link https://github.com/userfrosting/UserFrosting
+ * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License)
+ */
+
+namespace UserFrosting\Sprinkle\Core\Database\Relations\Concerns;
+
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\Builder;
+use Illuminate\Database\Eloquent\Collection;
+
+/**
+ * Implements the `sync` method for HasMany relationships.
+ *
+ * @author Alex Weissman (https://alexanderweissman.com)
+ */
+trait Syncable
+{
+ /**
+ * Synchronizes an array of data for related models with a parent model.
+ *
+ * @param mixed[] $data
+ * @param bool $deleting Delete models from the database that are not represented in the input data.
+ * @param bool $forceCreate Ignore mass assignment restrictions on child models.
+ * @param string $relatedKeyName The primary key used to determine which child models are new, updated, or deleted.
+ */
+ public function sync($data, $deleting = TRUE, $forceCreate = FALSE, $relatedKeyName = NULL) {
+ $changes = [
+ 'created' => [], 'deleted' => [], 'updated' => [],
+ ];
+
+ if (is_null($relatedKeyName)) {
+ $relatedKeyName = $this->related->getKeyName();
+ }
+
+ // First we need to attach any of the associated models that are not currently
+ // in the child entity 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->newQuery()->pluck(
+ $relatedKeyName
+ )->all();
+
+ // Separate the submitted data into "update" and "new"
+ $updateRows = [];
+ $newRows = [];
+ foreach ($data as $row) {
+ // We determine "updateable" rows as those whose $relatedKeyName (usually 'id') is set, not empty, and
+ // match a related row in the database.
+ if (isset($row[$relatedKeyName]) && !empty($row[$relatedKeyName]) && in_array($row[$relatedKeyName], $current)) {
+ $id = $row[$relatedKeyName];
+ $updateRows[$id] = $row;
+ } else {
+ $newRows[] = $row;
+ }
+ }
+
+ // Next, we'll determine the rows in the database that aren't in the "update" list.
+ // These rows will be scheduled for deletion. Again, we determine based on the relatedKeyName (typically 'id').
+ $updateIds = array_keys($updateRows);
+ $deleteIds = [];
+ foreach ($current as $currentId) {
+ if (!in_array($currentId, $updateIds)) {
+ $deleteIds[] = $currentId;
+ }
+ }
+
+ // Delete any non-matching rows
+ if ($deleting && count($deleteIds) > 0) {
+ // Remove global scopes to avoid ambiguous keys
+ $this->getRelated()
+ ->withoutGlobalScopes()
+ ->whereIn($relatedKeyName, $deleteIds)
+ ->delete();
+
+ $changes['deleted'] = $this->castKeys($deleteIds);
+ }
+
+ // Update the updatable rows
+ foreach ($updateRows as $id => $row) {
+ // Remove global scopes to avoid ambiguous keys
+ $this->getRelated()
+ ->withoutGlobalScopes()
+ ->where($relatedKeyName, $id)
+ ->update($row);
+ }
+
+ $changes['updated'] = $this->castKeys($updateIds);
+
+ // Insert the new rows
+ $newIds = [];
+ foreach ($newRows as $row) {
+ if ($forceCreate) {
+ $newModel = $this->forceCreate($row);
+ } else {
+ $newModel = $this->create($row);
+ }
+ $newIds[] = $newModel->$relatedKeyName;
+ }
+
+ $changes['created'] = $this->castKeys($newIds);
+
+ return $changes;
+ }
+
+
+ /**
+ * Cast the given keys to integers if they are numeric and string otherwise.
+ *
+ * @param array $keys
+ * @return array
+ */
+ protected function castKeys(array $keys) {
+ return (array)array_map(function ($v) {
+ return $this->castKey($v);
+ }, $keys);
+ }
+
+ /**
+ * Cast the given key to an integer if it is numeric.
+ *
+ * @param mixed $key
+ * @return mixed
+ */
+ protected function castKey($key) {
+ return is_numeric($key) ? (int)$key : (string)$key;
+ }
+}
diff --git a/main/app/sprinkles/core/src/Database/Relations/Concerns/Unique.php b/main/app/sprinkles/core/src/Database/Relations/Concerns/Unique.php index 3a321e4..deb2673 100644 --- a/main/app/sprinkles/core/src/Database/Relations/Concerns/Unique.php +++ b/main/app/sprinkles/core/src/Database/Relations/Concerns/Unique.php @@ -1,543 +1,543 @@ -<?php -/** - * UserFrosting (http://www.userfrosting.com) - * - * @link https://github.com/userfrosting/UserFrosting - * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License) - */ - -namespace UserFrosting\Sprinkle\Core\Database\Relations\Concerns; - -use Illuminate\Database\Eloquent\Builder; -use Illuminate\Database\Eloquent\Collection; -use Illuminate\Database\Query\Expression; - -/** - * Enforce uniqueness for BelongsToManyUnique, MorphToManyUnique, and BelongsToManyThrough. - * - * @author Alex Weissman (https://alexanderweissman.com) - */ -trait Unique -{ - /** - * The related tertiary model instance. - * - * @var \Illuminate\Database\Eloquent\Model - */ - protected $tertiaryRelated = NULL; - - /** - * The name to use for the tertiary relation (e.g. 'roles_via', etc) - * - * @var string - */ - protected $tertiaryRelationName = NULL; - - /** - * The foreign key to the related tertiary model instance. - * - * @var string - */ - protected $tertiaryKey; - - /** - * A callback to apply to the tertiary query. - * - * @var callable|null - */ - protected $tertiaryCallback = NULL; - - /** - * The limit to apply on the number of related models retrieved. - * - * @var int|null - */ - protected $limit = NULL; - - /** - * The offset to apply on the related models retrieved. - * - * @var int|null - */ - protected $offset = NULL; - - /** - * Alias to set the "offset" value of the query. - * - * @param int $value - * @return $this - */ - public function skip($value) { - return $this->offset($value); - } - - /** - * Set the "offset" value of the query. - * - * Implement for 'unionOffset' as well? (By checking the value of $this->query->getQuery()->unions) - * @see \Illuminate\Database\Query\Builder - * @param int $value - * @return $this - */ - public function offset($value) { - $this->offset = max(0, $value); - - return $this; - } - - /** - * Alias to set the "limit" value of the query. - * - * @param int $value - * @return $this - */ - public function take($value) { - return $this->limit($value); - } - - /** - * Set the "limit" value of the query. - * - * Implement for 'unionLimit' as well? (By checking the value of $this->query->getQuery()->unions) - * @see \Illuminate\Database\Query\Builder - * @param int $value - * @return $this - */ - public function limit($value) { - if ($value >= 0) { - $this->limit = $value; - } - - return $this; - } - - /** - * Set the limit on the number of intermediate models to load. - * - * @deprecated since 4.1.7 - * @param int $value - * @return $this - */ - public function withLimit($value) { - return $this->limit($value); - } - - /** - * Set the offset when loading the intermediate models. - * - * @deprecated since 4.1.7 - * @param int $value - * @return $this - */ - public function withOffset($value) { - return $this->offset($value); - } - - /** - * Add a query to load the nested tertiary models for this relationship. - * - * @param \Illuminate\Database\Eloquent\Model $tertiaryRelated - * @param string $tertiaryRelationName - * @param string $tertiaryKey - * @param callable $tertiaryCallback - * @return $this - */ - public function withTertiary($tertiaryRelated, $tertiaryRelationName = NULL, $tertiaryKey = NULL, $tertiaryCallback = NULL) { - $this->tertiaryRelated = new $tertiaryRelated; - - // Try to guess the tertiary related key from the tertiaryRelated model. - $this->tertiaryKey = $tertiaryKey ?: $this->tertiaryRelated->getForeignKey(); - - // Also add the tertiary key as a pivot - $this->withPivot($this->tertiaryKey); - - $this->tertiaryRelationName = is_null($tertiaryRelationName) ? $this->tertiaryRelated->getTable() : $tertiaryRelationName; - - $this->tertiaryCallback = is_null($tertiaryCallback) - ? function () { - // - } - : $tertiaryCallback; - - return $this; - } - - /** - * Return the count of child models for this relationship. - * - * @see http://stackoverflow.com/a/29728129/2970321 - * @return int - */ - public function count() { - $constrainedBuilder = clone $this->query; - - $constrainedBuilder = $constrainedBuilder->distinct(); - - return $constrainedBuilder->count($this->relatedKey); - } - - /** - * Add the constraints for a relationship count query. - * - * @see \Illuminate\Database\Eloquent\Relations\Relation - * @param \Illuminate\Database\Eloquent\Builder $query - * @param \Illuminate\Database\Eloquent\Builder $parentQuery - * @return \Illuminate\Database\Eloquent\Builder - */ - public function getRelationExistenceCountQuery(Builder $query, Builder $parentQuery) { - return $this->getRelationExistenceQuery( - $query, $parentQuery, new Expression("count(distinct {$this->relatedKey})") - ); - } - - /** - * 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) { - // Build dictionary of parent (e.g. user) to related (e.g. permission) models - list($dictionary, $nestedTertiaryDictionary) = $this->buildDictionary($results, $this->foreignKey); - - // 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()])) { - /** @var array */ - $items = $dictionary[$key]; - - // Eliminate any duplicates - $items = $this->related->newCollection($items)->unique(); - - // If set, match up the tertiary models to the models in the related collection - if (!is_null($nestedTertiaryDictionary)) { - $this->matchTertiaryModels($nestedTertiaryDictionary[$key], $items); - } - - $model->setRelation( - $relation, $items - ); - } - } - - return $models; - } - - /** - * Execute the query as a "select" statement, getting all requested models - * and matching up any tertiary models. - * - * @param array $columns - * @return \Illuminate\Database\Eloquent\Collection - */ - public function get($columns = ['*']) { - // Get models and condense the result set - $models = $this->getModels($columns, TRUE); - - // Remove the tertiary pivot key from the condensed models - $this->unsetTertiaryPivots($models); - - return $models; - } - - /** - * If we are applying either a limit or offset, we'll first determine a limited/offset list of model ids - * to select from in the final query. - * - * @param \Illuminate\Database\Eloquent\Builder $query - * @param int $limit - * @param int $offset - * @return \Illuminate\Database\Eloquent\Builder - */ - public function getPaginatedQuery(Builder $query, $limit = NULL, $offset = NULL) { - $constrainedBuilder = clone $query; - - // Since some unique models will be represented by more than one row in the database, - // we cannot apply limit/offset directly to the query. If we did that, we'd miss - // some of the records that are to be coalesced into the final set of models. - // Instead, we perform an additional query with grouping and limit/offset to determine - // the desired set of unique model _ids_, and then constrain our final query - // to these models with a whereIn clause. - $relatedKeyName = $this->related->getQualifiedKeyName(); - - // Apply an additional scope to override any selected columns in other global scopes - $uniqueIdScope = function ($subQuery) use ($relatedKeyName) { - $subQuery->select($relatedKeyName) - ->groupBy($relatedKeyName); - }; - - $identifier = spl_object_hash($uniqueIdScope); - - $constrainedBuilder->withGlobalScope($identifier, $uniqueIdScope); - - if ($limit) { - $constrainedBuilder->limit($limit); - } - - if ($offset) { - $constrainedBuilder->offset($offset); - } - - $primaryKeyName = $this->getParent()->getKeyName(); - $modelIds = $constrainedBuilder->get()->pluck($primaryKeyName)->toArray(); - - // Modify the unconstrained query to limit to these models - return $query->whereIn($relatedKeyName, $modelIds); - } - - /** - * Get the full join results for this query, overriding the default getEager() method. - * The default getEager() method would normally just call get() on this relationship. - * This is not what we want here though, because our get() method removes records before - * `match` has a chance to build out the substructures. - * - * @return \Illuminate\Database\Eloquent\Collection - */ - public function getEager() { - return $this->getModels(['*'], FALSE); - } - - /** - * Get the hydrated models and eager load their relations, optionally - * condensing the set of models before performing the eager loads. - * - * @param array $columns - * @param bool $condenseModels - * @return \Illuminate\Database\Eloquent\Collection - */ - public function getModels($columns = ['*'], $condenseModels = TRUE) { - // 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; - - // Add any necessary pagination on the related models - if ($this->limit || $this->offset) { - $this->getPaginatedQuery($this->query, $this->limit, $this->offset); - } - - // Apply scopes to the Eloquent\Builder instance. - $builder = $this->query->applyScopes(); - - $builder = $builder->addSelect( - $this->shouldSelect($columns) - ); - - $models = $builder->getModels(); - - // Hydrate the pivot models so we can load the via models - $this->hydratePivotRelation($models); - - if ($condenseModels) { - $models = $this->condenseModels($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); - } - - /** - * Condense the raw join query results into a set of unique models. - * - * Before doing this, we may optionally find any tertiary models that should be - * set as sub-relations on these models. - * @param array $models - * @return array - */ - protected function condenseModels(array $models) { - // Build dictionary of tertiary models, if `withTertiary` was called - $dictionary = NULL; - if ($this->tertiaryRelated) { - $dictionary = $this->buildTertiaryDictionary($models); - } - - // Remove duplicate models from collection - $models = $this->related->newCollection($models)->unique(); - - // If using withTertiary, use the dictionary to set the tertiary relation on each model. - if (!is_null($dictionary)) { - $this->matchTertiaryModels($dictionary, $models); - } - - return $models->all(); - } - - /** - * Build dictionary of related models keyed by the top-level "parent" id. - * If there is a tertiary query set as well, then also build a two-level dictionary - * that maps parent ids to arrays of related ids, which in turn map to arrays - * of tertiary models corresponding to each relationship. - * - * @param \Illuminate\Database\Eloquent\Collection $results - * @param string $parentKey - * @return array - */ - protected function buildDictionary(Collection $results, $parentKey = NULL) { - // First we will build a dictionary of child models keyed by the "parent key" (foreign key - // of the intermediate relation) so that we will easily and quickly match them to their - // parents without having a possibly slow inner loops for every models. - $dictionary = []; - - //Example nested dictionary: - //[ - // // User 1 - // '1' => [ - // // Permission 3 - // '3' => [ - // Role1, - // Role2 - // ], - // ... - // ], - // ... - //] - $nestedTertiaryDictionary = NULL; - $tertiaryModels = NULL; - - if ($this->tertiaryRelationName) { - // Get all tertiary models from the result set matching any of the parent models. - $tertiaryModels = $this->getTertiaryModels($results->all()); - } - - foreach ($results as $result) { - $parentKeyValue = $result->pivot->$parentKey; - - // Set the related model in the main dictionary. - // Note that this can end up adding duplicate models. It's cheaper to simply - // go back and remove the duplicates when we actually use the dictionary, - // rather than check for duplicates on each insert. - $dictionary[$parentKeyValue][] = $result; - - // If we're loading tertiary models, then set the keys in the nested dictionary as well. - if (!is_null($tertiaryModels)) { - $tertiaryKeyValue = $result->pivot->{$this->tertiaryKey}; - - if (!is_null($tertiaryKeyValue)) { - $tertiaryModel = clone $tertiaryModels[$tertiaryKeyValue]; - - // We also transfer the pivot relation at this point, since we have already coalesced - // any tertiary models into the nested dictionary. - $this->transferPivotsToTertiary($result, $tertiaryModel); - - $nestedTertiaryDictionary[$parentKeyValue][$result->getKey()][] = $tertiaryModel; - } - } - } - - return [$dictionary, $nestedTertiaryDictionary]; - } - - /** - * Build dictionary of tertiary models keyed by the corresponding related model keys. - * - * @param array $models - * @return array - */ - protected function buildTertiaryDictionary(array $models) { - $dictionary = []; - - // Find the related tertiary entities (e.g. tasks) for all related models (e.g. locations) - $tertiaryModels = $this->getTertiaryModels($models); - - // Now for each related model (e.g. location), we will build out a dictionary of their tertiary models (e.g. tasks) - foreach ($models as $model) { - $tertiaryKeyValue = $model->pivot->{$this->tertiaryKey}; - - $tertiaryModel = clone $tertiaryModels[$tertiaryKeyValue]; - - $this->transferPivotsToTertiary($model, $tertiaryModel); - - $dictionary[$model->getKey()][] = $tertiaryModel; - } - - return $dictionary; - } - - protected function transferPivotsToTertiary($model, $tertiaryModel) { - $pivotAttributes = []; - foreach ($this->pivotColumns as $column) { - $pivotAttributes[$column] = $model->pivot->$column; - unset($model->pivot->$column); - } - // Copy the related key pivot as well, but don't unset on the related model - $pivotAttributes[$this->relatedKey] = $model->pivot->{$this->relatedKey}; - - // Set the tertiary key pivot as well - $pivotAttributes[$this->tertiaryKey] = $tertiaryModel->getKey(); - - $pivot = $this->newExistingPivot($pivotAttributes); - $tertiaryModel->setRelation('pivot', $pivot); - } - - /** - * Get the tertiary models for the relationship. - * - * @param array $models - * @return \Illuminate\Database\Eloquent\Collection - */ - protected function getTertiaryModels(array $models) { - $tertiaryClass = $this->tertiaryRelated; - - $keys = []; - foreach ($models as $model) { - $keys[] = $model->getRelation('pivot')->{$this->tertiaryKey}; - } - $keys = array_unique($keys); - - $query = $tertiaryClass->whereIn($tertiaryClass->getQualifiedKeyName(), $keys); - - // Add any additional constraints/eager loads to the tertiary query - $callback = $this->tertiaryCallback; - $callback($query); - - $tertiaryModels = $query - ->get() - ->keyBy($tertiaryClass->getKeyName()); - - return $tertiaryModels; - } - - /** - * Match a collection of child models into a collection of parent models using a dictionary. - * - * @param array $dictionary - * @param \Illuminate\Database\Eloquent\Collection $results - * @return void - */ - protected function matchTertiaryModels(array $dictionary, Collection $results) { - // Now go through and set the tertiary relation on each child model - foreach ($results as $model) { - if (isset($dictionary[$key = $model->getKey()])) { - $tertiaryModels = $dictionary[$key]; - - $model->setRelation( - $this->tertiaryRelationName, $this->tertiaryRelated->newCollection($tertiaryModels) - ); - } - } - } - - /** - * Unset tertiary pivots on a collection or array of models. - * - * @param \Illuminate\Database\Eloquent\Collection $models - * @return void - */ - protected function unsetTertiaryPivots(Collection $models) { - foreach ($models as $model) { - foreach ($this->pivotColumns as $column) { - unset($model->pivot->$column); - } - } - } -} +<?php
+/**
+ * UserFrosting (http://www.userfrosting.com)
+ *
+ * @link https://github.com/userfrosting/UserFrosting
+ * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License)
+ */
+
+namespace UserFrosting\Sprinkle\Core\Database\Relations\Concerns;
+
+use Illuminate\Database\Eloquent\Builder;
+use Illuminate\Database\Eloquent\Collection;
+use Illuminate\Database\Query\Expression;
+
+/**
+ * Enforce uniqueness for BelongsToManyUnique, MorphToManyUnique, and BelongsToManyThrough.
+ *
+ * @author Alex Weissman (https://alexanderweissman.com)
+ */
+trait Unique
+{
+ /**
+ * The related tertiary model instance.
+ *
+ * @var \Illuminate\Database\Eloquent\Model
+ */
+ protected $tertiaryRelated = NULL;
+
+ /**
+ * The name to use for the tertiary relation (e.g. 'roles_via', etc)
+ *
+ * @var string
+ */
+ protected $tertiaryRelationName = NULL;
+
+ /**
+ * The foreign key to the related tertiary model instance.
+ *
+ * @var string
+ */
+ protected $tertiaryKey;
+
+ /**
+ * A callback to apply to the tertiary query.
+ *
+ * @var callable|null
+ */
+ protected $tertiaryCallback = NULL;
+
+ /**
+ * The limit to apply on the number of related models retrieved.
+ *
+ * @var int|null
+ */
+ protected $limit = NULL;
+
+ /**
+ * The offset to apply on the related models retrieved.
+ *
+ * @var int|null
+ */
+ protected $offset = NULL;
+
+ /**
+ * Alias to set the "offset" value of the query.
+ *
+ * @param int $value
+ * @return $this
+ */
+ public function skip($value) {
+ return $this->offset($value);
+ }
+
+ /**
+ * Set the "offset" value of the query.
+ *
+ * Implement for 'unionOffset' as well? (By checking the value of $this->query->getQuery()->unions)
+ * @see \Illuminate\Database\Query\Builder
+ * @param int $value
+ * @return $this
+ */
+ public function offset($value) {
+ $this->offset = max(0, $value);
+
+ return $this;
+ }
+
+ /**
+ * Alias to set the "limit" value of the query.
+ *
+ * @param int $value
+ * @return $this
+ */
+ public function take($value) {
+ return $this->limit($value);
+ }
+
+ /**
+ * Set the "limit" value of the query.
+ *
+ * Implement for 'unionLimit' as well? (By checking the value of $this->query->getQuery()->unions)
+ * @see \Illuminate\Database\Query\Builder
+ * @param int $value
+ * @return $this
+ */
+ public function limit($value) {
+ if ($value >= 0) {
+ $this->limit = $value;
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set the limit on the number of intermediate models to load.
+ *
+ * @deprecated since 4.1.7
+ * @param int $value
+ * @return $this
+ */
+ public function withLimit($value) {
+ return $this->limit($value);
+ }
+
+ /**
+ * Set the offset when loading the intermediate models.
+ *
+ * @deprecated since 4.1.7
+ * @param int $value
+ * @return $this
+ */
+ public function withOffset($value) {
+ return $this->offset($value);
+ }
+
+ /**
+ * Add a query to load the nested tertiary models for this relationship.
+ *
+ * @param \Illuminate\Database\Eloquent\Model $tertiaryRelated
+ * @param string $tertiaryRelationName
+ * @param string $tertiaryKey
+ * @param callable $tertiaryCallback
+ * @return $this
+ */
+ public function withTertiary($tertiaryRelated, $tertiaryRelationName = NULL, $tertiaryKey = NULL, $tertiaryCallback = NULL) {
+ $this->tertiaryRelated = new $tertiaryRelated;
+
+ // Try to guess the tertiary related key from the tertiaryRelated model.
+ $this->tertiaryKey = $tertiaryKey ?: $this->tertiaryRelated->getForeignKey();
+
+ // Also add the tertiary key as a pivot
+ $this->withPivot($this->tertiaryKey);
+
+ $this->tertiaryRelationName = is_null($tertiaryRelationName) ? $this->tertiaryRelated->getTable() : $tertiaryRelationName;
+
+ $this->tertiaryCallback = is_null($tertiaryCallback)
+ ? function () {
+ //
+ }
+ : $tertiaryCallback;
+
+ return $this;
+ }
+
+ /**
+ * Return the count of child models for this relationship.
+ *
+ * @see http://stackoverflow.com/a/29728129/2970321
+ * @return int
+ */
+ public function count() {
+ $constrainedBuilder = clone $this->query;
+
+ $constrainedBuilder = $constrainedBuilder->distinct();
+
+ return $constrainedBuilder->count($this->relatedKey);
+ }
+
+ /**
+ * Add the constraints for a relationship count query.
+ *
+ * @see \Illuminate\Database\Eloquent\Relations\Relation
+ * @param \Illuminate\Database\Eloquent\Builder $query
+ * @param \Illuminate\Database\Eloquent\Builder $parentQuery
+ * @return \Illuminate\Database\Eloquent\Builder
+ */
+ public function getRelationExistenceCountQuery(Builder $query, Builder $parentQuery) {
+ return $this->getRelationExistenceQuery(
+ $query, $parentQuery, new Expression("count(distinct {$this->relatedKey})")
+ );
+ }
+
+ /**
+ * 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) {
+ // Build dictionary of parent (e.g. user) to related (e.g. permission) models
+ list($dictionary, $nestedTertiaryDictionary) = $this->buildDictionary($results, $this->foreignKey);
+
+ // 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()])) {
+ /** @var array */
+ $items = $dictionary[$key];
+
+ // Eliminate any duplicates
+ $items = $this->related->newCollection($items)->unique();
+
+ // If set, match up the tertiary models to the models in the related collection
+ if (!is_null($nestedTertiaryDictionary)) {
+ $this->matchTertiaryModels($nestedTertiaryDictionary[$key], $items);
+ }
+
+ $model->setRelation(
+ $relation, $items
+ );
+ }
+ }
+
+ return $models;
+ }
+
+ /**
+ * Execute the query as a "select" statement, getting all requested models
+ * and matching up any tertiary models.
+ *
+ * @param array $columns
+ * @return \Illuminate\Database\Eloquent\Collection
+ */
+ public function get($columns = ['*']) {
+ // Get models and condense the result set
+ $models = $this->getModels($columns, TRUE);
+
+ // Remove the tertiary pivot key from the condensed models
+ $this->unsetTertiaryPivots($models);
+
+ return $models;
+ }
+
+ /**
+ * If we are applying either a limit or offset, we'll first determine a limited/offset list of model ids
+ * to select from in the final query.
+ *
+ * @param \Illuminate\Database\Eloquent\Builder $query
+ * @param int $limit
+ * @param int $offset
+ * @return \Illuminate\Database\Eloquent\Builder
+ */
+ public function getPaginatedQuery(Builder $query, $limit = NULL, $offset = NULL) {
+ $constrainedBuilder = clone $query;
+
+ // Since some unique models will be represented by more than one row in the database,
+ // we cannot apply limit/offset directly to the query. If we did that, we'd miss
+ // some of the records that are to be coalesced into the final set of models.
+ // Instead, we perform an additional query with grouping and limit/offset to determine
+ // the desired set of unique model _ids_, and then constrain our final query
+ // to these models with a whereIn clause.
+ $relatedKeyName = $this->related->getQualifiedKeyName();
+
+ // Apply an additional scope to override any selected columns in other global scopes
+ $uniqueIdScope = function ($subQuery) use ($relatedKeyName) {
+ $subQuery->select($relatedKeyName)
+ ->groupBy($relatedKeyName);
+ };
+
+ $identifier = spl_object_hash($uniqueIdScope);
+
+ $constrainedBuilder->withGlobalScope($identifier, $uniqueIdScope);
+
+ if ($limit) {
+ $constrainedBuilder->limit($limit);
+ }
+
+ if ($offset) {
+ $constrainedBuilder->offset($offset);
+ }
+
+ $primaryKeyName = $this->getParent()->getKeyName();
+ $modelIds = $constrainedBuilder->get()->pluck($primaryKeyName)->toArray();
+
+ // Modify the unconstrained query to limit to these models
+ return $query->whereIn($relatedKeyName, $modelIds);
+ }
+
+ /**
+ * Get the full join results for this query, overriding the default getEager() method.
+ * The default getEager() method would normally just call get() on this relationship.
+ * This is not what we want here though, because our get() method removes records before
+ * `match` has a chance to build out the substructures.
+ *
+ * @return \Illuminate\Database\Eloquent\Collection
+ */
+ public function getEager() {
+ return $this->getModels(['*'], FALSE);
+ }
+
+ /**
+ * Get the hydrated models and eager load their relations, optionally
+ * condensing the set of models before performing the eager loads.
+ *
+ * @param array $columns
+ * @param bool $condenseModels
+ * @return \Illuminate\Database\Eloquent\Collection
+ */
+ public function getModels($columns = ['*'], $condenseModels = TRUE) {
+ // 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;
+
+ // Add any necessary pagination on the related models
+ if ($this->limit || $this->offset) {
+ $this->getPaginatedQuery($this->query, $this->limit, $this->offset);
+ }
+
+ // Apply scopes to the Eloquent\Builder instance.
+ $builder = $this->query->applyScopes();
+
+ $builder = $builder->addSelect(
+ $this->shouldSelect($columns)
+ );
+
+ $models = $builder->getModels();
+
+ // Hydrate the pivot models so we can load the via models
+ $this->hydratePivotRelation($models);
+
+ if ($condenseModels) {
+ $models = $this->condenseModels($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);
+ }
+
+ /**
+ * Condense the raw join query results into a set of unique models.
+ *
+ * Before doing this, we may optionally find any tertiary models that should be
+ * set as sub-relations on these models.
+ * @param array $models
+ * @return array
+ */
+ protected function condenseModels(array $models) {
+ // Build dictionary of tertiary models, if `withTertiary` was called
+ $dictionary = NULL;
+ if ($this->tertiaryRelated) {
+ $dictionary = $this->buildTertiaryDictionary($models);
+ }
+
+ // Remove duplicate models from collection
+ $models = $this->related->newCollection($models)->unique();
+
+ // If using withTertiary, use the dictionary to set the tertiary relation on each model.
+ if (!is_null($dictionary)) {
+ $this->matchTertiaryModels($dictionary, $models);
+ }
+
+ return $models->all();
+ }
+
+ /**
+ * Build dictionary of related models keyed by the top-level "parent" id.
+ * If there is a tertiary query set as well, then also build a two-level dictionary
+ * that maps parent ids to arrays of related ids, which in turn map to arrays
+ * of tertiary models corresponding to each relationship.
+ *
+ * @param \Illuminate\Database\Eloquent\Collection $results
+ * @param string $parentKey
+ * @return array
+ */
+ protected function buildDictionary(Collection $results, $parentKey = NULL) {
+ // First we will build a dictionary of child models keyed by the "parent key" (foreign key
+ // of the intermediate relation) so that we will easily and quickly match them to their
+ // parents without having a possibly slow inner loops for every models.
+ $dictionary = [];
+
+ //Example nested dictionary:
+ //[
+ // // User 1
+ // '1' => [
+ // // Permission 3
+ // '3' => [
+ // Role1,
+ // Role2
+ // ],
+ // ...
+ // ],
+ // ...
+ //]
+ $nestedTertiaryDictionary = NULL;
+ $tertiaryModels = NULL;
+
+ if ($this->tertiaryRelationName) {
+ // Get all tertiary models from the result set matching any of the parent models.
+ $tertiaryModels = $this->getTertiaryModels($results->all());
+ }
+
+ foreach ($results as $result) {
+ $parentKeyValue = $result->pivot->$parentKey;
+
+ // Set the related model in the main dictionary.
+ // Note that this can end up adding duplicate models. It's cheaper to simply
+ // go back and remove the duplicates when we actually use the dictionary,
+ // rather than check for duplicates on each insert.
+ $dictionary[$parentKeyValue][] = $result;
+
+ // If we're loading tertiary models, then set the keys in the nested dictionary as well.
+ if (!is_null($tertiaryModels)) {
+ $tertiaryKeyValue = $result->pivot->{$this->tertiaryKey};
+
+ if (!is_null($tertiaryKeyValue)) {
+ $tertiaryModel = clone $tertiaryModels[$tertiaryKeyValue];
+
+ // We also transfer the pivot relation at this point, since we have already coalesced
+ // any tertiary models into the nested dictionary.
+ $this->transferPivotsToTertiary($result, $tertiaryModel);
+
+ $nestedTertiaryDictionary[$parentKeyValue][$result->getKey()][] = $tertiaryModel;
+ }
+ }
+ }
+
+ return [$dictionary, $nestedTertiaryDictionary];
+ }
+
+ /**
+ * Build dictionary of tertiary models keyed by the corresponding related model keys.
+ *
+ * @param array $models
+ * @return array
+ */
+ protected function buildTertiaryDictionary(array $models) {
+ $dictionary = [];
+
+ // Find the related tertiary entities (e.g. tasks) for all related models (e.g. locations)
+ $tertiaryModels = $this->getTertiaryModels($models);
+
+ // Now for each related model (e.g. location), we will build out a dictionary of their tertiary models (e.g. tasks)
+ foreach ($models as $model) {
+ $tertiaryKeyValue = $model->pivot->{$this->tertiaryKey};
+
+ $tertiaryModel = clone $tertiaryModels[$tertiaryKeyValue];
+
+ $this->transferPivotsToTertiary($model, $tertiaryModel);
+
+ $dictionary[$model->getKey()][] = $tertiaryModel;
+ }
+
+ return $dictionary;
+ }
+
+ protected function transferPivotsToTertiary($model, $tertiaryModel) {
+ $pivotAttributes = [];
+ foreach ($this->pivotColumns as $column) {
+ $pivotAttributes[$column] = $model->pivot->$column;
+ unset($model->pivot->$column);
+ }
+ // Copy the related key pivot as well, but don't unset on the related model
+ $pivotAttributes[$this->relatedKey] = $model->pivot->{$this->relatedKey};
+
+ // Set the tertiary key pivot as well
+ $pivotAttributes[$this->tertiaryKey] = $tertiaryModel->getKey();
+
+ $pivot = $this->newExistingPivot($pivotAttributes);
+ $tertiaryModel->setRelation('pivot', $pivot);
+ }
+
+ /**
+ * Get the tertiary models for the relationship.
+ *
+ * @param array $models
+ * @return \Illuminate\Database\Eloquent\Collection
+ */
+ protected function getTertiaryModels(array $models) {
+ $tertiaryClass = $this->tertiaryRelated;
+
+ $keys = [];
+ foreach ($models as $model) {
+ $keys[] = $model->getRelation('pivot')->{$this->tertiaryKey};
+ }
+ $keys = array_unique($keys);
+
+ $query = $tertiaryClass->whereIn($tertiaryClass->getQualifiedKeyName(), $keys);
+
+ // Add any additional constraints/eager loads to the tertiary query
+ $callback = $this->tertiaryCallback;
+ $callback($query);
+
+ $tertiaryModels = $query
+ ->get()
+ ->keyBy($tertiaryClass->getKeyName());
+
+ return $tertiaryModels;
+ }
+
+ /**
+ * Match a collection of child models into a collection of parent models using a dictionary.
+ *
+ * @param array $dictionary
+ * @param \Illuminate\Database\Eloquent\Collection $results
+ * @return void
+ */
+ protected function matchTertiaryModels(array $dictionary, Collection $results) {
+ // Now go through and set the tertiary relation on each child model
+ foreach ($results as $model) {
+ if (isset($dictionary[$key = $model->getKey()])) {
+ $tertiaryModels = $dictionary[$key];
+
+ $model->setRelation(
+ $this->tertiaryRelationName, $this->tertiaryRelated->newCollection($tertiaryModels)
+ );
+ }
+ }
+ }
+
+ /**
+ * Unset tertiary pivots on a collection or array of models.
+ *
+ * @param \Illuminate\Database\Eloquent\Collection $models
+ * @return void
+ */
+ protected function unsetTertiaryPivots(Collection $models) {
+ foreach ($models as $model) {
+ foreach ($this->pivotColumns as $column) {
+ unset($model->pivot->$column);
+ }
+ }
+ }
+}
diff --git a/main/app/sprinkles/core/src/Database/Relations/HasManySyncable.php b/main/app/sprinkles/core/src/Database/Relations/HasManySyncable.php index 9d85b1f..d09e25d 100644 --- a/main/app/sprinkles/core/src/Database/Relations/HasManySyncable.php +++ b/main/app/sprinkles/core/src/Database/Relations/HasManySyncable.php @@ -1,23 +1,23 @@ -<?php -/** - * UserFrosting (http://www.userfrosting.com) - * - * @link https://github.com/userfrosting/UserFrosting - * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License) - */ - -namespace UserFrosting\Sprinkle\Core\Database\Relations; - -use Illuminate\Database\Eloquent\Relations\HasMany; -use UserFrosting\Sprinkle\Core\Database\Relations\Concerns\Syncable; - -/** - * A HasMany relationship that supports a `sync` method. - * - * @author Alex Weissman (https://alexanderweissman.com) - * @link https://github.com/laravel/framework/blob/5.4/src/Illuminate/Database/Eloquent/Relations/HasMany.php - */ -class HasManySyncable extends HasMany -{ - use Syncable; -} +<?php
+/**
+ * UserFrosting (http://www.userfrosting.com)
+ *
+ * @link https://github.com/userfrosting/UserFrosting
+ * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License)
+ */
+
+namespace UserFrosting\Sprinkle\Core\Database\Relations;
+
+use Illuminate\Database\Eloquent\Relations\HasMany;
+use UserFrosting\Sprinkle\Core\Database\Relations\Concerns\Syncable;
+
+/**
+ * A HasMany relationship that supports a `sync` method.
+ *
+ * @author Alex Weissman (https://alexanderweissman.com)
+ * @link https://github.com/laravel/framework/blob/5.4/src/Illuminate/Database/Eloquent/Relations/HasMany.php
+ */
+class HasManySyncable extends HasMany
+{
+ use Syncable;
+}
diff --git a/main/app/sprinkles/core/src/Database/Relations/MorphManySyncable.php b/main/app/sprinkles/core/src/Database/Relations/MorphManySyncable.php index bb90257..26938f6 100644 --- a/main/app/sprinkles/core/src/Database/Relations/MorphManySyncable.php +++ b/main/app/sprinkles/core/src/Database/Relations/MorphManySyncable.php @@ -1,23 +1,23 @@ -<?php -/** - * UserFrosting (http://www.userfrosting.com) - * - * @link https://github.com/userfrosting/UserFrosting - * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License) - */ - -namespace UserFrosting\Sprinkle\Core\Database\Relations; - -use Illuminate\Database\Eloquent\Relations\MorphMany; -use UserFrosting\Sprinkle\Core\Database\Relations\Concerns\Syncable; - -/** - * A MorphMany relationship that constrains on the value of an additional foreign key in the pivot table. - * - * @author Alex Weissman (https://alexanderweissman.com) - * @link https://github.com/laravel/framework/blob/5.4/src/Illuminate/Database/Eloquent/Relations/MorphMany.php - */ -class MorphManySyncable extends MorphMany -{ - use Syncable; -} +<?php
+/**
+ * UserFrosting (http://www.userfrosting.com)
+ *
+ * @link https://github.com/userfrosting/UserFrosting
+ * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License)
+ */
+
+namespace UserFrosting\Sprinkle\Core\Database\Relations;
+
+use Illuminate\Database\Eloquent\Relations\MorphMany;
+use UserFrosting\Sprinkle\Core\Database\Relations\Concerns\Syncable;
+
+/**
+ * A MorphMany relationship that constrains on the value of an additional foreign key in the pivot table.
+ *
+ * @author Alex Weissman (https://alexanderweissman.com)
+ * @link https://github.com/laravel/framework/blob/5.4/src/Illuminate/Database/Eloquent/Relations/MorphMany.php
+ */
+class MorphManySyncable extends MorphMany
+{
+ use Syncable;
+}
diff --git a/main/app/sprinkles/core/src/Database/Relations/MorphToManyUnique.php b/main/app/sprinkles/core/src/Database/Relations/MorphToManyUnique.php index 0920d1c..7739711 100644 --- a/main/app/sprinkles/core/src/Database/Relations/MorphToManyUnique.php +++ b/main/app/sprinkles/core/src/Database/Relations/MorphToManyUnique.php @@ -1,23 +1,23 @@ -<?php -/** - * UserFrosting (http://www.userfrosting.com) - * - * @link https://github.com/userfrosting/UserFrosting - * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License) - */ - -namespace UserFrosting\Sprinkle\Core\Database\Relations; - -use Illuminate\Database\Eloquent\Relations\MorphToMany; -use UserFrosting\Sprinkle\Core\Database\Relations\Concerns\Unique; - -/** - * A MorphToMany relationship that reduces the related members to a unique (by primary key) set. - * - * @author Alex Weissman (https://alexanderweissman.com) - * @link https://github.com/laravel/framework/blob/5.4/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php - */ -class MorphToManyUnique extends MorphToMany -{ - use Unique; -} +<?php
+/**
+ * UserFrosting (http://www.userfrosting.com)
+ *
+ * @link https://github.com/userfrosting/UserFrosting
+ * @license https://github.com/userfrosting/UserFrosting/blob/master/licenses/UserFrosting.md (MIT License)
+ */
+
+namespace UserFrosting\Sprinkle\Core\Database\Relations;
+
+use Illuminate\Database\Eloquent\Relations\MorphToMany;
+use UserFrosting\Sprinkle\Core\Database\Relations\Concerns\Unique;
+
+/**
+ * A MorphToMany relationship that reduces the related members to a unique (by primary key) set.
+ *
+ * @author Alex Weissman (https://alexanderweissman.com)
+ * @link https://github.com/laravel/framework/blob/5.4/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php
+ */
+class MorphToManyUnique extends MorphToMany
+{
+ use Unique;
+}
|