first upload all files
This commit is contained in:
25
Modules/Attribute/Admin/AttributeSetTabs.php
Normal file
25
Modules/Attribute/Admin/AttributeSetTabs.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Attribute\Admin;
|
||||
|
||||
use Modules\Admin\Ui\Tab;
|
||||
use Modules\Admin\Ui\Tabs;
|
||||
|
||||
class AttributeSetTabs extends Tabs
|
||||
{
|
||||
public function make()
|
||||
{
|
||||
$this->group('attribute_set_information', trans('attribute::attribute_sets.tabs.group.attribute_set_information'))
|
||||
->active()
|
||||
->add($this->general());
|
||||
}
|
||||
|
||||
private function general()
|
||||
{
|
||||
return tap(new Tab('general', trans('attribute::attribute_sets.tabs.general')), function (Tab $tab) {
|
||||
$tab->active();
|
||||
$tab->fields('name');
|
||||
$tab->view('attribute::admin.attribute_sets.tabs.general');
|
||||
});
|
||||
}
|
||||
}
|
||||
26
Modules/Attribute/Admin/AttributeTable.php
Normal file
26
Modules/Attribute/Admin/AttributeTable.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Attribute\Admin;
|
||||
|
||||
use Modules\Admin\Ui\AdminTable;
|
||||
|
||||
class AttributeTable extends AdminTable
|
||||
{
|
||||
/**
|
||||
* Make table response for the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function make()
|
||||
{
|
||||
return $this->newTable()
|
||||
->addColumn('attribute_set', function ($attribute) {
|
||||
return $attribute->attributeSet->name;
|
||||
})
|
||||
->addColumn('is_filterable', function ($attribute) {
|
||||
return $attribute->is_filterable
|
||||
? trans('attribute::admin.table.yes')
|
||||
: trans('attribute::admin.table.no');
|
||||
});
|
||||
}
|
||||
}
|
||||
46
Modules/Attribute/Admin/AttributeTabs.php
Normal file
46
Modules/Attribute/Admin/AttributeTabs.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Attribute\Admin;
|
||||
|
||||
use Modules\Admin\Ui\Tab;
|
||||
use Modules\Admin\Ui\Tabs;
|
||||
use Modules\Category\Entities\Category;
|
||||
use Modules\Attribute\Entities\AttributeSet;
|
||||
|
||||
class AttributeTabs extends Tabs
|
||||
{
|
||||
public function make()
|
||||
{
|
||||
$this->group('attribute_set_information', trans('attribute::admin.tabs.group.attribute_information'))
|
||||
->active()
|
||||
->add($this->general())
|
||||
->add($this->values());
|
||||
}
|
||||
|
||||
private function general()
|
||||
{
|
||||
return tap(new Tab('general', trans('attribute::admin.tabs.general')), function (Tab $tab) {
|
||||
$tab->active();
|
||||
$tab->weight(5);
|
||||
$tab->fields(['attribute_set_id', 'name', 'slug']);
|
||||
$tab->view('attribute::admin.attributes.tabs.general', [
|
||||
'attributeSets' => $this->getAttributeSets(),
|
||||
'categories' => Category::treeList(),
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
private function getAttributeSets()
|
||||
{
|
||||
return AttributeSet::all()->sortBy('name')->pluck('name', 'id')
|
||||
->prepend(trans('admin::admin.form.please_select'), '');
|
||||
}
|
||||
|
||||
private function values()
|
||||
{
|
||||
return tap(new Tab('values', trans('attribute::admin.tabs.values')), function (Tab $tab) {
|
||||
$tab->weight(10);
|
||||
$tab->view('attribute::admin.attributes.tabs.values');
|
||||
});
|
||||
}
|
||||
}
|
||||
60
Modules/Attribute/Admin/ProductTabsExtender.php
Normal file
60
Modules/Attribute/Admin/ProductTabsExtender.php
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Attribute\Admin;
|
||||
|
||||
use Modules\Admin\Ui\Tab;
|
||||
use Modules\Admin\Ui\Tabs;
|
||||
use Modules\Attribute\Entities\Attribute;
|
||||
use Modules\Attribute\Entities\AttributeSet;
|
||||
|
||||
class ProductTabsExtender
|
||||
{
|
||||
public function extend(Tabs $tabs)
|
||||
{
|
||||
$tabs->group('advanced_information')
|
||||
->add($this->attributes());
|
||||
}
|
||||
|
||||
private function attributes()
|
||||
{
|
||||
if (! auth()->user()->hasAccess(['admin.attributes.index'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
return tap(new Tab('attributes', trans('attribute::admin.tabs.product.attributes')), function (Tab $tab) {
|
||||
$tab->weight(30);
|
||||
$tab->fields(['attributes.*.attribute_id', 'attributes.*.values']);
|
||||
$tab->view(function ($data) {
|
||||
return view('attribute::admin.products.tabs.attributes', [
|
||||
'productAttributes' => $this->getProductAttributes($data['product']),
|
||||
'attributeSets' => $this->getAttributeSets(),
|
||||
]);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private function getProductAttributes($product)
|
||||
{
|
||||
$old = old('attributes');
|
||||
|
||||
if (is_null($old)) {
|
||||
return $product->load('attributes')->attributes;
|
||||
}
|
||||
|
||||
return $this->getOldAttributes($old);
|
||||
}
|
||||
|
||||
public function getOldAttributes($old)
|
||||
{
|
||||
return Attribute::with(['values' => function ($query) use ($old) {
|
||||
$query->whereIn('id', array_flatten(array_pluck($old, 'values')));
|
||||
}])
|
||||
->whereIn('id', array_pluck($old, 'attribute_id'))
|
||||
->get();
|
||||
}
|
||||
|
||||
private function getAttributeSets()
|
||||
{
|
||||
return AttributeSet::with('attributes.values')->get()->sortBy('name');
|
||||
}
|
||||
}
|
||||
22
Modules/Attribute/Config/assets.php
Normal file
22
Modules/Attribute/Config/assets.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Define which assets will be available through the asset manager
|
||||
|--------------------------------------------------------------------------
|
||||
| These assets are registered on the asset manager
|
||||
*/
|
||||
'all_assets' => [
|
||||
'admin.attribute.css' => ['module' => 'attribute:admin/css/attribute.css'],
|
||||
'admin.attribute.js' => ['module' => 'attribute:admin/js/attribute.js'],
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Define which default assets will always be included in your pages
|
||||
| through the asset pipeline
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
'required_assets' => [],
|
||||
];
|
||||
16
Modules/Attribute/Config/permissions.php
Normal file
16
Modules/Attribute/Config/permissions.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'admin.attributes' => [
|
||||
'index' => 'attribute::permissions.attributes.index',
|
||||
'create' => 'attribute::permissions.attributes.create',
|
||||
'edit' => 'attribute::permissions.attributes.edit',
|
||||
'destroy' => 'attribute::permissions.attributes.destroy',
|
||||
],
|
||||
'admin.attribute_sets' => [
|
||||
'index' => 'attribute::permissions.attribute_sets.index',
|
||||
'create' => 'attribute::permissions.attribute_sets.create',
|
||||
'edit' => 'attribute::permissions.attribute_sets.edit',
|
||||
'destroy' => 'attribute::permissions.attribute_sets.destroy',
|
||||
],
|
||||
];
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateAttributeSetsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('attribute_sets', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('attribute_sets');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateAttributeSetTranslationsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('attribute_set_translations', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->integer('attribute_set_id')->unsigned();
|
||||
$table->string('locale');
|
||||
$table->string('name');
|
||||
|
||||
$table->unique(['attribute_set_id', 'locale']);
|
||||
$table->foreign('attribute_set_id')->references('id')->on('attribute_sets')->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('attribute_set_translations');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateAttributesTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('attributes', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->integer('attribute_set_id')->unsigned()->index();
|
||||
$table->boolean('is_filterable');
|
||||
$table->timestamps();
|
||||
|
||||
$table->foreign('attribute_set_id')->references('id')->on('attribute_sets')->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('attributes');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateAttributeTranslationsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('attribute_translations', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->integer('attribute_id')->unsigned();
|
||||
$table->string('locale');
|
||||
$table->string('name');
|
||||
|
||||
$table->unique(['attribute_id', 'locale']);
|
||||
$table->foreign('attribute_id')->references('id')->on('attributes')->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('attribute_translations');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateProductAttributesTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('product_attributes', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->integer('product_id')->unsigned()->index();
|
||||
$table->integer('attribute_id')->unsigned()->index();
|
||||
|
||||
$table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');
|
||||
$table->foreign('attribute_id')->references('id')->on('attributes')->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('product_attributes');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateAttributeValuesTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('attribute_values', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->integer('attribute_id')->unsigned()->index();
|
||||
$table->integer('position')->unsigned();
|
||||
$table->timestamps();
|
||||
|
||||
$table->foreign('attribute_id')->references('id')->on('attributes')->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('attribute_values');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateAttributeValueTranslationsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('attribute_value_translations', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->integer('attribute_value_id')->unsigned();
|
||||
$table->string('locale');
|
||||
$table->string('value');
|
||||
|
||||
$table->unique(['attribute_value_id', 'locale']);
|
||||
$table->foreign('attribute_value_id')->references('id')->on('attribute_values')->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('attribute_value_translations');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateProductAttributeValuesTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('product_attribute_values', function (Blueprint $table) {
|
||||
$table->integer('product_attribute_id')->unsigned();
|
||||
$table->integer('attribute_value_id')->unsigned();
|
||||
|
||||
$table->primary(['product_attribute_id', 'attribute_value_id'], 'product_attribute_id_attribute_value_id_primary');
|
||||
$table->foreign('product_attribute_id')->references('id')->on('product_attributes')->onDelete('cascade');
|
||||
$table->foreign('attribute_value_id')->references('id')->on('attribute_values')->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('product_attribute_values');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateAttributeCategoriesTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('attribute_categories', function (Blueprint $table) {
|
||||
$table->integer('attribute_id')->unsigned();
|
||||
$table->integer('category_id')->unsigned();
|
||||
|
||||
$table->primary(['attribute_id', 'category_id']);
|
||||
$table->foreign('attribute_id')->references('id')->on('attributes')->onDelete('cascade');
|
||||
$table->foreign('category_id')->references('id')->on('categories')->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('attribute_categories');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class AddSlugColumnToAttributesTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('attributes', function (Blueprint $table) {
|
||||
$table->string('slug')->nullable()->unique();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('attributes', function (Blueprint $table) {
|
||||
$table->dropColumn('slug');
|
||||
});
|
||||
}
|
||||
}
|
||||
112
Modules/Attribute/Entities/Attribute.php
Normal file
112
Modules/Attribute/Entities/Attribute.php
Normal file
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Attribute\Entities;
|
||||
|
||||
use Modules\Support\Eloquent\Model;
|
||||
use Modules\Category\Entities\Category;
|
||||
use Modules\Support\Eloquent\Sluggable;
|
||||
use Modules\Support\Eloquent\Translatable;
|
||||
use Modules\Attribute\Admin\AttributeTable;
|
||||
|
||||
class Attribute extends Model
|
||||
{
|
||||
use Translatable, Sluggable;
|
||||
|
||||
/**
|
||||
* The relations to eager load on every query.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $with = ['translations'];
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = ['attribute_set_id', 'slug', 'is_filterable'];
|
||||
|
||||
/**
|
||||
* The attributes that should be cast to native types.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'is_filterable' => 'boolean',
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that are translatable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $translatedAttributes = ['name'];
|
||||
|
||||
/**
|
||||
* The attribute that will be slugged.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $slugAttribute = 'name';
|
||||
|
||||
/**
|
||||
* Perform any actions required after the model boots.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected static function booted()
|
||||
{
|
||||
static::saved(function (self $attribute) {
|
||||
$attribute->saveRelations(request()->all());
|
||||
});
|
||||
}
|
||||
|
||||
public function attributeSet()
|
||||
{
|
||||
return $this->belongsTo(AttributeSet::class);
|
||||
}
|
||||
|
||||
public function categories()
|
||||
{
|
||||
return $this->belongsToMany(Category::class, 'attribute_categories');
|
||||
}
|
||||
|
||||
public function values()
|
||||
{
|
||||
return $this->hasMany(AttributeValue::class)->orderBy('position');
|
||||
}
|
||||
|
||||
public function table()
|
||||
{
|
||||
return new AttributeTable($this->with('attributeSet'));
|
||||
}
|
||||
|
||||
public function saveRelations(array $attributes)
|
||||
{
|
||||
$this->categories()->sync(array_get($attributes, 'categories', []));
|
||||
$this->saveValues(array_get($attributes, 'values', []));
|
||||
}
|
||||
|
||||
public function saveValues($values = [])
|
||||
{
|
||||
$ids = $this->getDeleteCandidates($values);
|
||||
|
||||
if ($ids->isNotEmpty()) {
|
||||
$this->values()->whereIn('id', $ids)->delete();
|
||||
}
|
||||
|
||||
foreach (array_reset_index($values) as $index => $value) {
|
||||
$this->values()->updateOrCreate(
|
||||
['id' => $value['id']],
|
||||
$value + ['position' => $index]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function getDeleteCandidates($values = [])
|
||||
{
|
||||
return $this->values()
|
||||
->pluck('id')
|
||||
->diff(array_pluck($values, 'id'));
|
||||
}
|
||||
}
|
||||
43
Modules/Attribute/Entities/AttributeSet.php
Normal file
43
Modules/Attribute/Entities/AttributeSet.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Attribute\Entities;
|
||||
|
||||
use Modules\Admin\Ui\AdminTable;
|
||||
use Modules\Support\Eloquent\Model;
|
||||
use Modules\Support\Eloquent\Translatable;
|
||||
|
||||
class AttributeSet extends Model
|
||||
{
|
||||
use Translatable;
|
||||
|
||||
/**
|
||||
* The relations to eager load on every query.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $with = ['translations'];
|
||||
|
||||
/**
|
||||
* The attributes that aren't mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $guarded = [];
|
||||
|
||||
/**
|
||||
* The attributes that are translatable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $translatedAttributes = ['name'];
|
||||
|
||||
public function attributes()
|
||||
{
|
||||
return $this->hasMany(Attribute::class);
|
||||
}
|
||||
|
||||
public function table()
|
||||
{
|
||||
return new AdminTable($this->newQuery());
|
||||
}
|
||||
}
|
||||
15
Modules/Attribute/Entities/AttributeSetTranslation.php
Normal file
15
Modules/Attribute/Entities/AttributeSetTranslation.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Attribute\Entities;
|
||||
|
||||
use Modules\Support\Eloquent\TranslationModel;
|
||||
|
||||
class AttributeSetTranslation extends TranslationModel
|
||||
{
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = ['name'];
|
||||
}
|
||||
15
Modules/Attribute/Entities/AttributeTranslation.php
Normal file
15
Modules/Attribute/Entities/AttributeTranslation.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Attribute\Entities;
|
||||
|
||||
use Modules\Support\Eloquent\TranslationModel;
|
||||
|
||||
class AttributeTranslation extends TranslationModel
|
||||
{
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = ['name'];
|
||||
}
|
||||
32
Modules/Attribute/Entities/AttributeValue.php
Normal file
32
Modules/Attribute/Entities/AttributeValue.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Attribute\Entities;
|
||||
|
||||
use Modules\Support\Eloquent\Model;
|
||||
use Modules\Support\Eloquent\Translatable;
|
||||
|
||||
class AttributeValue extends Model
|
||||
{
|
||||
use Translatable;
|
||||
|
||||
/**
|
||||
* The relations to eager load on every query.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $with = ['translations'];
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = ['position'];
|
||||
|
||||
/**
|
||||
* The attributes that are translatable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $translatedAttributes = ['value'];
|
||||
}
|
||||
15
Modules/Attribute/Entities/AttributeValueTranslation.php
Normal file
15
Modules/Attribute/Entities/AttributeValueTranslation.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Attribute\Entities;
|
||||
|
||||
use Modules\Support\Eloquent\TranslationModel;
|
||||
|
||||
class AttributeValueTranslation extends TranslationModel
|
||||
{
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = ['value'];
|
||||
}
|
||||
56
Modules/Attribute/Entities/ProductAttribute.php
Normal file
56
Modules/Attribute/Entities/ProductAttribute.php
Normal file
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Attribute\Entities;
|
||||
|
||||
use Modules\Support\Eloquent\Model;
|
||||
|
||||
class ProductAttribute extends Model
|
||||
{
|
||||
/**
|
||||
* The relations to eager load on every query.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $with = ['attribute', 'values'];
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = ['attribute_id'];
|
||||
|
||||
/**
|
||||
* The accessors to append to the model's array form.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $appends = ['name'];
|
||||
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = false;
|
||||
|
||||
public function attribute()
|
||||
{
|
||||
return $this->belongsTo(Attribute::class);
|
||||
}
|
||||
|
||||
public function values()
|
||||
{
|
||||
return $this->hasMany(ProductAttributeValue::class, 'product_attribute_id');
|
||||
}
|
||||
|
||||
public function getNameAttribute()
|
||||
{
|
||||
return $this->attribute->name;
|
||||
}
|
||||
|
||||
public function getAttributeSetAttribute()
|
||||
{
|
||||
return $this->attribute->attributeSet->name;
|
||||
}
|
||||
}
|
||||
49
Modules/Attribute/Entities/ProductAttributeValue.php
Normal file
49
Modules/Attribute/Entities/ProductAttributeValue.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Attribute\Entities;
|
||||
|
||||
use Modules\Support\Eloquent\Model;
|
||||
|
||||
class ProductAttributeValue extends Model
|
||||
{
|
||||
/**
|
||||
* The relations to eager load on every query.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $with = ['attributeValue'];
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = ['product_attribute_id', 'attribute_id'];
|
||||
|
||||
/**
|
||||
* The accessors to append to the model's array form.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $appends = ['value'];
|
||||
|
||||
public function exists()
|
||||
{
|
||||
return ! is_null($this->attributeValue);
|
||||
}
|
||||
|
||||
public function attributeValue()
|
||||
{
|
||||
return $this->belongsTo(AttributeValue::class, 'attribute_value_id');
|
||||
}
|
||||
|
||||
public function getIdAttribute()
|
||||
{
|
||||
return $this->attributeValue->id;
|
||||
}
|
||||
|
||||
public function getValueAttribute()
|
||||
{
|
||||
return $this->attributeValue->value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Attribute\Http\Controllers\Admin;
|
||||
|
||||
use Modules\Admin\Traits\HasCrudActions;
|
||||
use Modules\Attribute\Entities\Attribute;
|
||||
use Modules\Attribute\Http\Requests\SaveAttributeRequest;
|
||||
|
||||
class AttributeController
|
||||
{
|
||||
use HasCrudActions;
|
||||
|
||||
/**
|
||||
* Model for the resource.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $model = Attribute::class;
|
||||
|
||||
/**
|
||||
* The relations to eager load on every query.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $with = ['values'];
|
||||
|
||||
/**
|
||||
* Label of the resource.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $label = 'attribute::admin.attribute';
|
||||
|
||||
/**
|
||||
* View path of the resource.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $viewPath = 'attribute::admin.attributes';
|
||||
|
||||
/**
|
||||
* Form requests for the resource.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $validation = SaveAttributeRequest::class;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Attribute\Http\Controllers\Admin;
|
||||
|
||||
use Modules\Admin\Traits\HasCrudActions;
|
||||
use Modules\Attribute\Entities\AttributeSet;
|
||||
use Modules\Attribute\Http\Requests\SaveAttributeSetRequest;
|
||||
|
||||
class AttributeSetController
|
||||
{
|
||||
use HasCrudActions;
|
||||
|
||||
/**
|
||||
* Model for the resource.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $model = AttributeSet::class;
|
||||
|
||||
/**
|
||||
* Label of the resource.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $label = 'attribute::attribute_sets.attribute_set';
|
||||
|
||||
/**
|
||||
* View path of the resource.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $viewPath = 'attribute::admin.attribute_sets';
|
||||
|
||||
/**
|
||||
* Form requests for the resource.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $validation = SaveAttributeSetRequest::class;
|
||||
}
|
||||
70
Modules/Attribute/Http/Requests/SaveAttributeRequest.php
Normal file
70
Modules/Attribute/Http/Requests/SaveAttributeRequest.php
Normal file
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Attribute\Http\Requests;
|
||||
|
||||
use Illuminate\Validation\Rule;
|
||||
use Modules\Core\Http\Requests\Request;
|
||||
use Modules\Attribute\Entities\Attribute;
|
||||
|
||||
class SaveAttributeRequest extends Request
|
||||
{
|
||||
/**
|
||||
* Available attributes.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $availableAttributes = 'attribute::attributes.attributes';
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'attribute_set_id' => ['required', Rule::exists('attribute_sets', 'id')],
|
||||
'name' => 'required',
|
||||
'slug' => $this->getSlugRules(),
|
||||
'is_filterable' => 'required|boolean',
|
||||
];
|
||||
}
|
||||
|
||||
private function getSlugRules()
|
||||
{
|
||||
$rules = $this->route()->getName() === 'admin.attributes.update'
|
||||
? ['required']
|
||||
: ['sometimes'];
|
||||
|
||||
$slug = Attribute::where('id', $this->id)->value('slug');
|
||||
|
||||
$rules[] = Rule::unique('attributes', 'slug')->ignore($slug, 'slug');
|
||||
|
||||
return $rules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get data to be validated from the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function validationData()
|
||||
{
|
||||
return request()->merge([
|
||||
'values' => $this->filter($this->values ?? []),
|
||||
])->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter attribute values.
|
||||
*
|
||||
* @param array $values
|
||||
* @return array
|
||||
*/
|
||||
private function filter($values = [])
|
||||
{
|
||||
return array_filter($values, function ($value) {
|
||||
return ! is_null($value['value']);
|
||||
});
|
||||
}
|
||||
}
|
||||
27
Modules/Attribute/Http/Requests/SaveAttributeSetRequest.php
Normal file
27
Modules/Attribute/Http/Requests/SaveAttributeSetRequest.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Attribute\Http\Requests;
|
||||
|
||||
use Modules\Core\Http\Requests\Request;
|
||||
|
||||
class SaveAttributeSetRequest extends Request
|
||||
{
|
||||
/**
|
||||
* Available attributes.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $availableAttributes = 'attribute::attributes.attribute_sets';
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'name' => 'required',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Attribute\Http\Requests;
|
||||
|
||||
use Illuminate\Validation\Rule;
|
||||
use Modules\Core\Http\Requests\Request;
|
||||
|
||||
class SaveProductAttributesRequest extends Request
|
||||
{
|
||||
/**
|
||||
* Available attributes.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $availableAttributes = 'attribute::attributes.product_attributes';
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'attributes.*.attribute_id' => ['required_with:attributes.*.values', Rule::exists('attributes', 'id')],
|
||||
'attributes.*.values' => ['required_with:attributes.*.attribute_id', Rule::exists('attribute_values', 'id')],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get data to be validated from the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function validationData()
|
||||
{
|
||||
if (empty($this->except('attributes'))) {
|
||||
return request()->all();
|
||||
}
|
||||
|
||||
return request()->merge([
|
||||
'attributes' => $this->filter($this->get('attributes', [])),
|
||||
])->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter product attributes.
|
||||
*
|
||||
* @param array $attributes
|
||||
* @return array
|
||||
*/
|
||||
private function filter($attributes = [])
|
||||
{
|
||||
return array_filter($attributes, function ($attribute) {
|
||||
return ! is_null($attribute['attribute_id']);
|
||||
});
|
||||
}
|
||||
}
|
||||
69
Modules/Attribute/Listeners/SaveProductAttributes.php
Normal file
69
Modules/Attribute/Listeners/SaveProductAttributes.php
Normal file
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Attribute\Listeners;
|
||||
|
||||
use Modules\Product\Entities\Product;
|
||||
use Modules\Attribute\Entities\ProductAttributeValue;
|
||||
|
||||
class SaveProductAttributes
|
||||
{
|
||||
/**
|
||||
* Handle the event.
|
||||
*
|
||||
* @param \Modules\Product\Entities\Product $product
|
||||
* @return void
|
||||
*/
|
||||
public function handle(Product $product)
|
||||
{
|
||||
$this->deleteProductAttributes($product);
|
||||
$this->createProductAttributes($product);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all product attributes associated with the given product.
|
||||
*
|
||||
* @param \Modules\Product\Entities\Product $product
|
||||
* @return void
|
||||
*/
|
||||
private function deleteProductAttributes(Product $product)
|
||||
{
|
||||
$product->attributes()->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create product attributes for the given product.
|
||||
*
|
||||
* @param \Modules\Product\Entities\Product $product
|
||||
* @return void
|
||||
*/
|
||||
private function createProductAttributes(Product $product)
|
||||
{
|
||||
$productAttributeValues = [];
|
||||
|
||||
foreach (request('attributes', []) as $attribute) {
|
||||
$productAttribute = $product->attributes()->create([
|
||||
'attribute_id' => $attribute['attribute_id'],
|
||||
]);
|
||||
|
||||
foreach ($attribute['values'] as $valueId) {
|
||||
$productAttributeValues[] = [
|
||||
'product_attribute_id' => $productAttribute->id,
|
||||
'attribute_value_id' => $valueId,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$this->createProductAttributeValues($productAttributeValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the given product attribute values.
|
||||
*
|
||||
* @param array $productAttributeValues
|
||||
* @return void
|
||||
*/
|
||||
private function createProductAttributeValues(array $productAttributeValues)
|
||||
{
|
||||
ProductAttributeValue::insert($productAttributeValues);
|
||||
}
|
||||
}
|
||||
29
Modules/Attribute/Providers/AttributeServiceProvider.php
Normal file
29
Modules/Attribute/Providers/AttributeServiceProvider.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Attribute\Providers;
|
||||
|
||||
use Modules\Support\Traits\AddsAsset;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Modules\Admin\Ui\Facades\TabManager;
|
||||
use Modules\Attribute\Admin\AttributeTabs;
|
||||
use Modules\Attribute\Admin\AttributeSetTabs;
|
||||
use Modules\Attribute\Admin\ProductTabsExtender;
|
||||
|
||||
class AttributeServiceProvider extends ServiceProvider
|
||||
{
|
||||
use AddsAsset;
|
||||
|
||||
/**
|
||||
* Bootstrap the application services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
TabManager::register('attributes', AttributeTabs::class);
|
||||
TabManager::register('attribute_sets', AttributeSetTabs::class);
|
||||
TabManager::extend('products', ProductTabsExtender::class);
|
||||
|
||||
$this->addAdminAssets('admin.(attributes|products).(create|edit)', ['admin.attribute.css', 'admin.attribute.js']);
|
||||
}
|
||||
}
|
||||
27
Modules/Attribute/Providers/EventServiceProvider.php
Normal file
27
Modules/Attribute/Providers/EventServiceProvider.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Attribute\Providers;
|
||||
|
||||
use Modules\Product\Entities\Product;
|
||||
use Modules\Attribute\Listeners\SaveProductAttributes;
|
||||
use Modules\Attribute\Http\Requests\SaveProductAttributesRequest;
|
||||
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
|
||||
|
||||
class EventServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Perform any actions required after the model boots.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
parent::boot();
|
||||
|
||||
Product::saving(function () {
|
||||
resolve(SaveProductAttributesRequest::class);
|
||||
});
|
||||
|
||||
Product::saved(SaveProductAttributes::class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
export default class {
|
||||
constructor() {
|
||||
this.attributeId = 0;
|
||||
this.valuesCount = 0;
|
||||
|
||||
this.addOldValues(FleetCart.data['attribute.values']);
|
||||
|
||||
if (this.valuesCount === 0) {
|
||||
this.addAttributeValue();
|
||||
}
|
||||
|
||||
this.eventListeners();
|
||||
this.sortable();
|
||||
|
||||
window.admin.removeSubmitButtonOffsetOn('#values');
|
||||
}
|
||||
|
||||
addOldValues(values = {}) {
|
||||
for (let value of values) {
|
||||
this.addAttributeValue(value);
|
||||
}
|
||||
}
|
||||
|
||||
addAttributeValue(value = { id: '', value: '' }) {
|
||||
let template = _.template($('#attribute-value-template').html());
|
||||
let html = template({ valueId: this.valuesCount++, value });
|
||||
|
||||
$('#attribute-values').append(html);
|
||||
|
||||
window.admin.tooltip();
|
||||
}
|
||||
|
||||
eventListeners() {
|
||||
$('#add-new-value').on('click', () => this.addAttributeValue());
|
||||
|
||||
$('#attribute-values').on('click', '.delete-row', (e) => {
|
||||
$(e.currentTarget).closest('tr').remove();
|
||||
});
|
||||
}
|
||||
|
||||
sortable() {
|
||||
Sortable.create(document.getElementById('attribute-values'), {
|
||||
handle: '.drag-icon',
|
||||
animation: 150,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
export default class {
|
||||
constructor() {
|
||||
this.attributeCount = 0;
|
||||
|
||||
this.addProductAttributes(FleetCart.data['product.attributes']);
|
||||
|
||||
if (this.attributeCount === 0) {
|
||||
this.addProductAttribute();
|
||||
}
|
||||
|
||||
this.addProductAttributesErrors(FleetCart.errors['product.attributes']);
|
||||
|
||||
this.eventListeners();
|
||||
this.triggerSelected();
|
||||
this.sortable();
|
||||
}
|
||||
|
||||
addProductAttributes(attributes) {
|
||||
for (let attribute of attributes) {
|
||||
this.addProductAttribute(attribute);
|
||||
}
|
||||
}
|
||||
|
||||
addProductAttribute(attribute = {}) {
|
||||
let template = _.template($('#product-attribute-template').html());
|
||||
|
||||
let html = template({ attributeId: this.attributeCount++, attribute });
|
||||
|
||||
$('#product-attributes').append(html);
|
||||
|
||||
window.admin.tooltip();
|
||||
window.admin.selectize();
|
||||
}
|
||||
|
||||
addProductAttributesErrors(errors) {
|
||||
for (let key in errors) {
|
||||
let id = $.escapeSelector(key);
|
||||
let parent = $(`#${id}`).parent();
|
||||
|
||||
parent.addClass('has-error');
|
||||
parent.append(`<span class="help-block">${errors[key][0]}</span>`);
|
||||
}
|
||||
}
|
||||
|
||||
deleteProductAttribute(e) {
|
||||
$(e.currentTarget).closest('tr').remove();
|
||||
}
|
||||
|
||||
changeProductAttributeValues(attributeEl, clearSelected = true) {
|
||||
let values = $(attributeEl).find('option:selected').data('values');
|
||||
|
||||
let id = $.escapeSelector(`attributes.${attributeEl.dataset.attributeId}.values`);
|
||||
let attributeValues = $(`#${id}`)[0].selectize;
|
||||
|
||||
if (clearSelected) {
|
||||
attributeValues.clear();
|
||||
}
|
||||
|
||||
attributeValues.clearOptions();
|
||||
|
||||
let options = attributeValues.options;
|
||||
|
||||
for (let id in values) {
|
||||
attributeValues.addOption({ id, name: values[id] });
|
||||
|
||||
for (let i in options) {
|
||||
attributeValues.addItem(options[i].value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
eventListeners() {
|
||||
$('#add-new-attribute').on('click', () => this.addProductAttribute());
|
||||
$('#product-attributes').on('click', '.delete-row', this.deleteProductAttribute);
|
||||
$('#product-attributes-wrapper').on('change', '.attribute', (e) => {
|
||||
this.changeProductAttributeValues(e.currentTarget);
|
||||
});
|
||||
}
|
||||
|
||||
triggerSelected() {
|
||||
$('.attribute').has('option:selected').each((i, el) => {
|
||||
this.changeProductAttributeValues(el, false);
|
||||
});
|
||||
}
|
||||
|
||||
sortable() {
|
||||
Sortable.create(document.getElementById('product-attributes'), {
|
||||
handle: '.drag-icon',
|
||||
animation: 150,
|
||||
});
|
||||
}
|
||||
}
|
||||
10
Modules/Attribute/Resources/assets/admin/js/main.js
Normal file
10
Modules/Attribute/Resources/assets/admin/js/main.js
Normal file
@@ -0,0 +1,10 @@
|
||||
import AttributeValues from './AttributeValues';
|
||||
import ProductAttributes from './ProductAttributes';
|
||||
|
||||
if ($('#attribute-values-wrapper').length !== 0) {
|
||||
new AttributeValues();
|
||||
}
|
||||
|
||||
if ($('#product-attributes-wrapper').length !== 0) {
|
||||
new ProductAttributes();
|
||||
}
|
||||
90
Modules/Attribute/Resources/assets/admin/sass/main.scss
Normal file
90
Modules/Attribute/Resources/assets/admin/sass/main.scss
Normal file
@@ -0,0 +1,90 @@
|
||||
#product-attributes-wrapper,
|
||||
#attribute-values-wrapper {
|
||||
margin-bottom: 15px;
|
||||
|
||||
.table {
|
||||
.form-group {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
thead th {
|
||||
&:first-child {
|
||||
width: 40px;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
width: 60px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#product-attributes-wrapper {
|
||||
.table-responsive {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.table {
|
||||
> tbody > tr {
|
||||
> td {
|
||||
vertical-align: middle;
|
||||
|
||||
&:nth-child(2) {
|
||||
width: 160px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.options {
|
||||
.drag-icon {
|
||||
margin-top: 3px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#attribute-values-wrapper {
|
||||
.table {
|
||||
> tbody > tr {
|
||||
> td {
|
||||
&:nth-child(2) {
|
||||
min-width: 150px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 767px) {
|
||||
#product-attributes-wrapper {
|
||||
.options {
|
||||
.drag-icon {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.table {
|
||||
> tbody > tr {
|
||||
border-top: 1px solid #e9e9e9;
|
||||
|
||||
> td {
|
||||
&:nth-child(2),
|
||||
&:nth-child(3),
|
||||
&:nth-child(4) {
|
||||
display: block;
|
||||
border: none;
|
||||
width: auto;
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
text-align: left;
|
||||
vertical-align: initial;
|
||||
}
|
||||
|
||||
&:nth-child(4) {
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
35
Modules/Attribute/Resources/lang/en/admin.php
Normal file
35
Modules/Attribute/Resources/lang/en/admin.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'attribute' => 'Attribute',
|
||||
'attributes' => 'Attributes',
|
||||
'table' => [
|
||||
'name' => 'Name',
|
||||
'attribute_set' => 'Attribute Set',
|
||||
'filterable' => 'Filterable',
|
||||
'yes' => 'Yes',
|
||||
'no' => 'No',
|
||||
],
|
||||
'tabs' => [
|
||||
'group' => [
|
||||
'attribute_information' => 'Attribute Information',
|
||||
],
|
||||
'general' => 'General',
|
||||
'values' => 'Values',
|
||||
'product' => [
|
||||
'attributes' => 'Attributes',
|
||||
],
|
||||
],
|
||||
'form' => [
|
||||
'use_this_attribute_for_filtering_products' => 'Use this attribute for filtering products',
|
||||
'value' => 'Value',
|
||||
'add_new_value' => 'Add New Value',
|
||||
'delete_value' => 'Delete Value',
|
||||
'product' => [
|
||||
'attribute' => 'Attribute',
|
||||
'values' => 'Values',
|
||||
'add_new_attribute' => 'Add New Attribute',
|
||||
'delete_attribute' => 'Delete Attribute',
|
||||
],
|
||||
],
|
||||
];
|
||||
15
Modules/Attribute/Resources/lang/en/attribute_sets.php
Normal file
15
Modules/Attribute/Resources/lang/en/attribute_sets.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'attribute_set' => 'Attribute Set',
|
||||
'attribute_sets' => 'Attribute Sets',
|
||||
'table' => [
|
||||
'name' => 'Name',
|
||||
],
|
||||
'tabs' => [
|
||||
'group' => [
|
||||
'attribute_set_information' => 'Attribute Set Information',
|
||||
],
|
||||
'general' => 'General',
|
||||
],
|
||||
];
|
||||
6
Modules/Attribute/Resources/lang/en/attribute_values.php
Normal file
6
Modules/Attribute/Resources/lang/en/attribute_values.php
Normal file
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'attribute_value' => 'Attribute Value',
|
||||
'attribute_values' => 'Attribute Values',
|
||||
];
|
||||
18
Modules/Attribute/Resources/lang/en/attributes.php
Normal file
18
Modules/Attribute/Resources/lang/en/attributes.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'attributes' => [
|
||||
'attribute_set_id' => 'Attribute Set',
|
||||
'name' => 'Name',
|
||||
'categories' => 'Categories',
|
||||
'slug' => 'URL',
|
||||
'is_filterable' => 'Filterable',
|
||||
],
|
||||
'attribute_sets' => [
|
||||
'name' => 'Name',
|
||||
],
|
||||
'product_attributes' => [
|
||||
'attributes.*.attribute_id' => 'Attribute',
|
||||
'attributes.*.values' => 'Values',
|
||||
],
|
||||
];
|
||||
16
Modules/Attribute/Resources/lang/en/permissions.php
Normal file
16
Modules/Attribute/Resources/lang/en/permissions.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'attributes' => [
|
||||
'index' => 'Index Attribute',
|
||||
'create' => 'Create Attribute',
|
||||
'edit' => 'Edit Attribute',
|
||||
'destroy' => 'Delete Attribute',
|
||||
],
|
||||
'attribute_sets' => [
|
||||
'index' => 'Index Attribute Set',
|
||||
'create' => 'Create Attribute Set',
|
||||
'edit' => 'Edit Attribute Set',
|
||||
'destroy' => 'Delete Attribute Set',
|
||||
],
|
||||
];
|
||||
6
Modules/Attribute/Resources/lang/en/sidebar.php
Normal file
6
Modules/Attribute/Resources/lang/en/sidebar.php
Normal file
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'attribute_sets' => 'Attribute Sets',
|
||||
'attributes' => 'Attributes',
|
||||
];
|
||||
@@ -0,0 +1,18 @@
|
||||
@extends('admin::layout')
|
||||
|
||||
@component('admin::components.page.header')
|
||||
@slot('title', trans('admin::resource.create', ['resource' => trans('attribute::attribute_sets.attribute_set')]))
|
||||
|
||||
<li><a href="{{ route('admin.attribute_sets.index') }}">{{ trans('attribute::attribute_sets.attribute_sets') }}</a></li>
|
||||
<li class="active">{{ trans('admin::resource.create', ['resource' => trans('attribute::attribute_sets.attribute_set')]) }}</li>
|
||||
@endcomponent
|
||||
|
||||
@section('content')
|
||||
<form method="POST" action="{{ route('admin.attribute_sets.store') }}" class="form-horizontal" id="attribute-set-create-form" novalidate>
|
||||
{{ csrf_field() }}
|
||||
|
||||
{!! $tabs->render(compact('attributeSet')) !!}
|
||||
</form>
|
||||
@endsection
|
||||
|
||||
@include('attribute::admin.attributes.partials.shortcuts')
|
||||
@@ -0,0 +1,20 @@
|
||||
@extends('admin::layout')
|
||||
|
||||
@component('admin::components.page.header')
|
||||
@slot('title', trans('admin::resource.edit', ['resource' => trans('attribute::attribute_sets.attribute_set')]))
|
||||
@slot('subtitle', $attributeSet->name)
|
||||
|
||||
<li><a href="{{ route('admin.attribute_sets.index') }}">{{ trans('attribute::attribute_sets.attribute_sets') }}</a></li>
|
||||
<li class="active">{{ trans('admin::resource.edit', ['resource' => trans('attribute::attribute_sets.attribute_set')]) }}</li>
|
||||
@endcomponent
|
||||
|
||||
@section('content')
|
||||
<form method="POST" action="{{ route('admin.attribute_sets.update', $attributeSet) }}" class="form-horizontal" id="attribute-set-edit-form" novalidate>
|
||||
{{ csrf_field() }}
|
||||
{{ method_field('put') }}
|
||||
|
||||
{!! $tabs->render(compact('attributeSet')) !!}
|
||||
</form>
|
||||
@endsection
|
||||
|
||||
@include('attribute::admin.attributes.partials.shortcuts')
|
||||
@@ -0,0 +1,38 @@
|
||||
@extends('admin::layout')
|
||||
|
||||
@component('admin::components.page.header')
|
||||
@slot('title', trans('attribute::attribute_sets.attribute_sets'))
|
||||
|
||||
<li class="active">{{ trans('attribute::attribute_sets.attribute_sets') }}</li>
|
||||
@endcomponent
|
||||
|
||||
@component('admin::components.page.index_table')
|
||||
@slot('buttons', ['create'])
|
||||
@slot('resource', 'attribute_sets')
|
||||
@slot('name', trans('attribute::attribute_sets.attribute_set'))
|
||||
|
||||
@component('admin::components.table')
|
||||
@slot('thead')
|
||||
<tr>
|
||||
@include('admin::partials.table.select_all')
|
||||
|
||||
<th>{{ trans('admin::admin.table.id') }}</th>
|
||||
<th>{{ trans('attribute::attribute_sets.table.name') }}</th>
|
||||
<th data-sort>{{ trans('admin::admin.table.created') }}</th>
|
||||
</tr>
|
||||
@endslot
|
||||
@endcomponent
|
||||
@endcomponent
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
new DataTable('#attribute_sets-table .table', {
|
||||
columns: [
|
||||
{ data: 'checkbox', orderable: false, searchable: false, width: '3%' },
|
||||
{ data: 'id', width: '5%' },
|
||||
{ data: 'name', name: 'translations.name', orderable: false, defaultContent: '' },
|
||||
{ data: 'created', name: 'created_at', width: '30%' },
|
||||
],
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
@@ -0,0 +1,14 @@
|
||||
@push('shortcuts')
|
||||
<dl class="dl-horizontal">
|
||||
<dt><code>b</code></dt>
|
||||
<dd>{{ trans('admin::admin.shortcuts.back_to_index', ['name' => trans('attribute::attribute_sets.attribute_set')]) }}</dd>
|
||||
</dl>
|
||||
@endpush
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
keypressAction([
|
||||
{ key: 'b', route: "{{ route('admin.attribute_sets.index') }}" }
|
||||
]);
|
||||
</script>
|
||||
@endpush
|
||||
@@ -0,0 +1,5 @@
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
{{ Form::text('name', trans('attribute::attributes.attribute_sets.name'), $errors, $attributeSet, ['required' => true]) }}
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,18 @@
|
||||
@extends('admin::layout')
|
||||
|
||||
@component('admin::components.page.header')
|
||||
@slot('title', trans('admin::resource.create', ['resource' => trans('attribute::admin.attribute')]))
|
||||
|
||||
<li><a href="{{ route('admin.attributes.index') }}">{{ trans('attribute::admin.attributes') }}</a></li>
|
||||
<li class="active">{{ trans('admin::resource.create', ['resource' => trans('attribute::admin.attribute')]) }}</li>
|
||||
@endcomponent
|
||||
|
||||
@section('content')
|
||||
<form method="POST" action="{{ route('admin.attributes.store') }}" class="form-horizontal" id="attribute-create-form" novalidate>
|
||||
{{ csrf_field() }}
|
||||
|
||||
{!! $tabs->render(compact('attribute')) !!}
|
||||
</form>
|
||||
@endsection
|
||||
|
||||
@include('attribute::admin.attributes.partials.shortcuts')
|
||||
@@ -0,0 +1,20 @@
|
||||
@extends('admin::layout')
|
||||
|
||||
@component('admin::components.page.header')
|
||||
@slot('title', trans('admin::resource.edit', ['resource' => trans('attribute::admin.attribute')]))
|
||||
@slot('subtitle', $attribute->name)
|
||||
|
||||
<li><a href="{{ route('admin.attributes.index') }}">{{ trans('attribute::admin.attributes') }}</a></li>
|
||||
<li class="active">{{ trans('admin::resource.edit', ['resource' => trans('attribute::admin.attribute')]) }}</li>
|
||||
@endcomponent
|
||||
|
||||
@section('content')
|
||||
<form method="POST" action="{{ route('admin.attributes.update', $attribute) }}" class="form-horizontal" id="attribute-edit-form" novalidate>
|
||||
{{ csrf_field() }}
|
||||
{{ method_field('put') }}
|
||||
|
||||
{!! $tabs->render(compact('attribute')) !!}
|
||||
</form>
|
||||
@endsection
|
||||
|
||||
@include('attribute::admin.attributes.partials.shortcuts')
|
||||
@@ -0,0 +1,42 @@
|
||||
@extends('admin::layout')
|
||||
|
||||
@component('admin::components.page.header')
|
||||
@slot('title', trans('attribute::admin.attributes'))
|
||||
|
||||
<li class="active">{{ trans('attribute::admin.attributes') }}</li>
|
||||
@endcomponent
|
||||
|
||||
@component('admin::components.page.index_table')
|
||||
@slot('buttons', ['create'])
|
||||
@slot('resource', 'attributes')
|
||||
@slot('name', trans('attribute::admin.attribute'))
|
||||
|
||||
@component('admin::components.table')
|
||||
@slot('thead')
|
||||
<tr>
|
||||
@include('admin::partials.table.select_all')
|
||||
|
||||
<th>{{ trans('admin::admin.table.id') }}</th>
|
||||
<th>{{ trans('attribute::admin.table.name') }}</th>
|
||||
<th>{{ trans('attribute::admin.table.attribute_set') }}</th>
|
||||
<th>{{ trans('attribute::admin.table.filterable') }}</th>
|
||||
<th data-sort>{{ trans('admin::admin.table.created') }}</th>
|
||||
</tr>
|
||||
@endslot
|
||||
@endcomponent
|
||||
@endcomponent
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
new DataTable('#attributes-table .table', {
|
||||
columns: [
|
||||
{ data: 'checkbox', orderable: false, searchable: false, width: '3%' },
|
||||
{ data: 'id', width: '5%' },
|
||||
{ data: 'name', name: 'translations.name', orderable: false, defaultContent: '' },
|
||||
{ data: 'attribute_set', name: 'attributeSet.name', searchable: false, orderable: false, defaultContent: '' },
|
||||
{ data: 'is_filterable', name: 'is_filterable', searchable: false, orderable: false },
|
||||
{ data: 'created', name: 'created_at' },
|
||||
],
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
@@ -0,0 +1,14 @@
|
||||
@push('shortcuts')
|
||||
<dl class="dl-horizontal">
|
||||
<dt><code>b</code></dt>
|
||||
<dd>{{ trans('admin::admin.shortcuts.back_to_index', ['name' => trans('attribute::admin.attribute')]) }}</dd>
|
||||
</dl>
|
||||
@endpush
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
keypressAction([
|
||||
{ key: 'b', route: "{{ route('admin.attributes.index') }}" }
|
||||
]);
|
||||
</script>
|
||||
@endpush
|
||||
@@ -0,0 +1,13 @@
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
{{ Form::select('attribute_set_id', trans('attribute::attributes.attributes.attribute_set_id'), $errors, $attributeSets, $attribute, ['required' => true]) }}
|
||||
{{ Form::text('name', trans('attribute::attributes.attributes.name'), $errors, $attribute, ['required' => true]) }}
|
||||
{{ Form::select('categories', trans('attribute::attributes.attributes.categories'), $errors, $categories, $attribute, ['class' => 'selectize prevent-creation', 'multiple' => true]) }}
|
||||
|
||||
@if ($attribute->exists)
|
||||
{{ Form::text('slug', trans('attribute::attributes.attributes.slug'), $errors, $attribute, ['required' => true]) }}
|
||||
@endif
|
||||
|
||||
{{ Form::checkbox('is_filterable', trans('attribute::attributes.attributes.is_filterable'), trans('attribute::admin.form.use_this_attribute_for_filtering_products'), $errors, $attribute) }}
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,24 @@
|
||||
<script type="text/html" id="attribute-value-template">
|
||||
<tr>
|
||||
<td class="text-center">
|
||||
<span class="drag-icon">
|
||||
<i class="fa"></i>
|
||||
<i class="fa"></i>
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<input type="hidden" name="values[<%- valueId %>][id]" value="<%- value.id %>">
|
||||
|
||||
<div class="form-group">
|
||||
<input type="text" name="values[<%- valueId %>][value]" value="<%- value.value %>" class="form-control">
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td class="text-center">
|
||||
<button type="button" class="btn btn-default delete-row" data-toggle="tooltip" data-title="{{ trans('attribute::admin.form.delete_value') }}">
|
||||
<i class="fa fa-trash"></i>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</script>
|
||||
@@ -0,0 +1,29 @@
|
||||
<div id="attribute-values-wrapper">
|
||||
<div class="table-responsive">
|
||||
<table class="options table table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>{{ trans('attribute::admin.form.value') }}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody id="attribute-values">
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<button type="button" class="btn btn-default" id="add-new-value">
|
||||
{{ trans('attribute::admin.form.add_new_value') }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@include('attribute::admin.attributes.tabs.templates.attribute_value')
|
||||
|
||||
@push('globals')
|
||||
<script>
|
||||
FleetCart.data['attribute.values'] = {!! old_json('values', $attribute->values) !!};
|
||||
</script>
|
||||
@endpush
|
||||
@@ -0,0 +1,31 @@
|
||||
<div id="product-attributes-wrapper">
|
||||
<div class="table-responsive">
|
||||
<table class="options table table-bordered">
|
||||
<thead class="hidden-xs">
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>{{ trans('attribute::admin.form.product.attribute') }}</th>
|
||||
<th>{{ trans('attribute::admin.form.product.values') }}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody id="product-attributes">
|
||||
{{-- Product attributes will be added here dynamically using JS --}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<button type="button" class="btn btn-default" id="add-new-attribute">
|
||||
{{ trans('attribute::admin.form.product.add_new_attribute') }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@include('attribute::admin.products.tabs.templates.attribute')
|
||||
|
||||
@push('globals')
|
||||
<script>
|
||||
FleetCart.data['product.attributes'] = @json($productAttributes);
|
||||
FleetCart.errors['product.attributes'] = @json($errors->get('attributes.*'), JSON_FORCE_OBJECT);
|
||||
</script>
|
||||
@endpush
|
||||
@@ -0,0 +1,48 @@
|
||||
<script type="text/html" id="product-attribute-template">
|
||||
<tr>
|
||||
<td class="text-center">
|
||||
<span class="drag-icon">
|
||||
<i class="fa"></i>
|
||||
<i class="fa"></i>
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<div class="form-group">
|
||||
<label for="attributes.<%- attributeId %>.attribute_id" class="visible-xs">{{ trans('attribute::admin.form.product.attribute') }}</label>
|
||||
<select name="attributes[<%- attributeId %>][attribute_id]" class="form-control attribute custom-select-black" id="attributes.<%- attributeId %>.attribute_id" data-attribute-id="<%- attributeId %>">
|
||||
<option value="">{{ trans('admin::admin.form.please_select') }}</option>
|
||||
|
||||
@foreach ($attributeSets as $attributeSet)
|
||||
<optgroup label="{{ $attributeSet->name }}">
|
||||
@foreach ($attributeSet->attributes as $attribute)
|
||||
<option value="{{ $attribute->id }}" data-values="{{ json_encode($attribute->values->pluck('value', 'id'), JSON_FORCE_OBJECT) }}" <%= (attribute.attribute_id || attribute.id) == {{ $attribute->id }} ? 'selected' : '' %>>
|
||||
{{ $attribute->name }}
|
||||
</option>
|
||||
@endforeach
|
||||
</optgroup>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<div class="form-group">
|
||||
<label for="attributes.<%- attributeId %>.values" class="visible-xs">{{ trans('attribute::admin.form.product.values') }}</label>
|
||||
<select name="attributes[<%- attributeId %>][values][]" class="form-control selectize prevent-creation" id="attributes.<%- attributeId %>.values" multiple>
|
||||
<% _.each(attribute.values, function (value) { %>
|
||||
<option value="<%- value.attribute_value_id || value.id %>" selected>
|
||||
<%- value.value || value.attribute_value.value %>
|
||||
</option>
|
||||
<% }); %>
|
||||
</select>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td class="text-center">
|
||||
<button type="button" class="btn btn-default delete-row" data-toggle="tooltip" data-title="{{ trans('attribute::admin.form.product.delete_attribute') }}">
|
||||
<i class="fa fa-trash"></i>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</script>
|
||||
75
Modules/Attribute/Routes/admin.php
Normal file
75
Modules/Attribute/Routes/admin.php
Normal file
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::get('attributes', [
|
||||
'as' => 'admin.attributes.index',
|
||||
'uses' => 'AttributeController@index',
|
||||
'middleware' => 'can:admin.attributes.index',
|
||||
]);
|
||||
|
||||
Route::get('attributes/create', [
|
||||
'as' => 'admin.attributes.create',
|
||||
'uses' => 'AttributeController@create',
|
||||
'middleware' => 'can:admin.attributes.create',
|
||||
]);
|
||||
|
||||
Route::post('attributes', [
|
||||
'as' => 'admin.attributes.store',
|
||||
'uses' => 'AttributeController@store',
|
||||
'middleware' => 'can:admin.attributes.create',
|
||||
]);
|
||||
|
||||
Route::get('attributes/{id}/edit', [
|
||||
'as' => 'admin.attributes.edit',
|
||||
'uses' => 'AttributeController@edit',
|
||||
'middleware' => 'can:admin.attributes.edit',
|
||||
]);
|
||||
|
||||
Route::put('attributes/{id}', [
|
||||
'as' => 'admin.attributes.update',
|
||||
'uses' => 'AttributeController@update',
|
||||
'middleware' => 'can:admin.attributes.edit',
|
||||
]);
|
||||
|
||||
Route::delete('attributes/{ids?}', [
|
||||
'as' => 'admin.attributes.destroy',
|
||||
'uses' => 'AttributeController@destroy',
|
||||
'middleware' => 'can:admin.attributes.destroy',
|
||||
]);
|
||||
|
||||
Route::get('attributes-sets', [
|
||||
'as' => 'admin.attribute_sets.index',
|
||||
'uses' => 'AttributeSetController@index',
|
||||
'middleware' => 'can:admin.attribute_sets.index',
|
||||
]);
|
||||
|
||||
Route::get('attributes-sets/create', [
|
||||
'as' => 'admin.attribute_sets.create',
|
||||
'uses' => 'AttributeSetController@create',
|
||||
'middleware' => 'can:admin.attribute_sets.create',
|
||||
]);
|
||||
|
||||
Route::post('attributes-sets', [
|
||||
'as' => 'admin.attribute_sets.store',
|
||||
'uses' => 'AttributeSetController@store',
|
||||
'middleware' => 'can:admin.attribute_sets.create',
|
||||
]);
|
||||
|
||||
Route::get('attributes-sets/{id}/edit', [
|
||||
'as' => 'admin.attribute_sets.edit',
|
||||
'uses' => 'AttributeSetController@edit',
|
||||
'middleware' => 'can:admin.attribute_sets.edit',
|
||||
]);
|
||||
|
||||
Route::put('attributes-sets/{id}', [
|
||||
'as' => 'admin.attribute_sets.update',
|
||||
'uses' => 'AttributeSetController@update',
|
||||
'middleware' => 'can:admin.attribute_sets.edit',
|
||||
]);
|
||||
|
||||
Route::delete('attributes-sets/{ids?}', [
|
||||
'as' => 'admin.attribute_sets.destroy',
|
||||
'uses' => 'AttributeSetController@destroy',
|
||||
'middleware' => 'can:admin.attribute_sets.destroy',
|
||||
]);
|
||||
36
Modules/Attribute/Sidebar/SidebarExtender.php
Normal file
36
Modules/Attribute/Sidebar/SidebarExtender.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Attribute\Sidebar;
|
||||
|
||||
use Maatwebsite\Sidebar\Item;
|
||||
use Maatwebsite\Sidebar\Menu;
|
||||
use Maatwebsite\Sidebar\Group;
|
||||
use Modules\Admin\Sidebar\BaseSidebarExtender;
|
||||
|
||||
class SidebarExtender extends BaseSidebarExtender
|
||||
{
|
||||
public function extend(Menu $menu)
|
||||
{
|
||||
$menu->group(trans('admin::sidebar.content'), function (Group $group) {
|
||||
$group->item(trans('product::sidebar.products'), function (Item $item) {
|
||||
// attributes
|
||||
$item->item(trans('attribute::sidebar.attributes'), function (Item $item) {
|
||||
$item->weight(15);
|
||||
$item->route('admin.attributes.index');
|
||||
$item->authorize(
|
||||
$this->auth->hasAccess('admin.attributes.index')
|
||||
);
|
||||
});
|
||||
|
||||
// attribute sets
|
||||
$item->item(trans('attribute::sidebar.attribute_sets'), function (Item $item) {
|
||||
$item->weight(20);
|
||||
$item->route('admin.attribute_sets.index');
|
||||
$item->authorize(
|
||||
$this->auth->hasAccess('admin.attribute_sets.index')
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
27
Modules/Attribute/composer.json
Normal file
27
Modules/Attribute/composer.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"name": "fleetcart/attribute",
|
||||
"description": "The FleetCart Attribute Module.",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Envay Soft",
|
||||
"email": "envaysoft@gmail.com"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": "^8.0.2"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Modules\\Attribute\\": ""
|
||||
}
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0.x-dev"
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"sort-packages": true
|
||||
},
|
||||
"minimum-stability": "dev"
|
||||
}
|
||||
10
Modules/Attribute/module.json
Normal file
10
Modules/Attribute/module.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "Attribute",
|
||||
"alias": "attribute",
|
||||
"description": "The FleetCart Attribute Module.",
|
||||
"priority": 100,
|
||||
"providers": [
|
||||
"Modules\\Attribute\\Providers\\AttributeServiceProvider",
|
||||
"Modules\\Attribute\\Providers\\EventServiceProvider"
|
||||
]
|
||||
}
|
||||
8
Modules/Attribute/webpack.mix.js
Normal file
8
Modules/Attribute/webpack.mix.js
Normal file
@@ -0,0 +1,8 @@
|
||||
let mix = require('laravel-mix');
|
||||
let execSync = require('child_process').execSync;
|
||||
|
||||
mix.js(`${__dirname}/Resources/assets/admin/js/main.js`, `${__dirname}/Assets/admin/js/attribute.js`)
|
||||
.sass(`${__dirname}/Resources/assets/admin/sass/main.scss`, `${__dirname}/Assets/admin/css/attribute.css`)
|
||||
.then(() => {
|
||||
execSync(`npm run rtlcss ${__dirname}/Assets/admin/css/attribute.css ${__dirname}/Assets/admin/css/attribute.rtl.css`);
|
||||
});
|
||||
Reference in New Issue
Block a user