HEX
Server: LiteSpeed
System: Linux sv4.hami.host 5.14.0-611.54.3.el9_7.x86_64 #1 SMP PREEMPT_DYNAMIC Thu May 7 16:31:24 EDT 2026 x86_64
User: armgroup (1008)
PHP: 8.2.32
Disabled: show_source, system, shell_exec, passthru, exec, popen, proc_open, mail, socket_create, socket_create_listen, socket_create_pair, link, dl, openlog, syslog, stream_socket_server, curl_multi_init
Upload Files
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,
                ];
            }
        }
    }
}