Skip to content

Package: model-fields

Generated from api/packages/model-fields

Source: api/packages/model-fields · imported version 0.1.1. The sections after the README are extracted from the code on every docs build.

This package allows you to add unlimited extra primitive fields to any model.

Types of fields that can be user

  • booleandoc
  • number
  • varchar
  • text
  • json

Details documentation is provided as an example

  • composer require ulams/model-fields
  • php artisan migrate
  • php artisan db:seed --class="Ulams\ModelFields\Database\Seeders\PermissionTableSeeder"

The package allows to add additional fields by creating special meta description values that are saved in database.

Next to metadata descriptions there are values that works with the meta description.

Below are examples of how matadata and values are stored in database

model_fields_metadata table sample rows

id created_at updated_at name type rules extra default class_type visibility
2147 2022-03-03 12:10:05 2022-03-03 12:10:05 description text [“required”,“string”,“max:255”] NULL lorem ipsum Ulams\ModelFields\Tests\Models\User 1
2148 2022-03-03 12:10:05 2022-03-03 12:10:05 interested_in_tests boolean [“required”,“boolean”] NULL 1 Ulams\ModelFields\Tests\Models\User 1
2149 2022-03-03 12:10:05 2022-03-03 12:10:05 title varchar [“required”,“string”,“max:255”] NULL Ulams\ModelFields\Tests\Models\User 1
2150 2022-03-03 12:10:05 2022-03-03 12:10:05 consents json [“required”,“json”] NULL [] Ulams\ModelFields\Tests\Models\User 1
2151 2022-03-03 12:10:05 2022-03-03 12:10:05 extra_points number [“required”,“integer”] NULL 123 Ulams\ModelFields\Tests\Models\User 1
2153 2022-03-03 12:11:05 2022-03-03 12:11:05 extra_description text [“required”,“string”,“max:255”] NULL lorem ipsum Ulams\ModelFields\Tests\Models\User 1

model_fields_values table sample rows

id created_at updated_at name value class_type class_id
1432 2022-03-03 12:17:42 2022-03-03 12:17:42 consents {“consent1”:true,“consent2”:false} Ulams\ModelFields\Tests\Models\User 1458
1433 2022-03-03 12:17:42 2022-03-03 12:17:42 extra_points 1000 Ulams\ModelFields\Tests\Models\User 1458
1436 2022-03-03 12:17:42 2022-03-03 12:17:42 description zzz Ulams\ModelFields\Tests\Models\User 1458
1438 2022-03-03 12:17:42 2022-03-03 12:17:42 interested_in_tests true Ulams\ModelFields\Tests\Models\User 1458

See tests folder as rows above are generated from the tests.

The best documentation operates on live example so here it is.

Assuming you have User Model

use Illuminate\Database\Eloquent\Model;
class User extends Model
{
protected $table = 'users';
protected $fillable = ['first_name', 'last_name', 'email'];
protected $appends = ['foo'];
public function getFooAttribute()
{
return 'bar';
}
}

In order to add extra fields to user model you would need to create new columns in user table with migration and add those fields. This is a standard way of handling this issue, but this package introduces new one.

This option replaces Illuminate\Database\Eloquent\Model with Ulams\ModelFields\Models\Model

use Ulams\ModelFields\Models\Model;
class User extends Model
{
protected $table = 'users';
protected $fillable = ['first_name', 'last_name', 'email'];
protected $appends = ['foo'];
public function getFooAttribute()
{
return 'bar';
}
}

This option uses Ulams\ModelFields\Traits\ModelFields instead of extending class;

use Illuminate\Database\Eloquent\Model;
use Ulams\ModelFields\Traits\ModelFields;
class User extends Model
{
use ModelFields;
protected $table = 'users';
protected $fillable = ['first_name', 'last_name', 'email'];
protected $appends = ['foo'];
public function getFooAttribute()
{
return 'bar';
}
}
}

Basically that all the steps you need to allow model to be extendable.

Now lets create new field meta description. We’ll be adding new field to user, called description which will be long text.

use Ulams\ModelFields\Facades\ModelFields;
ModelFields::addOrUpdateMetadataField(
User::class, // Model class that we want to extents
'description', // name of new field
'text', // type of new field
'lorem ipsum', // default value
['required', 'string', 'max:255'] // validation rules
);

Interface of this method is as follows

use Ulams\ModelFields\Models\Metadata;
public function addOrUpdateMetadataField(string $class_type, string $name, string $type, string $default = '', array $rules = null, $visibility = 1 << 0): Metadata;

Once new field is added you can use is as any other attribute of model

$extraAttributes = [
'description' => 'to be or not to be',
];
$user = User::create(array_merge([
'first_name' => 'John',
'last_name' => 'Deo',
'email' => 'john@email.com',
], $extraAttributes));
$user = User::find($user->id);
assert($user->description === $extraAttributes['description']);

That’s all, your user model is ready to be extended. You can get and set attributes as they were created standard way.

$extraAttributes = [
'description' => 'aaa',
'interested_in_tests' => false,
'aaaa' => 'aaaa', // this will not be saved as is neither in model attributes nor in extra fields
'consents' => ['consent1' => true, 'consent2' => false]
];
$user = User::create(array_merge([
'first_name' => 'aaa',
'last_name' => 'aaa',
'email' => 'aaa@email.com',
], $extraAttributes));
$user->fill(['a' => 'nb']); // this will not be saved as is neither in model attributes nor in extra fields
$user = User::find($user->id); // fetch user from database
assert($user->description === $extraAttributes['description']);
assert($user->interested_in_tests === $extraAttributes['interested_in_tests']);
assert($user->consents === $extraAttributes['consents']);
assert($user->aaaa === null);
$user->description = 'abc';
$user->interested_in_tests = true;
$user->save();
$user = User::find($user->id); // fetch user from database
assert($user->description === 'abc');
assert($user->interested_in_tests === true);
$user->update([
'description' => 'zzz',
'interested_in_tests' => false
]);
$user = User::find($user->id); // fetch user from database
assert($user->description === 'zzz');
assert($user->interested_in_tests === false);

Using resources is simple, look at the following example

namespace Ulams\ModelFields\Tests\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
use Ulams\ModelFields\Tests\Models\User;
use Ulams\ModelFields\Facades\ModelFields;
use Ulams\ModelFields\Enum\MetaFieldVisibilityEnum;
class UserResource extends JsonResource
{
public function __construct(User $user)
{
$this->user = $user;
}
public function toArray($request)
{
return [
'id' => $this->user->id,
'first_name' => $this->user->first_name,
'last_name' => $this->user->last_name,
'email' => $this->user->email,
...ModelFields::getExtraAttributesValues($this->user, MetaFieldVisibilityEnum::PUBLIC) // MetaFieldVisibilityEnum::PUBLIC === 1
];
}
}

Note. In php 7.4 user array_merge instead of spread ... operator.

Look at the visibility field in example above. Package allows to define visibility of the meta fields. Here we’re defining 2 fields, one is public, second admin only.

use Ulams\ModelFields\Facades\ModelFields;
use Ulams\ModelFields\Facades\ModelFields;
ModelFields::addOrUpdateMetadataField(
User::class,
'title',
'varchar',
'',
['required', 'string', 'max:255']
);
ModelFields::addOrUpdateMetadataField(
User::class,
'admin_secret',
'varchar',
'super_secret',
['required', 'string', 'max:255'],
MetaFieldVisibilityEnum::ADMIN
);

Now we can have 2 endpoints one that list user with public fields, other with visible to admin only.

namespace Ulams\ModelFields\Tests\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
use Ulams\ModelFields\Tests\Models\User;
use Ulams\ModelFields\Facades\ModelFields;
use Ulams\ModelFields\Enum\MetaFieldVisibilityEnum;
class UserResource extends JsonResource
{
public function __construct(User $user)
{
$this->user = $user;
}
public function toArray($request)
{
return [
'first_name' => $this->user->first_name,
'last_name' => $this->user->last_name,
'email' => $this->user->email,
...ModelFields::getExtraAttributesValues($this->user, MetaFieldVisibilityEnum::PUBLIC)
];
}
}

Now let’s see how Admin Resource would look like.

namespace Ulams\ModelFields\Tests\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
use Ulams\ModelFields\Tests\Models\User;
use Ulams\ModelFields\Facades\ModelFields;
use Ulams\ModelFields\Enum\MetaFieldVisibilityEnum;
class UserAdminResource extends JsonResource
{
public function __construct(User $user)
{
$this->user = $user;
}
public function toArray($request)
{
return [
'id' => $this->user->id,
'first_name' => $this->user->first_name,
'last_name' => $this->user->last_name,
'email' => $this->user->email,
...ModelFields::getExtraAttributesValues($this->user, MetaFieldVisibilityEnum::ADMIN | MetaFieldVisibilityEnum::PUBLIC)
];
}
}

MetaFieldVisibilityEnum::ADMIN | MetaFieldVisibilityEnum::PUBLIC is a Flagged/Bitwise Enum. MetaFieldVisibilityEnum is just a proposal - you can use as many permissions as you like yet defining values you must use powers of 2, like.

const ReadComments = 1 << 0;
const WriteComments = 1 << 1;
const EditComments = 1 << 2;
const DeleteComments = 1 << 3;

Example below describes how to fetch validation rules from MetaField

namespace Ulams\ModelFields\Tests\Http\Requests;
use Ulams\ModelFields\Tests\Models\User;
use Illuminate\Foundation\Http\FormRequest;
use Ulams\ModelFields\Facades\ModelFields;
class UserCreateRequest extends FormRequest
{
/**
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'first_name' => ['required', 'string'],
'last_name' => ['required', 'string'],
'email' => ['required', 'unique:users'],
...ModelFields::getFieldsMetadataRules(User::class)
];
}
}

In php 7.4 user array_merge instead of spread ... operator.

All the endpoints are defined in swagger.

Run ./vendor/bin/phpunit to run tests. See tests folder as it’s quite good staring point as documentation appendix.

Test details codecov phpunit

This package does not dispatch any events.

This package does not listen for any events

All the endpoints defined in swagger are for admin panel.

There is native component you can use to implement this in admin panel for any model that allows extending

<ModelFields class_type="Ulams\Auth\Models\User" />

Example in admin panel

List of user model fields

List of user model fields

Creating/editing model field

Creating/editing model field

See example above how to extend controllers to CRUD model fields to give model

Permissions are defined in seeder

  • firstOrCreate doesn’t work when passing extra attributes
Method Path Auth Action
GET /api/model-fields ModelFieldsApiController@list
GET /api/admin/model-fields yes ModelFieldsAdminApiController@list
POST /api/admin/model-fields yes ModelFieldsAdminApiController@createOrUpdate
DELETE /api/admin/model-fields yes ModelFieldsAdminApiController@delete
Permission Seeded for roles Constant
metadata_create_update admin MetaFieldPermissionsEnum::METADATA_CREATE_UPDATE
metadata_delete admin MetaFieldPermissionsEnum::METADATA_DELETE
metadata_list admin MetaFieldPermissionsEnum::METADATA_LIST

Registered with AdministrableConfig::registerConfig (editable in the admin panel under Configuration → Settings).

None.

None.

None.

None.

None.