nova-package-development
nova-package-development copied to clipboard
Nova EAV Attributes
Package that allows to administrate EAV attributes and edit attribute values through Nova.
This allows to easily have custom attributes added to any model and edit the values within the resources.
Based on https://github.com/rinvex/laravel-attributes
I have a running implementation which supports sorting and translatable attributes.
If you are interested to finalise this into a package, please let me know how to share the code
I'd be very interested in a package like this. I'm currently planning to implement rivenex/laravel-attributes and was concerned about getting it all to play nice in Nova.
While I can't be of any help in putting together a package (simply not experienced enough), I would love to see code samples if you're willing to share.
let me outline the solution, which will give you sortable, translatable attributes you can add to any Model/Resource in Nova:
install and configure https://github.com/rinvex/laravel-attributes
Migration to add column id
to attribute_entity
Table
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AddIdToAttributeEntityTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('attribute_entity', function (Blueprint $table) {
$table->increments('id')->first();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('attribute_entity', function (Blueprint $table) {
$table->dropColumn('id');
});
}
}
make a wrapper models for nova compatibility:
Attribute.php
use Illuminate\Database\Eloquent\Relations\HasMany;
class Attribute extends \Rinvex\Attributes\Models\Attribute
{
public $timestamps = true;
/**
* Get the entities attached to this attribute.
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function attributeEntities(): HasMany
{
return parent::entities();
}
}
AttributeEntity.php
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class AttributeEntity extends \Rinvex\Attributes\Models\AttributeEntity
{
public $timestamps = true;
/**
* Get the attribute attached to this entity.
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function attribute(): BelongsTo
{
return $this->belongsTo(config('rinvex.attributes.models.attribute'));
}
}
Resources:
Nova/Attribute.php
namespace App\Nova;
use Illuminate\Http\Request;
use Laravel\Nova\Fields\HasMany;
use Laravel\Nova\Fields\Text;
use Laravel\Nova\Fields\Boolean;
use Naxon\NovaFieldSortable\Sortable;
use Naxon\NovaFieldSortable\Concerns\SortsIndexEntries;
use Laravel\Nova\Fields\Select;
class Attribute extends Resource
{
use SortsIndexEntries;
/**
* The model the resource corresponds to.
*
* @var string
*/
public static $model = Attribute::class;
/**
* The single value that should be used to represent the resource when being displayed.
*
* @var string
*/
public static $title = 'name';
/**
* The columns that should be searched.
*
* @var array
*/
public static $search = [
'slug', 'name'
];
/**
* Get the displayable label of the resource.
*
* @return string
*/
public static function label()
{
return __('Attributes');
}
/**
* Get the displayable singular label of the resource.
*
* @return string
*/
public static function singularLabel()
{
return __('Attribute');
}
/**
* Get the fields displayed by the resource.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function fields(Request $request)
{
return
[
Sortable::make(__('Sort Order'), 'id')->onlyOnIndex(),
Select::make(__('Type'), 'type')
->options(
array_combine(
array_keys(\Rinvex\Attributes\Models\Attribute::typeMap()),
array_keys(array_change_key_case(\Rinvex\Attributes\Models\Attribute::typeMap(), CASE_UPPER))
)
)
->rules('required')
,
Text::make(__('Group'), 'group')
,
Boolean::make(__('Is Required'), 'is_required')
->rules('required')
,
Boolean::make(__('Is Collection'), 'is_collection')
->rules('required')
,
Text::make(__('Default'), 'default')
,
HasMany::make(__('Attribute Entities'), 'AttributeEntities')
->rules('required'),
];
}
}
Nova/AttributeEntity.php
namespace App\Nova;
use Illuminate\Http\Request;
use Laravel\Nova\Fields\BelongsTo;
use Laravel\Nova\Fields\Select;
class AttributeEntity extends Resource
{
/**
* The model the resource corresponds to.
*
* @var string
*/
public static $model = \AttributeEntity::class;
/**
* The single value that should be used to represent the resource when being displayed.
*
* @var string
*/
public static $title = 'entity_type';
/**
* The columns that should be searched.
*
* @var array
*/
public static $search = [
'id','entity_type'
];
/**
* Get the displayable label of the resource.
*
* @return string
*/
public static function label()
{
return __('Attribute Entities');
}
/**
* Get the displayable singular label of the resource.
*
* @return string
*/
public static function singularLabel()
{
return __('Attribute Entity');
}
/**
* Get the fields displayed by the resource.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function fields(Request $request)
{
return [
BelongsTo::make(__('Attribute'), 'Attribute')
->rules('required')
,
Select::make(__('Entity Type'), 'entity_type')
->options(
array_combine(
app('rinvex.attributes.entities')->toArray(),
app('rinvex.attributes.entities')->toArray()
)
)
->rules('required')
,
// Number::make(__('Entity Id'), 'entity_id'), // not used???
];
}
}
Now you should be able to administrate the attributes in Nova.
In your models you want to add support for attributes using traits as following:
use Rinvex\Attributes\Traits\Attributable as Attributable;
use Rinvex\Support\Traits\HasTranslations as HasTranslations;
//... you code
// Trait with compatibility hack to support translatable attributes
use Attributable, HasTranslations {
Attributable::setAttribute insteadof HasTranslations;
}
In your Nova/Resource.php add
public function attributeFields()
{
$attributes = app('rinvex.attributes.attribute')::whereHas('entities', function ($query) {
$query->where('entity_type', '=', static::$model);
})
->orderBy(static::$defaultSortField, 'asc')
->get();
if (!$attributes) {
return [];
}
$fields = [];
$fields[] = Heading::make('Attributes');
foreach ($attributes as $attribute) {
$namespace = 'Laravel\Nova\Fields\\';
switch ($attribute->type) {
case 'varchar':
$type = 'Text';
break;
case 'text':
$type = 'Textarea';
break;
case 'integer':
$type = 'Number';
break;
default:
$type = 'Text';
break;
}
$type = $namespace . $type;
$fields[] = $type::make(__($attribute->name), $attribute->slug);
}
return $fields;
}
and use this in the ´fields´ method of Resources:
return array_merge([
// some fields
],
$this->attributeFields());
Now you should see the configured attributes in your Nova Resource.
Hope that helps forward and someone more experienced is able to make a package from these fragments.
@cord sounds great!
I am just getting back to this in my project. Thank you so much!
This package would help people a lot if it was made. @cord did you abandon it?
The given code still works here, hope someone can pick it up and make a package from it?
Yeap, just used it, its awesome. I misread, I thought you are going to make it :) maybe I will now.
@flakerimi would be great - am happy to contribute!
@cord I found this one : https://github.com/sunel/eav More completed than rinvex and very active, I will try it to make it work with this one first then try to convert it as package.