【问题标题】:Eloquent ORM: Define allowed model attributesEloquent ORM:定义允许的模型属性
【发布时间】:2017-03-25 17:03:41
【问题描述】:

在 laravel 的 eloquent ORM 中,有没有办法定义模型的允许属性?

默认情况下,我可以将任何属性放入模型的构造函数中 - 但只有在我实际尝试将模型保存到数据库时,我才会收到有关错误属性名称的通知。

示例代码:

// this works although there is a typo in "lastname"
$user = new \App\User(['firstname' => 'foo', 'lastnam' => 'bar']);

// this errors out with an SQL error
$user->save();

那么,有没有办法让 Laravel 自动检查请求的输入数据中是否存在无效键?

【问题讨论】:

  • @SteffenBrem 和我强烈建议你在 Laravel 项目中使用 Eloquent 而不是 Doctrine。 )
  • @AlexeyMezenin Eloquent 可以用于演示或原型,但对于任何其他情况,Doctrine 是优越的。 Eloquent 违反了许多编程原则,他们这样做是为了使其“更容易”(我们可以争论)使用。我只是给初学者一个建议,这样他们就不必在编程之旅中走很长的路了。
  • @SteffenBrem Laravel 本身违反了很多编程原则。这就是为什么它对实际项目如此方便。 ) Symfony 是另一个伟大的框架,适合那些更喜欢尊重所有已知的编程原则而不是方便和更高的开发速度的人。
  • @AlexeyMezenin 确实!很高兴你这么说。我试图鼓励人们更多地遵循这些原则,并且与遵守这些原则的项目合作是开始理解它们的好方法。在 Laravel 等框架中学习那些糟糕的做法非常容易,而且对任何人都没有任何好处。

标签: laravel eloquent


【解决方案1】:

如果您不仅想防止使用fill() 方法填充不允许的属性,而且还想直接设置它们,例如$model->foo = 'bar',那么您必须覆盖Model::setAttribute() 方法。

最好在扩展 Eloquent 的自定义基础模型中执行此操作。所以在app/Model.php:

namespace App;

use Exception;
use Illuminate\Database\Eloquent\Model as Eloquent;

class Model extends Eloquent
{
    // this should be actually defined in each sub-model
    protected $allowed = ['firstname', 'lastname'];

    public function setAttribute($key, $value)
    {
        // this way we can allow some attributes by default
        $allowed = array_merge($this->allowed, ['id']);

        if (! in_array($key, $allowed)) {
            throw new Exception("Not allowed attribute '$key'.");
        }

        return parent::setAttribute($key, $value);
    }
}

然后在不允许无效属性的模型中,您可以扩展此基本模型:

use App\Model;

class User extends Model

【讨论】:

    【解决方案2】:

    我不相信这可以在本地完成。我认为 Laravel 在这个意义上是故意放任的,如果我在某处设置属性时出错,我个人不介意出现 SQL 错误而不是 Eloquent 错误。

    话虽如此,当设置不存在的属性时,自定义模型以使其失败并不难:

    // User.php
    
    protected $fillable = [
        'firstname',
        'lastname',
    ];
    
    public function fill(array $attributes)
    {
        foreach ($attributes as $key => $value) {
            if (!in_array($key, $this->getFillable())) {
                throw new \Exception("Attribute [{$key}] is not fillable.");
            }
        }
    
        return parent::fill($attributes);
    }
    

    【讨论】:

      【解决方案3】:

      当你添加这样的属性时,Laravel uses fill() 方法是 mass assignment 功能的一部分:

      if ($this->isFillable($key)) {
          $this->setAttribute($key, $value);
      } elseif ($totallyGuarded) {
          throw new MassAssignmentException($key);
      }
      

      因此,要使其正常工作,请将要保存的所有允许值添加到 $fillable 数组:

      $fillable = ['firstname', 'lastname'];
      

      【讨论】:

      • 不幸的是,这并没有告诉我无效的属性——因为使用了fillableFromArray,它们被默默地丢弃了。
      • @cweiske 您应该手动验证输入数据。你不想得到 SQL 错误或其他东西,你想在尝试持久化数据之前知道某个字段是否为空。
      【解决方案4】:

      您可以覆盖模型构造函数并在那里验证:

      use Illuminate\Support\Facades\Schema;
      //...
      
      public function __construct(array $attributes = [])
      {
          $columns = Schema::getColumnListing($this->table);
      
          foreach ($attributes as $attribute => $value) {
              if (! in_array($attribute, $columns)) {
                  // not allowed
              }
          }
      
          parent::__construct($attributes);
      }
      

      【讨论】:

      • 这可能是最好的方法,尽管您也可以将它与Paul's answer 结合使用,如果您不想将其复制粘贴到基础模型类中,则只需在基础模型类中编写一次您拥有的每个模型。不过,这实际上是在验证您自己的代码,以便您可以找到拼写错误。
      【解决方案5】:

      您可以对每个输入使用 laravel exists:column 验证规则。
      请查看文档https://laravel.com/docs/5.3/validation#rule-exists

      您可以为此目的制作助手

      $table 是表名

      function validateInputColumns($table, array $inputs) 
      {
          $unknownCols = null;
      
          $i = 0;
      
          foreach ($inputs as $key => $val) {
              if (! Schema::hasColumn($table, $key)) {
                  $unknownCols[$i] = $key;
      
                  $i++;
              }
          }
      
          return is_null($unknownCols) ? true : $unknownCols;
      }
      

      它将返回数组中的未知列列表。

      【讨论】:

        【解决方案6】:

        如果我对您的理解正确,Eloquent Events 可能会对您有所帮助。 然后,您可以将输入数组与可填充数组进行比较。

        【讨论】:

          猜你喜欢
          • 2015-09-23
          • 1970-01-01
          • 2018-11-03
          • 2012-01-13
          • 2014-06-17
          • 1970-01-01
          • 2015-10-29
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多