简体   繁体   English

Laravel 模型动态属性

[英]Laravel Model Dynamic Attribute

I would like to ask if how to create a dynamic attribute on the model class.请问如何在model类上创建动态属性。 Let's suppose I have a table structure like below code.假设我有一个如下代码所示的表结构。

   Schema::create('materials', function (Blueprint $table) {
        $table->increments('id');
        $table->string('sp_number');
        $table->string('factory');
        $table->text('dynamic_fields')->comment('All description of the material will saved as json');
        $table->timestamps();
    });

I have a column in my table structure named "dynamic_fields" that will hold a JSON string for the fields.我的表结构中有一个名为“dynamic_fields”的列,它将保存字段的 JSON 字符串。 An example of JSON structure below.下面是 JSON 结构的示例。

[  
   {  
      "name":"COLOR WAY",
      "value":"ASDFF12"
   },
   {  
      "name":"DESCRIPTION",
      "value":"agg2sd12"
   },
   {  
      "name":"REF NUM",
      "value":"121312"
   }
]

So i want to access a field from my dynamic fields like for example "COLOR WAY".所以我想从我的动态字段中访问一个字段,例如“COLOR WAY”。 In my model i want to access the COLOR WAY field on the dynamic field like this way在我的模型中,我想像这样访问动态字段上的 COLOR WAY 字段

$material->color_way;

Can anybody show me how to do it?有人可以告诉我怎么做吗? sorry for my English.对不起我的英语不好。

If you know that there will only be certain dynamic fields ahead of time, you could opt to create accessor methods for them.如果您提前知道只有某些动态字段,您可以选择为它们创建访问器方法。 For example, you could add this to your model:例如,您可以将其添加到您的模型中:

// Dynamic fields must be cast as an array to iterate through them as shown below
protected $casts = [
    'dynamic_fields' => 'array'
];

// ...

public function getColorWayAttribute()
{
    foreach ($this->dynamic_fields as $field) {
        if ($field['name'] === 'COLOR WAY') {
            return $field['value'];
        }
    }

    return null;
}

This will allow you to do:这将允许您执行以下操作:

$colorWay = $material->color_way;

Alternatively, if the combinations your dynamic_fields are not limited, there could be a large number of them or you want there to be more flexibility to be able to add more and have them accessible, you could override the getAttribute method of Laravel's model class.或者,如果您的dynamic_fields的组合不受限制,可能有大量组合,或者您希望有更大的灵活性能够添加更多并使其可访问,您可以覆盖 Laravel 模型类的getAttribute方法。

// Dynamic fields must be cast as an array to iterate through them as shown below
protected $casts = [
    'dynamic_fields' => 'array'
];

// ...

public function getAttribute($key)
{
    $attribute = parent::getAttribute($key);

    if ($attribute === null && array_key_exists('dynamic_fields', $this->attributes)) {
        foreach ($this->dynamic_fields as $dynamicField) {
            $name = $dynamicField['name'];
            if (str_replace(' ', '_', mb_strtolower($name)) === $key) {
                return $dynamicField['value'];
            }
        }
    }

    return $attribute;
}

This approach calls Laravel's implementation of getAttribute which first checks if you have an actual attribute defined, or if you have an accessor defined for the attribute (like in my first suggestion), then checks if a method exists with that name on the base model class and then finally attempts to load a relation if you have one defined.这种方法调用 Laravel 的getAttribute实现,它首先检查是否定义了实际属性,或者是否为属性定义了访问器(如我的第一个建议),然后检查基模型类中是否存在具有该名称的方法如果你定义了一个关系,然后最后尝试加载一个关系。

When each of those approaches fails ( null is returned), we then check to see if there's a dynamic_fields attribute in the model.当这些方法中的每一种都失败时(返回null ),我们然后检查模型中是否存在dynamic_fields属性。 If there is, we loop through each of the dynamic fields (assuming your dynamic_fields is cast as an array ), we then convert the name of the defined dynamic field to lowercase and replace spaces with underscores.如果有,我们循环遍历每个动态字段(假设您的dynamic_fields被转换为array ),然后我们将定义的动态字段的名称转换为小写,并用下划线替换空格。 We then finally check to see if the name we have just derived matches the key provided and if it does, we return the value.然后我们最后检查我们刚刚派生的名称是否与提供的键匹配,如果匹配,我们返回值。 If it doesn't, the original $attribute will be returned, which will be null .如果不是,则将返回原始$attribute ,该$attribute将为null

This would allow you to get any of your dynamic fields as if they were defined as attributes in the class.这将允许您获取任何动态字段,就好像它们被定义为类中的属性一样。

$colorWay = $material->color_way;
$description = $material->description;
$refNum = $material->ref_num;

Please note: I have not tested this code, there could well be an issue or two present.请注意:我尚未测试此代码,很可能存在一两个问题。 Give it a try and see if it works for you.试一试,看看它是否适合你。 Also note that this will only work for getting dynamic fields, setting them will require overriding another method.另请注意,这仅适用于获取动态字段,设置它们需要覆盖另一种方法。

Try to use this code in your model:尝试在您的模型中使用此代码:

protected $casts = [
    'dynamic_fields' => 'array',
];

public function setAttribute($key, $value)
{
    if (!$this->getOriginal($key)) {
        $this->dynamic_fields[$key] = $value;
    }

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

public function getAttribute($key)
{
    if (!$this->getOriginal($key)) {
        return $this->dynamic_fields[$key]
    }

    parent::getAttribute($key);
}

In this example, you can get Dynamic Column form Dynamic Model .在此示例中,您可以从Dynamic Model获得Dynamic Column as well as its Models Relation too以及它的模型关系

1) first you have to define a table Scope in Model. 1)首先你必须在模型中定义一个表范围。

  private  $dynamicTable='';

  public function scopeDefineTable($query,$tableName)
{
    if( $tableName )
    {
        $this->dynamicTable= $tableName;
    }
    else
    {
        $this->dynamicTable= "deviceLogs_".date('n')."_".date('Y');
    }
    $query->from( $this->dynamicTable );

   $this->table=$this->dynamicTable; # give dynamic table nam to this model.
}


  public function  scopeCustomSelect( $query ,$items=[])
{
    $stu_class_col=['id as stu_class_id','std_id']; // Required else retional model will not retun data. here id and std_id is primary key and foreign key.
    $stu_doc_col=['id as stu_doc_id','std_id'];// Required else retional model will not retun data. here id and std_id is primary key and foreign key.

    foreach ( $items as $col)
    {
        if(  Schema::hasColumn('student_information', $col ))
        {
          $stu_info_col[]= $col ;
        }
        elseif (  Schema::hasColumn('student_class',$col))
        {
            $stu_class_col[]= $col ;
        }
        elseif (  Schema::hasColumn('student_image',$col))
        {
            $stu_doc_col[]= $col ;
        }
    }

   // converting array to string for bind column into with relation...
    $stu_class_col_string =  implode(',',$stu_class_col);
    $stu_doc_col_string =  implode(',',$stu_doc_col); 

    return $colQuery = $query->select($stu_info_col)
                    ->with(["student_class:$stu_class_col_string", "studentImage:$stu_doc_col_string"]);
}

using this you can get data from Rational Model too...使用这个你也可以从 Rational 模型中获取数据......

from Controller从控制器

    $studentInfo =  Student::whereHas("student_class",function($q) use($req){
                                   $q->where("std_session",$req->session_code);
                                   $q ->where("std_class",$req->class_code);
                                   $q ->where("std_section",$req->std_section); })
                           ->customSelect($fields['dataList'])
                           ->get();



here I am not using dynamic Model Scope. only Dynamic SustomSelect scope..

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM