Laravel Eloquent 模型属性

21

在实例化继承Laravel的Eloquent Model类的模型类之后,是否有一种方法可以确定属性/属性映射到表格,并因此可以保存到表格中?

例如,我有一个名为announcements的表格,其中包含idtextcreated_by列。

如何知道created_by是一个属性并且如果设置了将被保存?

$announcement = new Announcement();

isset($announcement->created_by) 如果我没有明确设置值,这理所当然会返回false。 我尝试了从Eloquent模型类继承的各种函数,但迄今为止没有任何一个起作用。 我正在寻找像这样的函数:

$announcement->doesThisMapToMyTable('created_by') 无论是否设置了$announcement->created_by,都会返回true。


1
Mattcore,请考虑将@Leith的simple answer设置为已接受。它简单明了,能够满足您的要求。 - Zanshin13
6个回答

37
如果您的模型已经充满了数据,您可以:
$announcement = Announcement::find(1);

$attributes = $announcement->getAttributes();

isset($attributes['created_by']);

对于空模型(新模型),不幸的是,您将不得不使用一个小技巧来获取列。请将此方法添加到您的BaseModel中:

<?php

class BaseModel extends Eloquent {

    public function getAllColumnsNames()
    {
        switch (DB::connection()->getConfig('driver')) {
            case 'pgsql':
                $query = "SELECT column_name FROM information_schema.columns WHERE table_name = '".$this->getTable()."'";
                $column_name = 'column_name';
                $reverse = true;
                break;

            case 'mysql':
                $query = 'SHOW COLUMNS FROM '.$this->getTable();
                $column_name = 'Field';
                $reverse = false;
                break;

            case 'sqlsrv':
                $parts = explode('.', $this->getTable());
                $num = (count($parts) - 1);
                $table = $parts[$num];
                $query = "SELECT column_name FROM ".DB::connection()->getConfig('database').".INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = N'".$table."'";
                $column_name = 'column_name';
                $reverse = false;
                break;

            default: 
                $error = 'Database driver not supported: '.DB::connection()->getConfig('driver');
                throw new Exception($error);
                break;
        }

        $columns = array();

        foreach(DB::select($query) as $column)
        {
            $columns[$column->$column_name] = $column->$column_name; // setting the column name as key too
        }

        if($reverse)
        {
            $columns = array_reverse($columns);
        }

        return $columns;
    }

}

将您的模型从中扩展:

class Announcement extends BaseModel {

}

那么您将能够:

$columns = $announcement->getAllColumnsNames();

isset($columns['created_by']);

Ķ░óĶ░ó’╝īõĮåµś»$announcement->attributesÕÆī$announcement->getAttributes()ķāĮĶ┐öÕø×NULLŃĆé - mattcrowe
是的,在空模型上你无法访问它们,所以我只是添加了一个我在我的应用程序中使用的方法。 - Antonio Carlos Ribeiro
太好了。感谢你的帮助。 - mattcrowe
4
我无法确定自己是应该高兴他的黑客技巧奏效了,还是担心我不得不使用这样的技巧来让Laravel做我需要它做的事情。无论如何,感谢你的提示! - Dylan Pierce
为了在模型中提供列,Zend框架查询数据库并使用缓存来保留列,Yii使用硬编码数组生成令人惊叹的模型(Gii工具),而Laravel则需要每次查询数据库才能获取它们!我肯定会选择在我的模型中进行硬编码。 - hpaknia
显示剩余8条评论

12

与其自己编写数据库内部的查找逻辑,你可以使用Schema门面来查找列:


use Illuminate\Support\Facades\Schema;

$announcement = new Announcement();
$column_names = Schema::getColumnListing($announcement->getTable());
if (in_array('created_by', $column_names)) {
  // whatever you need
}

另外,早在 Laravel 4 版本中就有 hasColumn() 检查:

use Illuminate\Support\Facades\Schema;

$announcement = new Announcement();
if (Schema::hasColumn($announcement->getTable(), 'created_by')) {
  // whatever you need
}

实际上在 Laravel 7 中应该使用 in_array('created_by', $column_names),因为 created_by 可能是一个数组值。 - user2293554
@user2293554 回去仔细检查了一些旧版本的 Laravel,因为我认为它是按照其他答案类似的列进行索引的,但看起来并不是!我已经更新了我的答案以纠正这个问题。 - Leith

7

Laravel 5.4 版本:

$hasCreatedAt = \Schema::hasColumn(app(Model::class)->getTable(), 'created_at');

    if($hasCreatedAt == true) {
       ...
    }

是的,非常好而简单。所有使用Laravel 5.4的人都应该给这个答案点赞。 - Christopher K.

0
我知道这个问题很旧,但是有一个更简单的答案,不需要查询模型所基于的表的列。
如果您在使用模型时使用了标准的时间戳列,您可以使用以下方法来确定是否存在“created_at”列:
$model->usesTimestamps();

如果您使用了非标准的名称来创建列,您还需要使用以下方法获取该列的名称:
$model->getCreatedAtColumn();

0

Laravel 5.4

我使用了Leith的答案来创建通用的帮助方法,该方法自动将JS对象映射到Laravel模型(并基本忽略那些不属于模型的属性,从而避免QueryBuilder错误消息未定义列)。此外还包含简单的createOrEdit方法(即使没有“ID是否存在?”验证):

    public function store(Request $request) {
        if($request->input("club")) {
            $club = \App\Club::find($request->input("club")["id"]);
        } else {
            $club = new \App\Club;
        }
        $club = self::mapModel($request->input("club"), $club);
        $club->save();
    }
    
    public function mapModel($input,$model) {
        $columns = Schema::getColumnListing($model->getTable());
        foreach ($columns as $i => $key) {
            if($input[$key]) {
                $model->{$key} = $input[$key];
            }
        }
        return $model;
    }


-2

我曾经使用过!empty($announcement->created_by),它对我的工作非常有效。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接