【问题标题】:How to only use created_at in Laravel如何在 Laravel 中只使用 created_at
【发布时间】:2015-07-05 08:39:03
【问题描述】:

我只想使用 created_at ,怎么办?

我知道:

这可以自定义时间戳名称

const CREATED_AT = 'created';
const UPDATED_AT = 'updated';

这可以禁用时间戳

public $timestamps = false;

【问题讨论】:

    标签: php laravel


    【解决方案1】:

    Eloquent 不提供开箱即用的此类功能,但您可以使用 creating 事件回调自行创建:

    class User extends Eloquent {
    
        public $timestamps = false;
    
        public static function boot()
        {
            parent::boot();
    
            static::creating(function ($model) {
                $model->created_at = $model->freshTimestamp();
            });
        }
    
    }
    

    【讨论】:

    • 我认为这是破解 Eloquent 模型时间戳的最佳方法。它适用于 Laravel 5.1。
    • 干得漂亮!并且应该首先调用parent::boot();
    • 可以改进它以使用$model->setCreatedAt($model->freshTimestamp());,这将使用static::CREATED_AT const
    • 您也可以通过在迁移中执行 $table->timestamp('created_at')->useCurrent(); 来跳过引导代码
    • 我使用了上述批准,但发现额外的条件检查有助于我在创建模型时在模型上设置备用 created_at。 static::creating(function ($model) { if (! $model->isDirty(static::CREATED_AT)) { $model->created_at = $model->freshTimestamp(); } });
    【解决方案2】:

    我的解决方案是使用新的__construct 方法。

    见:

    class MyModel extends Eloquent {
    
        public $timestamps = false;
    
        public function __construct(array $attributes = [])
        {
                parent::__construct($attributes);
    
                $this->attributes['created_at'] = $this->freshTimestamp();
        }
    }
    

    【讨论】:

      【解决方案3】:

      我的解决方案:

      class CreatePostsTable extends Migration {
      
         public function up() {
      
            Schema::create('posts', function(Blueprint $table){
      
               $table->timestamp('created_at')->default(DB::raw('CURRENT_TIMESTAMP'));
         });
      }
      

      这对我有用

      【讨论】:

      • 这样做有什么缺点吗?
      • 您的 PHP 脚本使用的时区可能与您的数据库不同。
      • 我看到了一个很大的缺点,即您无法在单元测试中模拟日期更改,就像 Carbon::setTestNow($now);
      • 但如果你真的需要,最好使用$table->timestamp('created_at')->useCurrent();
      【解决方案4】:

      要仅禁用 updated_at,您可以覆盖 Model::setUpdatedAt() 方法,如下所示:

      public function setUpdatedAt($value) {
          // Do nothing.
      }
      

      当然,如果您想对 created_at 列执行此操作,也同样简单。这适用于 Laravel 5.1

      【讨论】:

      • 我发现它不适用于 5.1.7,因为它也在生成器更新调用 return Arr::add($values, $column, $this->model->freshTimestampString()); 时更新时间戳
      • 我想是function setUpdatedAtAttribute($value)CMIIW
      • 它适用于 Laravel 5.8,但我更喜欢 const UPDATED_AT = null;
      【解决方案5】:

      仅使用 setUpdatedAt 的方法不适用于 Laravel 5.1.7,因为它还有一个处理 updated_at 的地方。

      Model类performUpdate方法调用Builder类方法:

      public function update(array $values)
      {
          return $this->query->update($this->addUpdatedAtColumn($values));
      }
      

      这导致我们

      return Arr::add($values, $column, $this->model->freshTimestampString());
      

      我不确定,为什么 Laravel 处理 updated_at 两次 - 在 performUpdate$this->updateTimestamps() 中,然后在 Builder 中使用 $this->addUpdatedAtColumn($values)

      通过一些调试,我发现您还必须使用 getUpdatedAtColumn 覆盖更新您的模型。一开始我还担心它会尝试更新一个不存在的字段“null”,但事实证明Arr::add 足够聪明,可以忽略空键。

      所以,在你的模型类中添加这些:

      public function setUpdatedAt($value)
      {
          // Do nothing.
      }
      
      public function getUpdatedAtColumn()
      {
          return null;
      }
      

      这应该足以禁用这两个更新。

      【讨论】:

      • getDates() 方法也应该被覆盖,所以它不包括null:public function getDates() { $defaults = [static::CREATED_AT]; return $this->timestamps ? array_merge($this->dates, $defaults) : $this->dates; }
      • 这也将搞砸更新关系,因为所有来自关系类的 getUpdatedAtColumn 调用。
      • 你能举一个@hackel的例子吗?
      【解决方案6】:

      在顶部使用:

      const UPDATED_AT = null;
      

      对于“created_at”字段,您可以使用:

      const CREATED_AT = null;
      

      LARAVEL 5.5.0 - 5.5.5 更新

      这已被破坏in Laravel 5.5.0(并再次修复in 5.5.5)。

      如果您使用的是 5.5.x,请确保您使用的是最新版本。

      如果由于某种原因您无法使用最新版本,这里有一个解决方法。

      将公共 $timestamps 设置为 false:

      public $timestamps = false;
      

      必要时:

      public function setCreatedAtAttribute($value) { 
          $this->attributes['created_at'] = \Carbon\Carbon::now(); 
      }
      

      public function setUpdatedAtAttribute($value) { 
          $this->attributes['updated_at'] = \Carbon\Carbon::now(); 
      }
      

      当需要“created_at”和“updated_at”这两个字段时,当然不必做任何事情;)

      【讨论】:

      • 有人能解释一下吗?它到底是做什么的?
      • 我同意 Anthony 的观点——这需要更多解释。
      • const UPDATED_AT = null; 阻止 Laravel 尝试更新表中的 updated_at 字段。
      • 使用源代码,孩子们。这种方法是不可取的。这将导致 updateTimestamps() 在模型不脏(没有字段更改)时尝试将日期保存到 null 属性,从而引发错误。只需尝试保存一个空模型或 touch() 现有模型即可看到这一点。这也将导致 getDates() 返回 ['created_at', null],如果您以某种方式无意中使用 null 键(它被强制转换为空字符串)在模型上设置了属性,这可能会导致问题。我相信 JustAMartin 的解决方案是最完整的。
      • @hackel 对于 Laravel 5.8 是错误的,源代码明确指出 if (! is_null(static::UPDATED_AT) && 好吧,他/她使用源代码是正确的,但他/她在政治上不正确地称呼人名。
      【解决方案7】:

      hereLaravel 5.2 or above 提供了更好的答案。

      你可以在模型中使用它-

      class User extends Model
      {
          public $timestamps = false; // disable all behavior
          public $timestamps = true; // enable all behavior
          public $timestamps = [ "created_at" ]; // enable only to created_at
          public $timestamps = [ "updated_at" ]; // enable only to updated_at
          public $timestamps = [ "created_at", "updated_at" ]; // same as true, enable all behavior
      }
      

      所以,对于你的问题,答案是 -

      public $timestamps = [ "created_at" ]; // enable only to created_at
      

      重新-

      public $timestamps = [ "created_at" ]; 
      

      不适用于 Laravel 6+

      【讨论】:

      • 适用于 Laravel 5.2 或 +
      • 如果没有自己研究供应商代码,请勿使用此答案。这不起作用,因为它仍然是一个提案并且尚未实施(现在是 5.3)。
      • 公开 $timestamps = [ "created_at" ];在 Laravel 5.5.13 中仍然无法使用。
      • 在 Laravel 5.8 中不工作,它给了我一个错误Column not found: 1054 Unknown column 'updated_at' in 'field list'
      • public $timestamps = [ "created_at" ]; 在 laravel 6 中不起作用
      【解决方案8】:

      我使用了非常简单的 hack ;)

      类 MyClass 扩展模型 {

      const CREATED_AT = 'creation_date';
      const UPDATED_AT = 'creation_date';
      

      }

      我只是将两者都指向同一列:)

      【讨论】:

      • 呃,这将导致每次保存模型时都会覆盖create_at列。不要这样做! (但是,如果您只想要 updated_at 列,它会起作用。)
      【解决方案9】:

      在 5.3 版中,我只是做了public $timestamps = false;,然后添加了受保护的 $fillable = ['created_at']。注意:你可以添加任何你想要的东西,只要确保它与你表中的匹配即可。`

      【讨论】:

      • 在 Laravel 5.8 中不工作,如果你在 Laravel 升级过程中没有改变它,最好不要这样做。
      • 通过这样做,你告诉模型一个 http 请求可以手动编辑 created_at 字段。这不是一个好的解决方案。不要这样做。
      【解决方案10】:

      一个简单、解耦和可重用的解决方案是使用模型观察器。这个想法是捕获creating 事件并填充created_at 属性。这种方法可以被任意数量的模型使用,而无需重复代码或使用非官方的技巧。最重要的是,它与 Model 类的内部机制非常相似,从而避免了意外错误。

      1) 在App\Observers 中创建SetCreatedAt 观察者:

      namespace App\Observers;
      
      use Illuminate\Database\Eloquent\Model;
      
      class SetCreatedAt
      {
          /**
           * Sets created_at when creating the model.
           *
           * @param Model $model
           * @return void
           */
          public function creating(Model $model)
          {
              $model->setCreatedAt($model->freshTimestamp());
          }
      }
      

      2) 在boot 方法内的App\Providers\AppServiceProvider 上,为您希望为其生成created_at 的每个模型添加以下行:

      /**
       * Bootstrap any application services.
       *
       * @return void
       */
      public function boot()
      {
          // Replace OrderLog with your model
          OrderLog::observe(SetCreatedAt::class);
      }
      

      3) 在您的模型上,您唯一需要做的就是禁用时间戳:

      // Disable timestamps on the model
      public $timestamps = false;
      

      使用 Laravel 5.3 进行测试,但它也应该适用于以前的版本。

      祝你好运!

      【讨论】:

      • 什么是 OrderLog?这是你的型号名称吗?
      • 如果我需要多个模型来拥有这个,我应该在每个模型中复制引导中的观察吗?
      • @ClearBoth 是的,OrderLog 只是一个例子;用你的模型替换它。要在多个模型中使用,只需为每个模型复制 YourModel::observe(SetCreatedAt::class) 行。我这里写了更详细的教程arianacosta.com/php/laravel/…
      • 我已经实现了这个,但是,你确定这是这样做的明智选择吗?我在应用服务提供商中有几个模型,这意味着它将在每个页面请求上加载,这可能会影响性能。
      • @ClearBoth 说得好。注册观察者的性能影响应该几乎不存在。但是,如果您发现在您的应用程序中您正在 AppServiceProvider 上加载数十个模型,那么将其移至其自己的服务提供者并有选择地加载它们可能是一个好主意。感谢您的洞察力。
      【解决方案11】:

      在 5.4 中,它给出的问题是即使在更新(Eloquent 更新)之后它也不会填充 updated_at 字段。

      改为添加此方法

      public function setUpdatedAtAttribute($value)
      {
          // auto disable update_at in inserts 
      }
      

      【讨论】:

      • @YevgeniyAfanasyev 请看问题日期,laravel 5.8 甚至还不存在。
      • 你是对的。也许它在当时是一个有价值的答案,并且你在其中放入了 Laravel 版本做得很好。但是如果有人选择了这个答案,他们需要在 laravel 升级过程中检查他们的代码,这应该被提及。我无法验证答案,所以我不在这里投票。
      【解决方案12】:

      我通过在我的数据库中为列created_at 添加默认值CURRENT_TIMESTAMP 来解决。在我的模型中,我使用下面的代码

      public $timestamps = false;
      protected $dates = ['created_at'];
      

      我希望这个方法适用于所有版本的 laravel。

      【讨论】:

      • 请注意,您的数据库时间可能与 apache/php 时间不同。
      【解决方案13】:

      您可以在 MySQL 表中为 created 字段使用 CURRENT_TIMESTAMP 默认值并设置

      public $timestamps = false;
      

      在你的模型中。

      【讨论】:

      • 我想是的。例如,在您的迁移中,您会编写: $table->timestamp('failed_at')->useCurrent(); (Laravel 在 failed_jobs 迁移存根中使用它)。
      【解决方案14】:

      在类的顶部使用:

      const UPDATED_AT = null;

      const CREATED_AT = null;

      【讨论】:

      • 投了赞成票,这是一个正确的答案,但细节太少了。下次,请提及您的 Laravel 版本。
      【解决方案15】:

      在 Laravel 5.7 中,这对我来说已经足够了:

      迁移中:

      $table->timestamp('created_at')->nullable();
      

      而不是经典的$table->timestamp('created_at');

      在模型中:

      const UPDATED_AT = null;
      

      【讨论】:

        【解决方案16】:

        在您的model 设置上

        const UPDATED_AT = null;

        const CREATED_AT = null;

        它会阻止 Laravel 尝试更新 updated_at/created_at 字段

        适用于 Laravel 5.8

        而且它比覆盖:setUpdatedAt 在你的model 中更好

        public function setUpdatedAt($value) : self 
        {
            // Do nothing.
            return $this;
        }
        

        因为它更短并且因为if (! is_null(static::UPDATED_AT) 的检查在源代码中发生在触发之前 setUpdatedAt

        【讨论】:

          【解决方案17】:

          自 Laravel 5.*

          型号:

          //  Disable updated_at (only created_at)
          class Book extends Model
          {
               const UPDATED_AT = null;
          
               /* ... */
          }
          

          迁移:

          Schema::create('books', function (Blueprint $table): void {
              /* ... */
              $table->timestampTz('created_at')->nullable();
          });
          

          【讨论】:

          • 这是在 2020 年实现这一目标的正确方法。不再需要接受的答案。
          • 绝对是最好的解决方案。
          【解决方案18】:

          对于在这里寻找updated_at 而不是created_at 的任何人,但其他答案似乎都不适合您:

          在 Laravel 8 中,您需要将模型属性 CREATED_AT 设置为 null 并将 UPDATED_AT 设置为“updated_at”或您想要的任何其他名称到您的 updated_at 字段。

          use Illuminate\Database\Eloquent\Model;
          
          class User extends Model
          {
              /**
               * The name of the "created at" column.
               *
               * @var string|null
               */
              const CREATED_AT = null;
          
              /**
               * The name of the "updated at" column.
               *
               * @var string|null
               */
              const UPDATED_AT = 'updated_at';
          
          
              public function setCreatedAt($value)
              {
                  // do nothing
              }
          }
          

          还有你的迁移...

          Schema::create('users', function (Blueprint $table) {
              // ...
              $table->timestamp('updated_at'); // instead of $table->timestamps();
          });
          
          

          我不确定为什么需要在模型中设置此属性,因为它已经在父类 Illuminate\Database\Eloquent\Model 中设置,但它仅在我进行此更改后才对我有用。

          【讨论】:

            猜你喜欢
            • 2019-12-07
            • 2020-09-12
            • 1970-01-01
            • 2022-01-03
            • 2014-01-16
            • 2020-10-23
            • 2014-12-17
            • 2020-06-02
            • 2023-02-26
            相关资源
            最近更新 更多