Laravel:正确覆盖 SoftDeletes 特性
Laravel: Override SoftDeletes trait properly
我想创建一个使用 SoftDeletes
命名为 SoftDeletesWithStatus
的特征,它也会更新状态列。我的问题是我想在 SoftDeletes
的函数中间实现我的代码,如下所示:
protected function runSoftDelete() {
$query = $this->newQueryWithoutScopes()->where($this->getKeyName(), $this->getKey());
$time = $this->freshTimestamp();
$columns = [$this->getDeletedAtColumn() => $this->fromDateTime($time)];
//I want to implement my code here
$this->{$this->getDeletedAtColumn()} = $time;
if ($this->timestamps && ! is_null($this->getUpdatedAtColumn())) {
$this->{$this->getUpdatedAtColumn()} = $time;
$columns[$this->getUpdatedAtColumn()] = $this->fromDateTime($time);
}
$query->update($columns);
}
public function restore() {
if ($this->fireModelEvent('restoring') === false) {
return false;
}
$this->{$this->getDeletedAtColumn()} = null;
//I want to implement my code here
$this->exists = true;
$result = $this->save();
$this->fireModelEvent('restored', false);
return $result;
}
将代码复制粘贴到我的 SoftDeletesWithStatus
特征中并在其中实现我的代码是否是更好的解决方案?
感谢您的帮助。
我最接近的解决方案是:
<?php
namespace App;
use Illuminate\Database\Eloquent\SoftDeletes;
//Status 1 = Activated; Status 99 = Deleted
trait SoftDeletesWithStatus {
use SoftDeletes {
SoftDeletes::runSoftDelete as parentRunSoftDelete;
SoftDeletes::restore as parentRestore;
}
public function getStatusColumn() {
return defined('static::STATUS') ? static::STATUS : 'status';
}
public function runSoftDelete() {
$this->parentRunSoftDelete();
$query = $this->newQueryWithoutScopes()->where($this->getKeyName(), $this->getKey());
$columns = [$this->getStatusColumn() => 99];
$this->{$this->getDeletedAtColumn()} = 99;
$query->update($columns);
}
public function restore() {
$result = $this->parentRestore();
$this->{$this->getStatusColumn()} = 1;
$this->save();
return $result;
}
}
然后我只是在我想要的模型中使用我的特征:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use App\SoftDeletesWithStatus;
class MyModel extends Model {
use SoftDeletesWithStatus;
}
JacupoStanchis 我认为解决方案不完整。
新特征的方法 runSoftDelete
和 restore
没有处理关系。
假设您有一个简单的关系,例如:
Author 1-n Book
工作示例:
$Author->delete();
$Author->restore();
无效示例:
$Book->author()->delete();
$Book->author()->restore();
感谢 Xdebug,我可以找到 "not working example".
的解决方案
顺便说一句。在我的例子中,需要一个字符串列,这样我就可以结合使用唯一约束和删除状态。所以方法不同
app/Traits/SoftDeletes.php
<?php
namespace App\Traits;
use App\Overrides\Eloquent\SoftDeletingScope;
trait SoftDeletes
{
use \Illuminate\Database\Eloquent\SoftDeletes;
/**
* Boot the soft deleting trait for a model.
*
* @return void
*/
public static function bootSoftDeletes()
{
static::addGlobalScope(new SoftDeletingScope);
}
/**
* Perform the actual delete query on this model instance.
*
* @return void
*/
protected function runSoftDelete()
{
$query = $this->newModelQuery()->where($this->getKeyName(), $this->getKey());
$time = $this->freshTimestamp();
$columns = [
$this->getDeletedAtColumn() => $this->fromDateTime($time),
$this->getDeletedHashColumn() => uniqid(),
];
$this->{$this->getDeletedAtColumn()} = $time;
if ($this->timestamps && ! is_null($this->getUpdatedAtColumn())) {
$this->{$this->getUpdatedAtColumn()} = $time;
$columns[$this->getUpdatedAtColumn()] = $this->fromDateTime($time);
}
$query->update($columns);
}
/**
* Restore a soft-deleted model instance.
*
* @return bool|null
*/
public function restore()
{
// If the restoring event does not return false, we will proceed with this
// restore operation. Otherwise, we bail out so the developer will stop
// the restore totally. We will clear the deleted timestamp and save.
if ($this->fireModelEvent('restoring') === false) {
return false;
}
$this->{$this->getDeletedAtColumn()} = null;
$this->{$this->getDeletedHashColumn()} = '';
// Once we have saved the model, we will fire the "restored" event so this
// developer will do anything they need to after a restore operation is
// totally finished. Then we will return the result of the save call.
$this->exists = true;
$result = $this->save();
$this->fireModelEvent('restored', false);
return $result;
}
/**
* Get the name of the "deleted at" column.
*
* @return string
*/
public function getDeletedHashColumn()
{
return defined('static::DELETED_HASH') ? static::DELETED_HASH : 'deleted_hash';
}
}
app/Overrides/Eloquent/SoftDeletingScope.php
<?php
namespace App\Overrides\Eloquent;
use Illuminate\Database\Eloquent;
class SoftDeletingScope extends Eloquent\SoftDeletingScope
{
/**
* Extend the query builder with the needed functions.
*
* @param \Illuminate\Database\Eloquent\Builder $builder
* @return void
*/
public function extend(Eloquent\Builder $builder)
{
foreach ($this->extensions as $extension) {
$this->{"add{$extension}"}($builder);
}
$builder->onDelete(function (Eloquent\Builder $builder) {
$deletedAtColumn = $this->getDeletedAtColumn($builder);
$deletedHashColumn = $builder->getModel()->getDeletedHashColumn();
return $builder->update([
$deletedAtColumn => $builder->getModel()->freshTimestampString(),
$deletedHashColumn => uniqid(),
]);
});
}
/**
* Add the restore extension to the builder.
*
* @param \Illuminate\Database\Eloquent\Builder $builder
* @return void
*/
protected function addRestore(Eloquent\Builder $builder)
{
$builder->macro('restore', function (Eloquent\Builder $builder) {
$builder->withTrashed();
return $builder->update([
$builder->getModel()->getDeletedAtColumn() => null,
$builder->getModel()->getDeletedHashColumn() => '',
]);
});
}
}
我将 bootSoftDeletes
方法添加到新 Trait 中,该方法将自定义 SoftDeletingScope
添加到全局范围。
我想创建一个使用 SoftDeletes
命名为 SoftDeletesWithStatus
的特征,它也会更新状态列。我的问题是我想在 SoftDeletes
的函数中间实现我的代码,如下所示:
protected function runSoftDelete() {
$query = $this->newQueryWithoutScopes()->where($this->getKeyName(), $this->getKey());
$time = $this->freshTimestamp();
$columns = [$this->getDeletedAtColumn() => $this->fromDateTime($time)];
//I want to implement my code here
$this->{$this->getDeletedAtColumn()} = $time;
if ($this->timestamps && ! is_null($this->getUpdatedAtColumn())) {
$this->{$this->getUpdatedAtColumn()} = $time;
$columns[$this->getUpdatedAtColumn()] = $this->fromDateTime($time);
}
$query->update($columns);
}
public function restore() {
if ($this->fireModelEvent('restoring') === false) {
return false;
}
$this->{$this->getDeletedAtColumn()} = null;
//I want to implement my code here
$this->exists = true;
$result = $this->save();
$this->fireModelEvent('restored', false);
return $result;
}
将代码复制粘贴到我的 SoftDeletesWithStatus
特征中并在其中实现我的代码是否是更好的解决方案?
感谢您的帮助。
我最接近的解决方案是:
<?php
namespace App;
use Illuminate\Database\Eloquent\SoftDeletes;
//Status 1 = Activated; Status 99 = Deleted
trait SoftDeletesWithStatus {
use SoftDeletes {
SoftDeletes::runSoftDelete as parentRunSoftDelete;
SoftDeletes::restore as parentRestore;
}
public function getStatusColumn() {
return defined('static::STATUS') ? static::STATUS : 'status';
}
public function runSoftDelete() {
$this->parentRunSoftDelete();
$query = $this->newQueryWithoutScopes()->where($this->getKeyName(), $this->getKey());
$columns = [$this->getStatusColumn() => 99];
$this->{$this->getDeletedAtColumn()} = 99;
$query->update($columns);
}
public function restore() {
$result = $this->parentRestore();
$this->{$this->getStatusColumn()} = 1;
$this->save();
return $result;
}
}
然后我只是在我想要的模型中使用我的特征:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use App\SoftDeletesWithStatus;
class MyModel extends Model {
use SoftDeletesWithStatus;
}
JacupoStanchis 我认为解决方案不完整。
新特征的方法 runSoftDelete
和 restore
没有处理关系。
假设您有一个简单的关系,例如:
Author 1-n Book
工作示例:
$Author->delete();
$Author->restore();
无效示例:
$Book->author()->delete();
$Book->author()->restore();
感谢 Xdebug,我可以找到 "not working example".
的解决方案
顺便说一句。在我的例子中,需要一个字符串列,这样我就可以结合使用唯一约束和删除状态。所以方法不同
app/Traits/SoftDeletes.php
<?php
namespace App\Traits;
use App\Overrides\Eloquent\SoftDeletingScope;
trait SoftDeletes
{
use \Illuminate\Database\Eloquent\SoftDeletes;
/**
* Boot the soft deleting trait for a model.
*
* @return void
*/
public static function bootSoftDeletes()
{
static::addGlobalScope(new SoftDeletingScope);
}
/**
* Perform the actual delete query on this model instance.
*
* @return void
*/
protected function runSoftDelete()
{
$query = $this->newModelQuery()->where($this->getKeyName(), $this->getKey());
$time = $this->freshTimestamp();
$columns = [
$this->getDeletedAtColumn() => $this->fromDateTime($time),
$this->getDeletedHashColumn() => uniqid(),
];
$this->{$this->getDeletedAtColumn()} = $time;
if ($this->timestamps && ! is_null($this->getUpdatedAtColumn())) {
$this->{$this->getUpdatedAtColumn()} = $time;
$columns[$this->getUpdatedAtColumn()] = $this->fromDateTime($time);
}
$query->update($columns);
}
/**
* Restore a soft-deleted model instance.
*
* @return bool|null
*/
public function restore()
{
// If the restoring event does not return false, we will proceed with this
// restore operation. Otherwise, we bail out so the developer will stop
// the restore totally. We will clear the deleted timestamp and save.
if ($this->fireModelEvent('restoring') === false) {
return false;
}
$this->{$this->getDeletedAtColumn()} = null;
$this->{$this->getDeletedHashColumn()} = '';
// Once we have saved the model, we will fire the "restored" event so this
// developer will do anything they need to after a restore operation is
// totally finished. Then we will return the result of the save call.
$this->exists = true;
$result = $this->save();
$this->fireModelEvent('restored', false);
return $result;
}
/**
* Get the name of the "deleted at" column.
*
* @return string
*/
public function getDeletedHashColumn()
{
return defined('static::DELETED_HASH') ? static::DELETED_HASH : 'deleted_hash';
}
}
app/Overrides/Eloquent/SoftDeletingScope.php
<?php
namespace App\Overrides\Eloquent;
use Illuminate\Database\Eloquent;
class SoftDeletingScope extends Eloquent\SoftDeletingScope
{
/**
* Extend the query builder with the needed functions.
*
* @param \Illuminate\Database\Eloquent\Builder $builder
* @return void
*/
public function extend(Eloquent\Builder $builder)
{
foreach ($this->extensions as $extension) {
$this->{"add{$extension}"}($builder);
}
$builder->onDelete(function (Eloquent\Builder $builder) {
$deletedAtColumn = $this->getDeletedAtColumn($builder);
$deletedHashColumn = $builder->getModel()->getDeletedHashColumn();
return $builder->update([
$deletedAtColumn => $builder->getModel()->freshTimestampString(),
$deletedHashColumn => uniqid(),
]);
});
}
/**
* Add the restore extension to the builder.
*
* @param \Illuminate\Database\Eloquent\Builder $builder
* @return void
*/
protected function addRestore(Eloquent\Builder $builder)
{
$builder->macro('restore', function (Eloquent\Builder $builder) {
$builder->withTrashed();
return $builder->update([
$builder->getModel()->getDeletedAtColumn() => null,
$builder->getModel()->getDeletedHashColumn() => '',
]);
});
}
}
我将 bootSoftDeletes
方法添加到新 Trait 中,该方法将自定义 SoftDeletingScope
添加到全局范围。