如何在 eloquent 的模型上创建条件? (Laravel 5.3)
How to create the conditions on the model of eloquent? (Laravel 5.3)
我在控制器上的删除方法是这样的:
<?php
public function deleteMessage($id, $seller_id, $buyer_id)
{
//if the seller delete
if($seller_id == auth()->user->id)
//const DELETED_AT = 'deleted_by_seller';
//if the buyer delete
else($buyer_id == auth()->user->id)
//const DELETED_AT = 'deleted_by_buyer';
$result = Message::destroy($id);
return $result;
}
我的模型是这样的:
<?php
namespace App\Models;
use Jenssegers\Mongodb\Eloquent\Model as Eloquent;
use Jenssegers\Mongodb\Eloquent\HybridRelations;
use Jenssegers\Mongodb\Eloquent\SoftDeletes;
class MessageThread extends Eloquent
{
use HybridRelations;
use SoftDeletes;
// const DELETED_AT = 'deleted_by_seller';
// const DELETED_AT = 'deleted_by_buyer';
protected $connection = 'mongodb';
protected $dates = ['deleted_by_seller', 'deleted_by_buyer'];
protected $fillable = ['subject', 'information', 'created_at', 'update_at'];
}
我想点赞:
如果卖家删除消息则:const DELETED_AT = 'deleted_by_seller';
如果买家删除消息则:const DELETED_AT = 'deleted_by_buyer';
我该怎么做?
更新:
the original article refers my personal blog
软删除特征
在laravel中,我们通过扩展Illuminate\Database\Eloquent\Model
定义了自己的模型。要软删除模型实例,我们应该在模型中使用 Illuminate\Database\Eloquent\SoftDeletes
特征。 runSoftDelete()
是 SoftDeletes
trait 中的关键函数,构建一个 sql 查询,获取用于标记记录是否已被删除的列,然后用当前时间戳更新该列。
protected function runSoftDelete()
{
$query = $this->newQueryWithoutScopes()->where($this->getKeyName(), $this->getKey());
$this->{$this->getDeletedAtColumn()} = $time = $this->freshTimestamp();
$query->update([$this->getDeletedAtColumn() => $this->fromDateTime($time)]);
}
Delete()的过程
当我们在模型上调用 delete()
函数时会发生什么?
由于我们自己的模型扩展了Illuminate\Database\Eloquent\Model
,我们看一下。这是 delete()
函数:
public function delete()
{
if (is_null($this->getKeyName())) {
throw new Exception('No primary key defined on model.');
}
if ($this->exists) {
if ($this->fireModelEvent('deleting') === false) {
return false;
}
// Here, we'll touch the owning models, verifying these timestamps get updated
// for the models. This will allow any caching to get broken on the parents
// by the timestamp. Then we will go ahead and delete the model instance.
$this->touchOwners();
$this->performDeleteOnModel();
$this->exists = false;
// Once the model has been deleted, we will fire off the deleted event so that
// the developers may hook into post-delete operations. We will then return
// a boolean true as the delete is presumably successful on the database.
$this->fireModelEvent('deleted', false);
return true;
}
}
代码清晰。它确保模型具有 primaryKey
并且实例首先存在于数据库中。然后调用performDeleteOnModel()
函数进行删除操作。一定要注意!
这里我们应该知道:
An inherited member from a base class is overridden by a member inserted by a Trait. The precedence order is that members from the current class override Trait methods, which in turn override inherited methods.
所以当 performDeleteOnModel()
调用时执行的确切函数是 SoftDeletes
特征中具有相同名称的函数,而不是 Model
class 中的函数。现在我们回到特征:
protected function performDeleteOnModel()
{
if ($this->forceDeleting) {
return $this->newQueryWithoutScopes()->where($this->getKeyName(), $this->getKey())->forceDelete();
}
return $this->runSoftDelete();
}
嗯,它调用runSoftDelete()
我们一开始就讲过。这是软检测的流程。
获取问题
提问者想在删除时使用不同的DELETED_AT
列。仅通过覆盖 getDeletedAtColumn()
来保持软删除机制的良好运行还有很多不足之处。为什么被删除的模型被软删除了,结果还在结果中?
当 Model
class 被构造时,它将通过调用它们的 boot[TraitName]
方法来引导特征。因此这里是 bootSoftDelete()
方法。
protected static function bootTraits()
{
foreach (class_uses_recursive(get_called_class()) as $trait) {
if (method_exists(get_called_class(), $method = 'boot'.class_basename($trait))) {
forward_static_call([get_called_class(), $method]);
}
}
}
现在让我们再次关注 SoftDeletes
特质。
public static function bootSoftDeletes()
{
static::addGlobalScope(new SoftDeletingScope);
}
这里的 trait 通过调用 static::addGlobalScope()
注册了一个 SoftDeletingScope
class 有一个 apply()
方法。位于Model
class 的方法将其存储到$globalScopes
数组中。
public static function addGlobalScope(ScopeInterface $scope)
{
static::$globalScopes[get_called_class()][get_class($scope)] = $scope;
}
在模型上建立查询时,会自动调用applyGlobalScopes()
方法,逐一访问$globalScopes
数组中的实例,并调用它们的apply()
方法。
public function applyGlobalScopes($builder)
{
foreach ($this->getGlobalScopes() as $scope) {
$scope->apply($builder, $this);
}
return $builder;
}
我们现在将揭开问题的面纱。在 SoftDeletingScope
class:
public function apply(Builder $builder, Model $model)
{
$builder->whereNull($model->getQualifiedDeletedAtColumn());
$this->extend($builder);
}
它将对 select 那些 DELETED_AT
列为空的记录的每个查询添加约束。而这就是SoftDeletes
的秘密。
动态DELETED_AT列
首先,我需要重申,我不推荐使用动态 DELETED_AT
列的这种行为。
为了解决提问者的动态DELETED_AT
栏目问题,你需要实现你自己的SoftDeletingScope
class这样的apply()
功能:
public function apply(Builder $builder, Model $model)
{
$builder->where(function ($query){
$query->where('DELETED_AT_COLUMN_1',null)->orWhere('DELETED_AT_COLUMN_2',null);
});
$this->extend($builder);
}
然后用它覆盖 bootSoftDeletes()
public static function bootSoftDeletes()
{
static::addGlobalScope(new YourOwnSoftDeletingScope);
}
原回答:
您无法在 运行 时间内更改 const
变量的值。所以需要手动给CREATED_AT
赋值
首先,我认为这不是您拥有的理想数据库结构。您应该有两列:deleted_by 和 deleted_at,而不是包括 deleted_by_seller 和 deleted_by_buyer,其中一列始终为 null。
如果您仍然想继续使用现有的数据库结构,正如@William 指出的那样,试试这个:
在您的模型 class 中,添加以下内容:
protected $deletedAtCol = "deleted_at";
/**
* Get the name of the "deleted at" column.
*
* @return string
*/
public function getDeletedAtColumn()
{
return $this->deletedAtCol;
}
/**
* Set the name of the "deleted at" column.
* @param string $colName
* @return string
*/
public function setDeletedAtColumn($colName)
{
$this->deletedAtCol = $colName;
}
然后在您的控制器中添加:
public function deleteMessage($id, $seller_id, $buyer_id)
{
$message = Message::findOrFail($id);
//if the seller delete
if($seller_id == auth()->user->id)
$message->setDeletedAtCol("deleted_by_seller");
//if the buyer delete
else($buyer_id == auth()->user->id)
$message->setDeletedAtCol("deleted_by_buyer");
return $message->delete();
}
我在控制器上的删除方法是这样的:
<?php
public function deleteMessage($id, $seller_id, $buyer_id)
{
//if the seller delete
if($seller_id == auth()->user->id)
//const DELETED_AT = 'deleted_by_seller';
//if the buyer delete
else($buyer_id == auth()->user->id)
//const DELETED_AT = 'deleted_by_buyer';
$result = Message::destroy($id);
return $result;
}
我的模型是这样的:
<?php
namespace App\Models;
use Jenssegers\Mongodb\Eloquent\Model as Eloquent;
use Jenssegers\Mongodb\Eloquent\HybridRelations;
use Jenssegers\Mongodb\Eloquent\SoftDeletes;
class MessageThread extends Eloquent
{
use HybridRelations;
use SoftDeletes;
// const DELETED_AT = 'deleted_by_seller';
// const DELETED_AT = 'deleted_by_buyer';
protected $connection = 'mongodb';
protected $dates = ['deleted_by_seller', 'deleted_by_buyer'];
protected $fillable = ['subject', 'information', 'created_at', 'update_at'];
}
我想点赞:
如果卖家删除消息则:const DELETED_AT = 'deleted_by_seller';
如果买家删除消息则:const DELETED_AT = 'deleted_by_buyer';
我该怎么做?
更新:
the original article refers my personal blog
软删除特征
在laravel中,我们通过扩展Illuminate\Database\Eloquent\Model
定义了自己的模型。要软删除模型实例,我们应该在模型中使用 Illuminate\Database\Eloquent\SoftDeletes
特征。 runSoftDelete()
是 SoftDeletes
trait 中的关键函数,构建一个 sql 查询,获取用于标记记录是否已被删除的列,然后用当前时间戳更新该列。
protected function runSoftDelete()
{
$query = $this->newQueryWithoutScopes()->where($this->getKeyName(), $this->getKey());
$this->{$this->getDeletedAtColumn()} = $time = $this->freshTimestamp();
$query->update([$this->getDeletedAtColumn() => $this->fromDateTime($time)]);
}
Delete()的过程
当我们在模型上调用 delete()
函数时会发生什么?
由于我们自己的模型扩展了Illuminate\Database\Eloquent\Model
,我们看一下。这是 delete()
函数:
public function delete()
{
if (is_null($this->getKeyName())) {
throw new Exception('No primary key defined on model.');
}
if ($this->exists) {
if ($this->fireModelEvent('deleting') === false) {
return false;
}
// Here, we'll touch the owning models, verifying these timestamps get updated
// for the models. This will allow any caching to get broken on the parents
// by the timestamp. Then we will go ahead and delete the model instance.
$this->touchOwners();
$this->performDeleteOnModel();
$this->exists = false;
// Once the model has been deleted, we will fire off the deleted event so that
// the developers may hook into post-delete operations. We will then return
// a boolean true as the delete is presumably successful on the database.
$this->fireModelEvent('deleted', false);
return true;
}
}
代码清晰。它确保模型具有 primaryKey
并且实例首先存在于数据库中。然后调用performDeleteOnModel()
函数进行删除操作。一定要注意!
这里我们应该知道:
An inherited member from a base class is overridden by a member inserted by a Trait. The precedence order is that members from the current class override Trait methods, which in turn override inherited methods.
所以当 performDeleteOnModel()
调用时执行的确切函数是 SoftDeletes
特征中具有相同名称的函数,而不是 Model
class 中的函数。现在我们回到特征:
protected function performDeleteOnModel()
{
if ($this->forceDeleting) {
return $this->newQueryWithoutScopes()->where($this->getKeyName(), $this->getKey())->forceDelete();
}
return $this->runSoftDelete();
}
嗯,它调用runSoftDelete()
我们一开始就讲过。这是软检测的流程。
获取问题
提问者想在删除时使用不同的DELETED_AT
列。仅通过覆盖 getDeletedAtColumn()
来保持软删除机制的良好运行还有很多不足之处。为什么被删除的模型被软删除了,结果还在结果中?
当 Model
class 被构造时,它将通过调用它们的 boot[TraitName]
方法来引导特征。因此这里是 bootSoftDelete()
方法。
protected static function bootTraits()
{
foreach (class_uses_recursive(get_called_class()) as $trait) {
if (method_exists(get_called_class(), $method = 'boot'.class_basename($trait))) {
forward_static_call([get_called_class(), $method]);
}
}
}
现在让我们再次关注 SoftDeletes
特质。
public static function bootSoftDeletes()
{
static::addGlobalScope(new SoftDeletingScope);
}
这里的 trait 通过调用 static::addGlobalScope()
注册了一个 SoftDeletingScope
class 有一个 apply()
方法。位于Model
class 的方法将其存储到$globalScopes
数组中。
public static function addGlobalScope(ScopeInterface $scope)
{
static::$globalScopes[get_called_class()][get_class($scope)] = $scope;
}
在模型上建立查询时,会自动调用applyGlobalScopes()
方法,逐一访问$globalScopes
数组中的实例,并调用它们的apply()
方法。
public function applyGlobalScopes($builder)
{
foreach ($this->getGlobalScopes() as $scope) {
$scope->apply($builder, $this);
}
return $builder;
}
我们现在将揭开问题的面纱。在 SoftDeletingScope
class:
public function apply(Builder $builder, Model $model)
{
$builder->whereNull($model->getQualifiedDeletedAtColumn());
$this->extend($builder);
}
它将对 select 那些 DELETED_AT
列为空的记录的每个查询添加约束。而这就是SoftDeletes
的秘密。
动态DELETED_AT列
首先,我需要重申,我不推荐使用动态 DELETED_AT
列的这种行为。
为了解决提问者的动态DELETED_AT
栏目问题,你需要实现你自己的SoftDeletingScope
class这样的apply()
功能:
public function apply(Builder $builder, Model $model)
{
$builder->where(function ($query){
$query->where('DELETED_AT_COLUMN_1',null)->orWhere('DELETED_AT_COLUMN_2',null);
});
$this->extend($builder);
}
然后用它覆盖 bootSoftDeletes()
public static function bootSoftDeletes()
{
static::addGlobalScope(new YourOwnSoftDeletingScope);
}
原回答:
您无法在 运行 时间内更改 const
变量的值。所以需要手动给CREATED_AT
赋值
首先,我认为这不是您拥有的理想数据库结构。您应该有两列:deleted_by 和 deleted_at,而不是包括 deleted_by_seller 和 deleted_by_buyer,其中一列始终为 null。
如果您仍然想继续使用现有的数据库结构,正如@William 指出的那样,试试这个:
在您的模型 class 中,添加以下内容:
protected $deletedAtCol = "deleted_at";
/**
* Get the name of the "deleted at" column.
*
* @return string
*/
public function getDeletedAtColumn()
{
return $this->deletedAtCol;
}
/**
* Set the name of the "deleted at" column.
* @param string $colName
* @return string
*/
public function setDeletedAtColumn($colName)
{
$this->deletedAtCol = $colName;
}
然后在您的控制器中添加:
public function deleteMessage($id, $seller_id, $buyer_id)
{
$message = Message::findOrFail($id);
//if the seller delete
if($seller_id == auth()->user->id)
$message->setDeletedAtCol("deleted_by_seller");
//if the buyer delete
else($buyer_id == auth()->user->id)
$message->setDeletedAtCol("deleted_by_buyer");
return $message->delete();
}