Merge pull request #12 from jitendra-webkul/jitendra

Product page
This commit is contained in:
JItendra Singh 2018-08-01 11:42:26 +05:30 committed by GitHub
commit 0867d34eb2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 222 additions and 19 deletions

View File

@ -61,6 +61,10 @@ Route::group(['middleware' => ['web']], function () {
'view' => 'admin::catalog.products.edit'
])->name('admin.catalog.products.edit');
Route::put('/products/edit/{id}', 'Webkul\Product\Http\Controllers\ProductController@update')->defaults('_config', [
'redirect' => 'admin.catalog.products.index'
])->name('admin.catalog.products.update');
// Catalog Category Routes
Route::get('/categories', 'Webkul\Category\Http\Controllers\CategoryController@index')->defaults('_config', [

View File

@ -0,0 +1,58 @@
<?php
namespace Webkul\Admin;
class ProductFormAccordian {
public $items = [];
/**
* Shortcut method for create a Product Form Accordian with a callback.
* This will allow you to do things like fire an event on creation.
*
* @param callable $callback Callback to use after the accordian creation
* @return object
*/
public static function create($callback) {
$accordian = new ProductFormAccordian();
$callback($accordian);
$accordian->items = $accordian->sortItems($accordian->items);
return $accordian;
}
/**
* Add a accordian item to the item stack
*
* @param string $key Dot seperated heirarchy
* @param string $name Text for the anchor
* @param string $view Blade file for accordian
* @param integer $sort Sorting index for the items
*/
public function add($key, $name, $view, $sort = 0)
{
array_push($this->items, [
'key' => $key,
'name' => $name,
'view' => $view,
'sort' => $sort
]);
}
/**
* Method to sort through the acl items and put them in order
*
* @return void
*/
public function sortItems($items) {
usort($items, function($a, $b) {
if ($a['sort'] == $b['sort']) {
return 0;
}
return ($a['sort'] < $b['sort']) ? -1 : 1;
});
return $items;
}
}

View File

@ -40,6 +40,12 @@ class AdminServiceProvider extends ServiceProvider
*/
protected function composeView()
{
view()->composer(['admin::catalog.products.create', 'admin::catalog.products.edit'], function ($view) {
$accordians = current(Event::fire('admin.catalog.products.accordian.create'));
$view->with('form_accordians', $accordians);
});
view()->composer(['admin::layouts.nav-left', 'admin::layouts.nav-aside', 'admin::layouts.tabs'], function ($view) {
$menu = current(Event::fire('admin.menu.create'));

View File

@ -6,6 +6,7 @@ use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\View;
use Webkul\Ui\Menu;
use Webkul\Admin\ProductFormAccordian;
class EventServiceProvider extends ServiceProvider
{
@ -21,6 +22,8 @@ class EventServiceProvider extends ServiceProvider
$this->buildACL();
$this->registerACL();
$this->createProductFormAccordian();
}
/**
@ -110,4 +113,22 @@ class EventServiceProvider extends ServiceProvider
View::share('acl', app('acl'));
}
/**
* This method fires an event for accordian creation, any package can add their accordian item by listening to the admin.catalog.products.accordian.build event
*
* @return void
*/
public function createProductFormAccordian()
{
Event::listen('admin.catalog.products.accordian.create', function() {
return ProductFormAccordian::create(function($accordian) {
Event::fire('admin.catalog.products.accordian.build', $accordian);
});
});
Event::listen('admin.catalog.products.accordian.build', function($accordian) {
$accordian->add('categories', 'Categories', 'admin::catalog.products.accordians.categories', 1);
});
}
}

View File

@ -0,0 +1,6 @@
<accordian :title="'{{ __($accordian['name']) }}'" :active="true">
<div slot="body">
</div>
</accordian>

View File

@ -0,0 +1,4 @@
<div class="control-group">
<label for="sku">{{ $attribute->admin_name }}</label>
<input type="text" class="control" id="sku" name="sku"/>
</div>

View File

@ -35,6 +35,7 @@
@csrf()
<?php $familyId = app('request')->input('family') ?>
<?php $sku = app('request')->input('sku') ?>
<accordian :title="'{{ __('admin::app.catalog.products.general') }}'" :active="true">
<div slot="body">
@ -57,7 +58,7 @@
<select class="control" v-validate="'required'" id="attribute_family_id" name="attribute_family_id" {{ $familyId ? 'disabled' : '' }}>
<option value=""></option>
@foreach($families as $family)
<option value="{{ $family->id }}" {{ $familyId == $family->id ? 'selected' : '' }}>{{ $family->name }}</option>
<option value="{{ $family->id }}" {{ ($familyId == $family->id || old('attribute_family_id') == $family->id) ? 'selected' : '' }}>{{ $family->name }}</option>
@endforeach
</select>
@ -67,13 +68,11 @@
<span class="control-error" v-if="errors.has('attribute_family_id')">@{{ errors.first('attribute_family_id') }}</span>
</div>
@if($familyId)
<div class="control-group" :class="[errors.has('sku') ? 'has-error' : '']">
<label for="sku">{{ __('admin::app.catalog.products.sku') }}</label>
<input type="text" v-validate="'required'" class="control" id="sku" name="sku" value="{{ old('sku') }}"/>
<span class="control-error" v-if="errors.has('sku')">@{{ errors.first('sku') }}</span>
</div>
@endif
<div class="control-group" :class="[errors.has('sku') ? 'has-error' : '']">
<label for="sku">{{ __('admin::app.catalog.products.sku') }}</label>
<input type="text" v-validate="'required'" class="control" id="sku" name="sku" value="{{ $sku ?: old('sku') }}"/>
<span class="control-error" v-if="errors.has('sku')">@{{ errors.first('sku') }}</span>
</div>
</div>
</accordian>
@ -130,8 +129,14 @@
@section('javascript')
<script>
(function() {
$(document).ready(function () {
$('.label .cross-icon').on('click', function(e) {
$(e.target).parent().remove();
})
})();
$('.actions .trash-icon').on('click', function(e) {
$(e.target).parents('tr').remove();
})
});
</script>
@stop

View File

@ -2,11 +2,11 @@
@section('content')
<div class="content">
<form method="POST" action="{{ route('admin.catalog.products.store') }}" @submit.prevent="onSubmit">
<form method="POST" action="{{ route('admin.catalog.products.update', $product->id) }}" @submit.prevent="onSubmit">
<div class="page-header">
<div class="page-title">
<h1>{{ __('admin::app.catalog.products.add-title') }}</h1>
<h1>{{ __('admin::app.catalog.products.edit-title') }}</h1>
</div>
<div class="page-action">
@ -19,7 +19,31 @@
<div class="page-content">
@csrf()
@foreach($product->attribute_family->attribute_groups as $attributeGroup)
@if(count($attributeGroup->attributes))
<accordian :title="'{{ __($attributeGroup->name) }}'" :active="true">
<div slot="body">
@foreach($attributeGroup->attributes as $attribute)
@if(view()->exists($typeView = 'admin::catalog.products.attribute-types.' . $attribute->type))
@include ($typeView)
@endif
@endforeach
</div>
</accordian>
@endif
@endforeach
@foreach($form_accordians->items as $accordian)
@include ($accordian['view'])
@endforeach
</div>
</form>

View File

@ -25,9 +25,11 @@ class CreateProductAttributeValueTable extends Migration
$table->json('json_value')->nullable();
$table->integer('product_id')->unsigned();
$table->integer('attribute_id')->unsigned();
$table->integer('channel_id')->unsigned();
$table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');
$table->foreign('attribute_id')->references('id')->on('attributes')->onDelete('cascade');
$table->unique(['locale', 'attribute_id', 'product_id']);
$table->foreign('channel_id')->references('id')->on('channels')->onDelete('cascade');
$table->unique(['channel_id', 'locale', 'attribute_id', 'product_id'], 'chanel_locale_attribute_value_index_unique');
});
}

View File

@ -85,15 +85,20 @@ class ProductController extends Controller
*/
public function store()
{
if(!request()->get('family') && request()->input('type') == 'configurable') {
return redirect(url()->current() . '?family=' . request()->input('attribute_family_id'));
if(!request()->get('family') && request()->input('type') == 'configurable' && request()->input('sku') != '') {
return redirect(url()->current() . '?family=' . request()->input('attribute_family_id') . '&sku=' . request()->input('sku'));
}
if(request()->input('type') == 'configurable' && (!request()->has('super_attributes') || !count(request()->get('super_attributes')))) {
session()->flash('error', 'Please select atleast one configurable attribute.');
return back();
}
$this->validate(request(), [
'type' => 'required',
'attribute_family_id' => 'required',
'sku' => ['required', 'unique:products,sku', new \Webkul\Core\Contracts\Validations\Slug],
'super_attributes' => 'required|array|min:1'
'sku' => ['required', 'unique:products,sku', new \Webkul\Core\Contracts\Validations\Slug]
]);
$product = $this->product->create(request()->all());
@ -113,6 +118,8 @@ class ProductController extends Controller
{
$product = $this->product->findOrFail($id);
dd($product);
return view($this->_config['view'], compact('product'));
}

View File

@ -6,11 +6,22 @@ use Illuminate\Database\Eloquent\Model;
use Webkul\Attribute\Models\Attribute;
use Webkul\Category\Models\Category;
use Webkul\Inventory\Models\InventorySource;
use Webkul\Attribute\Models\AttributeFamily;
class Product extends Model
{
protected $fillable = ['type', 'attribute_family_id', 'sku'];
protected $with = ['super_attributes'];
/**
* Get the product attribute family that owns the product.
*/
public function attribute_family()
{
return $this->belongsTo(AttributeFamily::class);
}
/**
* The categories that belong to the product.
*/
@ -58,4 +69,12 @@ class Product extends Model
{
return $this->belongsToMany(self::class, 'product_cross_sells');
}
public function __get($name) {
// if(array_key_exists($name, $this->data)) {
// return $this->data[$name];
// }
return null;
}
}

View File

@ -0,0 +1,41 @@
<?php
namespace Webkul\Product\Observers;
use Webkul\Product\Models\Product;
class ProductObserver
{
/**
* Handle to the product "created" event.
*
* @param \App\Product $product
* @return void
*/
public function created(Product $product)
{
}
/**
* Handle the product "updated" event.
*
* @param \App\Product $product
* @return void
*/
public function updated(Product $product)
{
//
}
/**
* Handle the product "deleted" event.
*
* @param \App\Product $product
* @return void
*/
public function deleted(Product $product)
{
//
}
}

View File

@ -4,6 +4,8 @@ namespace Webkul\Product\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Routing\Router;
use Webkul\Product\Models\Product;
use Webkul\Product\Observers\ProductObserver;
class ProductServiceProvider extends ServiceProvider
{
@ -15,6 +17,8 @@ class ProductServiceProvider extends ServiceProvider
public function boot(Router $router)
{
$this->loadMigrationsFrom(__DIR__ . '/../Database/Migrations');
Product::observe(ProductObserver::class);
}
/**

View File

@ -30,8 +30,10 @@ class ProductRepository extends Repository
{
$product = $this->model->create($data);
foreach ($data['super_attributes'] as $attributeId => $attribute) {
$product->super_attributes()->attach($attributeId);
if(isset($data['super_attributes'])) {
foreach ($data['super_attributes'] as $attributeId => $attribute) {
$product->super_attributes()->attach($attributeId);
}
}
return $product;