-
Notifications
You must be signed in to change notification settings - Fork 376
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
04f1996
commit 0271fcd
Showing
6 changed files
with
297 additions
and
90 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
<?php | ||
|
||
namespace Lunar\Base; | ||
|
||
use Illuminate\Database\Eloquent\Builder; | ||
use Illuminate\Database\Eloquent\Model; | ||
use Illuminate\Database\Schema\Blueprint; | ||
use Illuminate\Support\Str; | ||
|
||
class PositionManifest implements PositionManifestInterface | ||
{ | ||
/** | ||
* {@inheritDoc} | ||
*/ | ||
public function saving(Model $model): void | ||
{ | ||
if ( | ||
$model->isDirty($this->constraints($model)) | ||
|| !(intval($model->position) > 0) | ||
|| $model->query() | ||
->where($model->getKeyName(), '!=', $model->getKey()) | ||
->wherePosition($model->position) | ||
->wherePositionUniqueConstraints($model->getAttributes()) | ||
->exists() | ||
) { | ||
$model->position = $model->query() | ||
->where($model->getKeyName(), '!=', $model->getKey()) | ||
->wherePositionUniqueConstraints($model->getAttributes()) | ||
->max('position') + 1; | ||
} | ||
} | ||
|
||
/** | ||
* | ||
* {@inheritDoc} | ||
*/ | ||
public function constraints(Model $model): array | ||
{ | ||
return array_merge( | ||
!property_exists($model, 'positionUniqueConstraints') | ||
|| !is_array($model->positionUniqueConstraints) | ||
? [] : $model->positionUniqueConstraints, | ||
['position'] | ||
); | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
public function query(Builder $query, int $position, array $constraints = []): void | ||
{ | ||
$query | ||
->wherePosition($position) | ||
->wherePositionUniqueConstraints($constraints); | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
public function queryPosition(Builder $query, int $position): void | ||
{ | ||
$query->where('position', $position); | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
public function queryUniqueConstraints(Builder $query, array $constraints): void | ||
{ | ||
$constraints = collect($constraints); | ||
$modelConstraints = collect($this->constraints($query->getModel()))->reject('position'); | ||
|
||
if (count($modelConstraints) && !$constraints->hasAny($modelConstraints->toArray())) { | ||
throw new \InvalidArgumentException( | ||
sprintf( | ||
'Position constraints "%s" for "%s" not defined!', | ||
$modelConstraints->diff($constraints)->join('", "', '" and "'), | ||
get_class($this) | ||
) | ||
); | ||
} | ||
|
||
$modelConstraints->each( | ||
function ($attribute) use ($query, $constraints) { | ||
if (method_exists($query, Str::camel('scope_' . $attribute))) { | ||
$method = Str::camel($attribute); | ||
} else { | ||
$method = Str::camel('where_' . $attribute); | ||
} | ||
$query->{$method}($constraints[$attribute]); | ||
} | ||
); | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
public static function registerBlueprintMacros(): void | ||
{ | ||
/** | ||
* Add a `position` column to the table and define a unique positions index | ||
* with the given constraints | ||
* | ||
* The constraints can defined as array or assigned from the corsponding | ||
* model property `positionUniqueConstraints` if model object or | ||
* model classname is given. | ||
* | ||
* @param array|string|\Illuminate\Database\Eloquent\Model $constraints | ||
* @return void | ||
*/ | ||
Blueprint::macro('position', function (array|string|Model $constraints = []) { | ||
/** @var Blueprint $this */ | ||
if (is_string($constraints)) { | ||
$constraints = app($constraints); | ||
} | ||
if (!is_array($constraints)) { | ||
$constraints = PositionManifest::constraints($constraints); | ||
} else { | ||
$constraints = collect($constraints) | ||
->push('position') | ||
->unique() | ||
->all(); | ||
} | ||
$this->unsignedBigInteger('position'); | ||
$this->unique($constraints, $this->getIndexName('unique', ['position'])); | ||
}); | ||
|
||
/** | ||
* Remove the `position` column to the table and drop the unique positions index | ||
* | ||
* @param array|string|\Illuminate\Database\Eloquent\Model $constraints | ||
* @return void | ||
*/ | ||
Blueprint::macro('dropPosition', function () { | ||
/** @var Blueprint $this */ | ||
$this->dropUnique($this->getIndexName('unique', ['position'])); | ||
$this->dropColumn('position'); | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
<?php | ||
namespace Lunar\Base; | ||
|
||
use Illuminate\Database\Eloquent\Builder; | ||
use Illuminate\Database\Eloquent\Model; | ||
|
||
interface PositionManifestInterface | ||
{ | ||
/** | ||
* Before model gets saved, check if relevant model attributes has changed | ||
* and position value is greate than zero and unique and if not, set position | ||
* to next greatest value | ||
* | ||
* @param \Illuminate\Database\Eloquent\Model $model | ||
* @return void | ||
*/ | ||
public function saving(Model $model): void; | ||
|
||
/** | ||
* Return the defined constraints from model's positionUniqueConstraints | ||
* property array | ||
* | ||
* @param \Illuminate\Database\Eloquent\Model $model | ||
* @return array | ||
*/ | ||
public function constraints(Model $model): array; | ||
|
||
/** | ||
* Scope the query to only include given position and constraints | ||
* | ||
* @param \Illuminate\Database\Eloquent\Builder $query | ||
* @param int $position | ||
* @param array $constraints | ||
* @return void | ||
*/ | ||
public function query(Builder $query, int $position, array $constraints = []): void; | ||
|
||
/** | ||
* Scope the query to only include given position | ||
* | ||
* @param \Illuminate\Database\Eloquent\Builder $query | ||
* @param int $position | ||
* @return void | ||
*/ | ||
public function queryPosition(Builder $query, int $position): void; | ||
|
||
/** | ||
* Scope the query to only include given constraints | ||
* | ||
* @param \Illuminate\Database\Eloquent\Builder $query | ||
* @param array|\Illuminate\Support\Collection $constraints | ||
* @return void | ||
*/ | ||
public function queryUniqueConstraints(Builder $query, array $constraints): void; | ||
|
||
/** | ||
* Regster blueprint macros to allow ease | ||
* ddefinition and removement from `position` columne | ||
* @return void | ||
*/ | ||
public static function registerBlueprintMacros(): void; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.