Merging with master

This commit is contained in:
prashant-webkul 2018-08-09 17:44:36 +05:30
commit 9e960ec0ad
16 changed files with 303 additions and 42 deletions

View File

@ -13,7 +13,7 @@ return [
|
*/
'default' => env('FILESYSTEM_DRIVER', 'local'),
'default' => env('FILESYSTEM_DRIVER', 'public'),
/*
|--------------------------------------------------------------------------
@ -51,7 +51,7 @@ return [
'public' => [
'driver' => 'local',
'root' => storage_path('app/public'),
'url' => env('APP_URL').'/storage',
'url' => env('APP_URL').'/public/storage',
'visibility' => 'public',
],

View File

@ -131,13 +131,13 @@
</select>
</div>
<!--<div class="control-group">
<div class="control-group">
<label for="value_per_channel">{{ __('admin::app.catalog.attributes.value_per_channel') }}</label>
<select class="control" id="value_per_channel" name="value_per_channel">
<option value="0">{{ __('admin::app.catalog.attributes.no') }}</option>
<option value="1">{{ __('admin::app.catalog.attributes.yes') }}</option>
</select>
</div>-->
</div>
<div class="control-group">
<label for="is_filterable">{{ __('admin::app.catalog.attributes.is_filterable') }}</label>

View File

@ -174,7 +174,7 @@
<input type="hidden" name="value_per_locale" value="{{ $attribute->value_per_locale }}"/>
</div>
<!--<div class="control-group">
<div class="control-group">
<label for="value_per_channel">{{ __('admin::app.catalog.attributes.value_per_channel') }}</label>
<select class="control" id="value_per_channel" name="value_per_channel" disabled>
<option value="0" {{ $attribute->value_per_channel ? '' : 'selected' }}>
@ -185,7 +185,7 @@
</option>
</select>
<input type="hidden" name="value_per_channel" value="{{ $attribute->value_per_channel }}"/>
</div>-->
</div>
<div class="control-group">
<label for="is_filterable">{{ __('admin::app.catalog.attributes.is_filterable') }}</label>

View File

@ -1,7 +1,7 @@
<accordian :title="'{{ __($accordian['name']) }}'" :active="true">
<div slot="body">
<image-wrapper :button-label="'{{ __('admin::app.catalog.products.add-image-btn-title') }}'" input-name="images" multiple="true"></image-wrapper>
<image-wrapper :button-label="'{{ __('admin::app.catalog.products.add-image-btn-title') }}'" input-name="images" :images='@json($product->images)'></image-wrapper>
</div>
</accordian>

View File

@ -9,7 +9,7 @@
<?php $locale = request()->get('locale') ?: app()->getLocale(); ?>
<?php $channel = request()->get('channel') ?: channel()->getChannel(); ?>
<form method="POST" action="" @submit.prevent="onSubmit">
<form method="POST" action="" @submit.prevent="onSubmit" enctype="multipart/form-data">
<div class="page-header">
@ -133,6 +133,7 @@
@section('javascript')
<script>
$(document).ready(function () {
$('#channel-switcher, #locale-switcher').on('change', function (e) {
$('#channel-switcher').val()

View File

@ -21,7 +21,11 @@ class Channel
public function getCurrentChannel() {
//just retrieve only three columns id, name and code
$current_channel = collect(ChannelModel::select('id','name','code')->first());
$current_channel = collect(ChannelModel::select('id', 'name', 'code')->first());
return $current_channel;
}
public function getChannelModel() {
return ChannelModel::first();
}
}

View File

@ -15,9 +15,9 @@ class CreateProductImagesTable extends Migration
{
Schema::create('product_images', function (Blueprint $table) {
$table->increments('id');
$table->string('type');
$table->string('type')->nullable();
$table->string('path');
$table->integer('product_id')->unsigned()->nullable();
$table->integer('product_id')->unsigned();
$table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');
});
}

View File

@ -161,8 +161,6 @@ class ProductController extends Controller
*/
public function update(ProductForm $request, $id)
{
dd(request()->all());
$this->product->update(request()->all(), $id);
session()->flash('success', 'Product updated successfully.');

View File

@ -4,12 +4,13 @@ namespace Webkul\Product\Models;
use Illuminate\Database\Eloquent\Model;
use Webkul\Product\Models\Product;
use Illuminate\Support\Facades\Storage;
class ProductImage extends Model
{
public $timestamps = false;
protected $fillable = [];
protected $fillable = ['path', 'product_id'];
/**
* Get the product that owns the image.
@ -18,4 +19,42 @@ class ProductImage extends Model
{
return $this->belongsTo(Product::class);
}
/**
* Get image url for the product image.
*/
public function url()
{
return Storage::url($this->path);
}
/**
* Get image url for the product image.
*/
public function getUrlAttribute()
{
return $this->url();
}
/**
* @param string $key
*
* @return bool
*/
public function isCustomAttribute($attribute)
{
return $this->attribute_family->custom_attributes->pluck('code')->contains($attribute);
}
/**
* @return array
*/
public function toArray()
{
$array = parent::toArray();
$array['url'] = $this->url;
return $array;
}
}

View File

@ -0,0 +1,71 @@
<?php
namespace Webkul\Product\Repositories;
use Illuminate\Support\Facades\Storage;
use Webkul\Core\Eloquent\Repository;
/**
* Product Image Reposotory
*
* @author Jitendra Singh <jitendra@webkul.com>
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
*/
class ProductImageRepository extends Repository
{
/**
* Specify Model class name
*
* @return mixed
*/
function model()
{
return 'Webkul\Product\Models\ProductImage';
}
/**
* @param array $data
* @param mixed $product
* @return mixed
*/
public function uploadImages($data, $product)
{
$previousImageIds = $product->images()->pluck('id');
if(isset($data['images'])) {
foreach ($data['images'] as $imageId => $image) {
$file = 'images.' . $imageId;
$dir = 'product/' . $product->id;
if (str_contains($imageId, 'image_')) {
$this->create([
'path' => request()->file($file)->store($dir),
'product_id' => $product->id
]);
} else {
if(is_numeric($index = $previousImageIds->search($imageId))) {
$previousImageIds->forget($index);
}
if(request()->hasFile($file)) {
if($imageModel = $this->find($imageId)) {
Storage::delete($imageModel->path);
}
$this->update([
'path' => request()->file($file)->store($dir)
], $imageId);
}
}
}
}
foreach ($previousImageIds as $imageId) {
if($imageModel = $this->find($imageId)) {
Storage::delete($imageModel->path);
$this->delete($imageId);
}
}
}
}

View File

@ -8,6 +8,7 @@ use Webkul\Attribute\Repositories\AttributeRepository;
use Webkul\Attribute\Repositories\AttributeOptionRepository;
use Webkul\Product\Repositories\ProductAttributeValueRepository;
use Webkul\Product\Repositories\ProductInventoryRepository;
use Webkul\Product\Repositories\ProductImageRepository;
use Webkul\Product\Models\ProductAttributeValue;
/**
@ -46,6 +47,13 @@ class ProductRepository extends Repository
*/
protected $productInventory;
/**
* ProductImageRepository object
*
* @var array
*/
protected $productImage;
/**
* Create a new controller instance.
*
@ -53,6 +61,7 @@ class ProductRepository extends Repository
* @param Webkul\Attribute\Repositories\AttributeOptionRepository $attributeOption
* @param Webkul\Product\Repositories\ProductAttributeValueRepository $attributeValue
* @param Webkul\Product\Repositories\ProductInventoryRepository $productInventory
* @param Webkul\Product\Repositories\ProductImageRepository $productImage
* @return void
*/
public function __construct(
@ -60,6 +69,7 @@ class ProductRepository extends Repository
AttributeOptionRepository $attributeOption,
ProductAttributeValueRepository $attributeValue,
ProductInventoryRepository $productInventory,
ProductImageRepository $productImage,
App $app)
{
$this->attribute = $attribute;
@ -70,6 +80,8 @@ class ProductRepository extends Repository
$this->productInventory = $productInventory;
$this->productImage = $productImage;
parent::__construct($app);
}
@ -183,6 +195,8 @@ class ProductRepository extends Repository
}
$this->productInventory->saveInventories($data, $product);
$this->productImage->uploadImages($data, $product);
return $product;
}

View File

@ -1,4 +1,5 @@
@extends('shop::store.layouts.master')
@section('content-wrapper')
<div class="content">
@ -57,6 +58,5 @@
</div>
</form>
</div>
@endsection

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="160px" height="114px" viewBox="0 0 160 114" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 50 (54983) - http://www.bohemiancoding.com/sketch -->
<title>placeholder-icon</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Catalog-Product-New-Variable-Product" transform="translate(-144.000000, -1457.000000)" stroke="#C7C7C7" stroke-width="2">
<g id="2" transform="translate(104.000000, 860.000000)">
<g id="Image" transform="translate(20.000000, 528.000000)">
<g id="Images" transform="translate(0.000000, 26.000000)">
<g id="Block">
<g id="Image-Icon">
<g id="placeholder-icon" transform="translate(20.000000, 43.333333)">
<rect id="Rectangle-3" x="1" y="1" width="158" height="111.333333"></rect>
<rect id="Rectangle-3" x="17.6666667" y="17.6666667" width="121.333333" height="78"></rect>
<polyline id="Path-2" points="17.9238281 78.6588542 47.7115392 48.4681532 97.1757812 95.7462565"></polyline>
<polyline id="Path-3" points="73.7011719 72.7286606 110.238697 37.3952908 139.06543 66.2701823"></polyline>
<circle id="Oval-3" cx="75" cy="41.6666667" r="8.33333333"></circle>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -1,7 +1,13 @@
<template>
<div>
<input type="file" :name="finalInputName" ref="imageInput"/>
</div>
<label class="image-item" :for="_uid" v-bind:class="{ 'has-image': imageData.length > 0 }">
<input type="hidden" :name="finalInputName"/>
<input type="file" accept="image/*" :name="finalInputName" ref="imageInput" :id="_uid" @change="addImageView($event)"/>
<img class="preview" :src="imageData" v-if="imageData.length > 0">
<label class="remove-image" @click="removeImage()">{{ removeButtonLabel }}</label>
</label>
</template>
<script>
@ -13,10 +19,8 @@
default: 'attachments'
},
multiple: {
type: [Boolean, String],
required: false,
default: true
removeButtonLabel: {
type: String,
},
image: {
@ -26,22 +30,42 @@
}
},
data: function() {
return {
imageData: ''
}
},
mounted () {
if(!this.image.id) {
var element = this.$refs.imageInput;
element.dispatchEvent(new Event("click"));
element.click();
if(this.image.id && this.image.url) {
this.imageData = this.image.url;
}
},
computed: {
finalInputName () {
if(this.multiple)
return this.inputName + '[]';
return this.inputName;
return this.inputName + '[' + this.image.id + ']';
}
},
methods: {
addImageView () {
var imageInput = this.$refs.imageInput;
if (imageInput.files && imageInput.files[0]) {
var reader = new FileReader();
reader.onload = (e) => {
this.imageData = e.target.result;
}
reader.readAsDataURL(imageInput.files[0]);
}
},
removeImage () {
this.$emit('onRemoveImage', this.image)
}
}
}
</script>

View File

@ -1,7 +1,14 @@
<template>
<div>
<div class="image-wrapper">
<image-item v-for='(image, index) in images' :key='image.uid' :image="image" :input-name="inputName" :multiple="multiple" @onRemoveImage="removImage($event)"></image-item>
<image-item
v-for='(image, index) in items'
:key='image.id'
:image="image"
:input-name="inputName"
:remove-button-label="removeButtonLabel"
@onRemoveImage="removeImage($event)"
></image-item>
</div>
<label class="btn btn-lg btn-primary" style="display: inline-block" @click="createFileType">{{ buttonLabel }}</label>
@ -17,18 +24,18 @@
default: 'Add Image'
},
removeButtonLabel: {
type: String,
required: false,
default: 'Remove Image'
},
inputName: {
type: String,
required: false,
default: 'attachments'
},
multiple: {
type: [Boolean, String],
required: false,
default: true
},
images: {
type: Array,
required: false,
@ -36,9 +43,33 @@
}
},
data: function() {
return {
imageCount: 0,
items: []
}
},
created () {
var this_this = this;
this.images.forEach(function(image) {
this_this.items.push(image)
this_this.imageCount++;
});
},
methods: {
createFileType () {
this.images.push({});
this.imageCount++;
this.items.push({'id': 'image_' + this.imageCount});
},
removeImage (image) {
let index = this.items.indexOf(image)
Vue.delete(this.items, index);
}
}

View File

@ -956,8 +956,8 @@ h2 {
}
.label {
background: #e7e7e7;
border-radius: 2px;
background: #E7E7E7;
@include border-radius(2px);
padding: 8px;
color: #000311;
display: inline-block;
@ -978,3 +978,54 @@ h2 {
padding: 14px;
}
}
.image-wrapper {
margin-bottom: 20px;
display: inline-block;
width: 100%;
.image-item {
width: 200px;
height: 200px;
margin-right: 20px;
background: #F8F9FA;
@include border-radius(3px);
display: inline-block;
position: relative;
background-image: url("../images/placeholder-icon.svg");
background-repeat: no-repeat;
background-position: center;
img.preview {
width: 100%;
height: 100%;
}
input {
display: none;
}
.remove-image {
// display: none;
background-image: linear-gradient(-180deg, rgba(0,0,0,0.08) 0%, rgba(0,0,0,0.24) 100%);
@include border-radius(0 0 4px 4px);
position: absolute;
bottom: 0;
width: 100%;
padding: 10px;
text-align: center;
color: #fff;
text-shadow: 0 1px 2px rgba(0,0,0,0.24);
margin-right: 20px;
cursor: pointer;
}
&:hover .remove-image {
display: block;
}
&.has-image {
background-image: none;
}
}
}