File: /home/armgroup/libs/app/Http/Livewire/Admin/Product/Edit.php
<?php
namespace App\Http\Livewire\Admin\Product;
use App\Models\Tag;
use App\Models\Brand;
use App\Models\Image;
use App\Models\Option;
use App\Models\Product;
use Livewire\Component;
use App\Models\Category;
use App\Models\Attribute;
use App\Models\Organization;
use App\Models\OptionProduct;
use App\Http\Livewire\General;
use App\Models\AttributeGroup;
use Illuminate\Support\Facades\DB;
use App\Events\InventoryIncreased;
use App\Http\Livewire\ConvertEmptyStringsToNull;
class Edit extends Component
{
use ConvertEmptyStringsToNull, General;
public Product $product;
public $category;
public $items;
public $deleteIds = [];
public $attributes;
public $selectedAttributes = [];
public $tags;
public $faq;
public $tag_id;
public $brands;
public $items2 = [];
public $options = [];
public $allOptions;
public $selected_option_id = null;
public $productSelectedOptions = [];
public $optionValues;
public $can_change_status;
public $category_id;
public $categories;
public $countries;
public $organizations;
public $specials = [];
protected $listeners = ['imageChanged', 'multiImageChanged', 'videoChanged'];
public function multiImageChanged($index, $imagePath)
{
$this->items[$index]['path'] = ltrim(parse_url($imagePath, PHP_URL_PATH), '/');
}
public function addSpecial()
{
array_push($this->specials, [
'product_id' => $this->product->id,
'organization_id' => null,
'special' => null,
'special_started_at' => null,
'special_ended_at' => null,
]);
$this->emit('addedSpecial', count($this->specials) - 1);
}
public function removeSpecial($index)
{
unset($this->specials[$index]);
}
public function addItem($type)
{
if ($type == 1) {
$this->items[] = [
'id' => null,
'path' => null,
'sort_order' => null,
'imageable_id' => $this->product->id,
'imageable_type' => Product::class,
];
$this->emit('addedItem');
} elseif ($type == 2) {
$this->items2[] = [
'product_id' => $this->product->id,
'option_id' => $this->selected_option_id,
'value_id' => null,
'price' => null,
'stock' => 0,
'code' => null,
// 'special' => null,
// 'special_started_at' => null,
// 'special_ended_at' => null,
];
} else {
$this->faq[] = [
'question' => null,
'answer' => null,
];
}
}
public function removeItem($index, $type)
{
if ($type == 1) {
if ($this->items[$index]['id']) {
$this->deleteIds[] = $this->items[$index]['id'];
}
unset($this->items[$index]);
} elseif ($type == 2) {
unset($this->items2[$index]);
} else {
unset($this->faq[$index]);
}
}
public function mount()
{
$this->countries = config('countries');
$this->faq = $this->product->faq ?: [];
$this->organizations = Organization::query()->get(['id', 'name']);
$this->tags = Tag::all();
$this->tag_id = $this->product->tags->pluck('id')->toArray();
$this->category = $this->product->categories()->where('is_main', 1)->first();
$this->categories = Category::query()->where('type', Product::class)->where('id', '<>', $this->category->id)->get(['id', 'name']);
$this->category_id = $this->product->categories()->where('is_main', 0)->pluck('id')->toArray();
$this->items = $this->product
->images()
->select('id', 'path', 'sort_order', 'imageable_id', 'imageable_type')
->get()
->toArray();
$attribute_ids = AttributeGroup::whereRelation('categories', 'id', $this->category->id)->orWhereDoesntHave('categories')->pluck('id')->toArray();
$this->attributes = Attribute::whereIn('group_id', $attribute_ids)->has('values')->with('values')->get();
$this->selectedAttributes = DB::table('attribute_product')
->where('product_id', $this->product->id)
->whereIn('attribute_id', $this->attributes->pluck('id')->toArray())
->pluck('value_id', 'attribute_id')
->toArray();
$this->brands = Brand::query()->select('id', 'name')->get();
$this->specials = DB::table('organization_product')
->where('product_id', $this->product->id)
->select('product_id', 'organization_id','special', 'special_started_at', 'special_ended_at')
->get()
->toArray();
$this->specials = array_map(function ($value) {
return (array)$value;
}, $this->specials);
if ($this->brands->where('id', $this->product->brand_id)->count() == 0) {
$this->product->brand_id = null;
}
$this->can_change_status = auth()->user()->can('change status');
$this->allOptions = Option::with('values:id,option_id,name')->get(['id', 'name']);
$this->items2 = DB::table('option_product')
->where('product_id', $this->product->id)
->get()
->toArray();
if (count($this->items2)) {
$this->items2 = array_map(function ($item) {
return (array) $item;
}, $this->items2);
$this->selected_option_id = $this->items2[0]['option_id'];
$this->options = Option::query()
->where('id', $this->selected_option_id)
->with('values:id,option_id,name')
->get(['id', 'name']);
} else {
$this->items2[] = [
// 'product_id' => $this->product->id,
'option_id' => null,
'value_id' => null,
'price' => null,
'stock' => $this->product->stock,
// 'code' => $this->product->code,
// 'special' => $this->product->special,
// 'special_started_at' => $this->product->special_started_at,
// 'special_ended_at' => $this->product->special_ended_at,
];
// $this->items2[] = [
// 'product_id' => $this->product->id,
// 'option_id' => null,
// 'value_id' => null,
// 'price' => $this->product->price,
// 'stock' => $this->product->stock,
// 'code' => $this->product->code,
// 'special' => $this->product->special,
// 'special_started_at' => $this->product->special_started_at,
// 'special_ended_at' => $this->product->special_ended_at,
// ];
}
}
public function render()
{
return view('livewire.admin.product.edit');
}
protected function rules()
{
$data = [
'product.name' => 'required|max:250',
'product.latin_name' => 'nullable|max:250',
'product.meta_title' => 'nullable|max:250',
'product.slug' => 'required|max:250|alpha_dash|unique:products,slug,'.$this->product->id,
'product.image' => 'required|max:250',
'product.short_description' => 'nullable|max:250',
'product.description' => 'nullable|max:65000',
'product.weight' => 'nullable|integer|min:0|max:999999999999999',
'product.sort_order' => 'nullable|integer|min:0|max:999999999',
'product.sending_days' => 'nullable|integer|min:0|max:30',
'product.status' => 'required|in:0,1',
'product.suggest' => 'required|in:0,1',
'product.best_seller' => 'required|in:0,1',
'product.country_code' => 'nullable|string',
// 'product.slider_text' => 'nullable|required_if:product.show_in_slider,1|max:500',
// 'product.slider_video' => 'nullable|required_if:product.show_in_slider,1|max:250',
'product.brand_id' => 'nullable|exists:brands,id',
'product.price' => 'nullable|integer|min:0|max:999999999999999',
'product.code' => 'nullable|string|max:250|unique:products,code,'. $this->product->id,
'product.stock' => 'nullable|integer|min:0|max:999999999999999',
'tag_id' => 'nullable|array',
'tag_id.*' => 'required|exists:tags,id',
'category_id' => 'nullable|array',
'category_id.*' => 'required|exists:categories,id',
'items.*.path' => 'required|max:250',
'items.*.sort_order' => 'nullable|integer|min:0|max:999999999',
'faq.*.question' => 'required|max:250',
'faq.*.answer' => 'required|max:250',
'items2.*.product_id' => 'nullable|in:'.$this->product->id,
'items2.*.option_id' => 'nullable',
'items2.*.value_id' => 'nullable',
'items2.*.price' => 'nullable|integer|min:0|max:999999999999999',
// 'items2.*.stock' => 'required|integer|min:0|max:10000',
// 'items2.*.code' => 'nullable|max:50',
// 'items2.*.special' => 'nullable|integer|min:0|max:999999999999998|lt:items2.*.price',
// 'items2.*.special_started_at' => 'nullable|date|required_with:items2.*.special',
// 'items2.*.special_ended_at' => 'nullable|date|after:items2.*.special_started_at|required_with:items2.*.special',
'specials.*.product_id' => 'required|in:'. $this->product->id,
'specials.*.organization_id' => 'nullable|distinct|exists:organizations,id',
'specials.*.special' => 'required|integer|min:0|max:999999999999998|lt:product.price',
'specials.*.special_started_at'=> 'required|date',
'specials.*.special_ended_at' => 'required|date|after:specials.*.special_started_at',
];
if ($this->selected_option_id) {
$data['items2.*.option_id'] = 'required|in:'.$this->selected_option_id;
$data['items2.*.value_id'] = 'required|exists:option_values,id|distinct';
}
return $data;
}
protected $validationAttributes = [
'faq.*.question' => 'سوال',
'faq.*.answer' => 'جواب',
'items.*.path' => 'تصویر',
'items.*.sort_order' => 'ترتیب',
'image' => 'تصویر شاخص',
'items2.*.option_id' => 'گزینه',
'items2.*.value_id' => 'مقدار',
'items2.*.price' => 'افزایش قیمت',
'items2.*.stock' => 'موجودی',
'items2.*.code' => 'کد',
// 'items2.*.special' => 'قیمت ویژه',
// 'items2.*.special_started_at' => 'تاریخ شروع',
// 'items2.*.special_ended_at' => 'تاریخ پایان',
'specials.*.organization_id' => 'سازمان',
'specials.*.special' => 'قیمت ویژه',
'specials.*.special_started_at'=> 'تاریخ شروع',
'specials.*.special_ended_at' => 'تاریخ پایان',
];
public function update()
{
$data = $this->validate();
$stock = 0;
foreach ($this->items2 as $value) {
if(!empty($value['option_id'])){
$stock += $value['stock'];
}
}
if (! $this->can_change_status) {
$this->product->status = $this->product->getOriginal('status');
}
$data['faq'] = count($this->faq) ? $this->faq : null;
DB::transaction(function () use ($data, $stock) {
if(count($this->items2)) {
$this->product->stock = !empty($value['option_id']) ? $stock : $this->product->stock;
}
if ($this->product->status && $this->product->stock > 0 && $this->product->demands()->count()) {
InventoryIncreased::dispatch($this->product);
}
$this->product->update($data);
$categories = [
$this->category->id => ['is_main' => true],
];
DB::table('organization_product')->where('product_id', $this->product->id)->delete();
if($this->specials) {
DB::table('organization_product')->insert($this->specials);
}
foreach ($this->category_id as $category) {
$categories[$category] = ['is_main' => false];
}
$this->product->categories()->sync($categories);
$this->product->tags()->sync($this->tag_id);
if (! count($this->items)) {
$this->product->images()->delete();
} else {
if (count($this->deleteIds)) {
Image::whereIn('id', $this->deleteIds)->delete();
}
Image::upsert(
$this->items,
['id', 'imageable_id', 'imageable_type'],
['path', 'sort_order']
);
}
DB::table('attribute_product')
->where('product_id', $this->product->id)
->delete();
if (count($this->selectedAttributes)) {
$attributes_data = [];
foreach ($this->selectedAttributes as $attribute => $value) {
if ($value) {
$attributes_data[] = [
'product_id' => $this->product->id,
'attribute_id' => $attribute,
'value_id' => $value,
];
}
}
if (count($attributes_data)) {
DB::table('attribute_product')->insert($attributes_data);
}
}
DB::table('option_product')
->where('product_id', $this->product->id)
->delete();
if ($this->selected_option_id) {
DB::table('option_product')->insert($this->items2);
}
$collectItems2 = collect($this->items2);
if(count($this->items2)) {
$this->product->stock = !empty($value['option_id']) ? $collectItems2->sum('stock') : $this->product->stock;
}
// $this->product->stock = $collectItems2->sum('stock');
// if (! $this->selected_option_id) {
// $this->product->code = $collectItems2->first()['code'];
// } else {
// $this->product->code = null;
// }
// $lowestPriceOption = OptionProduct::query()->where('product_id', $this->product->id)->first()?->toArray() ?:
// $collectItems2->sortBy('price')->sortBy(fn ($item) => $item['special'] ?: PHP_INT_MAX)->first();
// $this->product->price = $lowestPriceOption['price'];
// $this->product->special = $lowestPriceOption['special'] ?: null;
// $this->product->special_started_at = $lowestPriceOption['special'] ? $lowestPriceOption['special_started_at'] : null;
// $this->product->special_ended_at = $lowestPriceOption['special'] ? $lowestPriceOption['special_ended_at'] : null;
$this->product->save();
saveActivity("محصول {$this->product->name} ویرایش شد.", $this->product);
});
$this->doneMessage("{$this->product->name} با موفقیت ویرایش شد");
return redirect()->route('admin.products.index', $this->product->slug);
}
public function imageChanged($imagePath)
{
$this->product->image = ltrim(parse_url($imagePath, PHP_URL_PATH), '/');
}
public function videoChanged($videoPath)
{
$this->resetValidation('product.slider_video');
$this->product->slider_video = null;
$extension = pathinfo($videoPath, PATHINFO_EXTENSION);
if (strtolower($extension) != 'mp4') {
$this->addError('product.slider_video', 'فرمت باید mp4 باشد.');
return;
}
$this->product->slider_video = ltrim(parse_url($videoPath, PHP_URL_PATH), '/');
}
public function setProductOptions()
{
$this->productSelectedOptions = array_filter($this->productSelectedOptions);
if (count($this->productSelectedOptions) > 1) {
$this->ajaxDoneMessage('حداکثر یک گزینه میتوانید انتخاب کنید.', 'warning');
return;
}
$option_ids = array_keys($this->productSelectedOptions);
$value_ids = array_merge(...$this->productSelectedOptions);
$this->options = Option::query()
->whereIn('id', $option_ids)
->with(['values' => function ($query) use ($value_ids) {
return $query->whereIn('id', $value_ids)->select('id', 'option_id', 'name');
}])
->get(['id', 'name']);
$this->items2 = [];
$this->selected_option_id = null;
$count = count($this->options);
if ($count == 0) {
$this->items2[] = [
'product_id' => $this->product->id,
'option_id' => null,
'value_id' => null,
'price' => null,
'code' => null,
'stock' => 0,
'special' => null,
'special_started_at' => null,
'special_ended_at' => null,
];
} elseif ($count == 1) {
foreach ($this->options[0]->values as $value) {
$this->selected_option_id = $value->option_id;
$this->items2[] = [
'product_id' => $this->product->id,
'option_id' => $value->option_id,
'value_id' => $value->id,
'price' => null,
'code' => null,
'stock' => 0,
'special' => null,
'special_started_at' => null,
'special_ended_at' => null,
];
}
}
}
}