vBladeNYC's avatar

Asking for suggestions on how to deal with dynamic model attributes and mass assignment

Hi all,

Im currently building a CMS type system where i have a MODEL called Publications which can have custom fields added. Im using MongoDB for some of my Models, including PUBLICATIONS and UserDefinedAttributes models, which allows for schema-less tables (collections) and allows for on-demand creation of fields in tables (collections).

So imagine you have the following situation, you have a set of COMMON ATTRIBUTES, like:

  • title
  • publicationType [article, research paper, white paper, commentary, review, etc]
  • publicationDate
  • abstract
  • authors (array of many authors)
  • and a lot more...

*** and then some PUBLICATIONS would need some additional data stored with some records... but the problem is that its very difficult to predict and figure out ALL POSSIBLE ATTRIBUTES... so there is a need to allow to create custom attributes and be able to use them when creating PUBLICATIONS records.

So in order to do that, there is an additional MODEL called "User Defined Attributes" which allows the creation of attributes of type STRING. The purpose of this additional MODEL is to be able to validate against all possible EXPECTED fields during FormRequest Validation.

PublicationStoreRequest

<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class PublicationStoreRequest  extends FormRequest
{
    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        $commonAttrs = [
            'title' => 'required|string|max:255',
            'publicationType' => 'required|string',
            'authors' => 'required|array',
            'publicationDate' => 'required|date',
            etc
            etc
            etc
        ];

        // QUESTION: How do i get a list of UserDefinedAttributes and assign it to $customAttrs
        // all of CustomAttrs are optional and of type string with max 255 chars;
        // so structure of the $customAttrs will be like this $customAttrs = ['customAttrX' => 'nullable|string|max:255']
        // $customAttrs = getCustomAttrs(); // how to get dynamically?

        $expectedAttrs = array_merge($commonAttrs, $customAttrs);

        return $expectedAttrs;
    }

     /**
     * Custom message for validation
     *
     * @return array
     */
    public function messages()
    {
        return [
            'title.required' => 'title is required!',
            'publicationType.required' => 'publicationType is required!',
            'authors.required' => 'authors is required!'
        ];
    }
}

Now for my PUBLICATIONS, im not sure if i can set DYNAMICALLY which fields are FILLABLE, so i figure ANYTHING EXPECTED is FILLABLE except what is $GUARDED...

Publication Model

<?php
 
namespace App\Models;
 
use MongoDB\Laravel\Eloquent\Model as MongoModel;
 
class Publication extends MongoModel
{
    /**
     * The table associated with the model.
     *
     * @var string
     */
    protected $collection = 'publications';

    /**
     * The attributes that aren't mass assignable.
     *
     * @var array
     */
    protected $guarded = ['user_id', 'institution_id'];
}

and finally my Controller.... PublicationsController

<?php

namespace App\Http\Controllers\Publications;

use App\Http\Controllers\Controller;
use App\Http\Requests\PublicationStoreRequest;
use App\Models\Publication;

class PublicationsController extends Controller
{
    public function store(PublicationStoreRequest $request)
    {
        // Will return only validated data        
        $validatedData = $request->validated();

        Publication::create($validatedData);
        return back()->with('successfulCreate', 'New Publication added successfully.');
    }
}

Any and all suggestions/comments are greatly appreciated. Thanks in advance!

0 likes
2 replies
LaryAI's avatar
LaryAI
AI
Best Answer
Level 58

To dynamically get a list of UserDefinedAttributes and assign them to $customAttrs in the PublicationStoreRequest class, you can create a method in the UserDefinedAttributes model that retrieves the custom attributes. Here's an example of how you can modify the code:

use App\Models\UserDefinedAttributes;

class PublicationStoreRequest extends FormRequest
{
    // ...

    public function rules()
    {
        $commonAttrs = [
            'title' => 'required|string|max:255',
            'publicationType' => 'required|string',
            'authors' => 'required|array',
            'publicationDate' => 'required|date',
            // etc
        ];

        $customAttrs = UserDefinedAttributes::pluck('attribute_name')
            ->mapWithKeys(function ($attribute) {
                return [$attribute => 'nullable|string|max:255'];
            })
            ->toArray();

        $expectedAttrs = array_merge($commonAttrs, $customAttrs);

        return $expectedAttrs;
    }

    // ...
}

In this example, we use the pluck method to retrieve all the attribute names from the UserDefinedAttributes model. Then, we use the mapWithKeys method to transform the attribute names into an associative array where the attribute name is the key and the validation rule is the value. Finally, we convert the collection to an array using the toArray method and merge it with the common attributes.

Make sure to import the UserDefinedAttributes model at the top of the file:

use App\Models\UserDefinedAttributes;

This solution assumes that the UserDefinedAttributes model has a column named attribute_name that stores the names of the custom attributes. Adjust the code accordingly if your model has a different column name.

Remember to replace the UserDefinedAttributes model with the actual namespace and class name of your UserDefinedAttributes model.

1 like
vBladeNYC's avatar

WOW... The AI pretty much got it 100%. Question is it possible to dynamically assign $fillable in the model?

Please or to participate in this conversation.