![]() Server : Apache System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64 User : corals ( 1002) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system Directory : /home/corals/job-board.corals.io/Corals/modules/Ecommerce/Jobs/ |
<?php namespace Corals\Modules\Ecommerce\Jobs; use Corals\Modules\Ecommerce\Http\Requests\{ProductRequest, SKURequest}; use Corals\Modules\Ecommerce\Models\{Attribute, Brand, Category, Product, SKU}; use Corals\Modules\Ecommerce\Services\{ProductService}; use Corals\Modules\Ecommerce\Traits\ImportTrait; use Corals\Modules\Marketplace\Services\SKUService; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Database\Eloquent\Collection; use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\{InteractsWithQueue, SerializesModels}; use Illuminate\Support\{Arr, Str}; use League\Csv\{Exception as CSVException}; class HandleProductsImportFile implements ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, ImportTrait; protected $importFilePath; /** * @var Collection */ protected $categories; /** * @var Collection */ protected $brands; /** * @var Collection */ protected $attributes; /** * @var array */ protected $importHeaders; protected $user; protected $images_root; protected $clearExistingImages; /** * HandleProductsImportFile constructor. * @param $importFilePath * @param $images_root * @param $clearExistingImages * @param $user */ public function __construct($importFilePath, $images_root, $clearExistingImages, $user) { $this->user = $user; $this->importFilePath = $importFilePath; $this->clearExistingImages = $clearExistingImages; $this->images_root = $images_root; $this->importHeaders = array_keys(trans('Ecommerce::import.product-headers')); } /** * @throws CSVException */ public function handle() { $this->doImport(); } /** * @param $record * @throws \Exception */ protected function handleImportRecord($record) { $record = array_map('trim', $record); //prepare product data $productData = $productRequestData = $this->getProductData($record); $productRequestData['variation_options'] = array_keys(data_get($productRequestData, 'variation_options', [])); $productRequestData['global_options'] = array_keys(data_get($productRequestData, 'global_options', [])); unset($productRequestData['shippable']); //validate record $this->validateRecord($productRequestData); //check if product/sku exist $skuCode = data_get($record, 'SKU'); $skuModel = SKU::query() ->where('code', $skuCode) ->first(); $productCode = data_get($record, 'Parent SKU'); if ($productCode) { $productModel = Product::query() ->where('product_code', $productCode) ->first(); } elseif ($skuModel) { $productModel = $skuModel->product; } $productRequest = new ProductRequest(); $productRequest->replace($productRequestData); $productService = new ProductService(); if (isset($productModel) && $productModel) { $productModel = $productService->update($productRequest, $productModel); } else { $productModel = $productService->store($productRequest, Product::class); } $this->handleProductImages($record, $productModel); if ($productData['type'] === 'variable') { $productData['product_id'] = $productModel->id; $skuData = $this->getSKUData($productData); $skuService = new SKUService(); $skuRequest = new SKURequest(); $skuRequest->replace($skuData); if ($skuModel) { $skuModel = $skuService->update($skuRequest, $skuModel); } else { $skuModel = $skuService->store($skuRequest, SKU::class); } $featuredImage = data_get($record, 'Featured Image'); if ($featuredImage) { $this->addMediaFromFile( $skuModel, $featuredImage, $skuModel->mediaCollectionName, "sku_{$skuModel->id}"); } } unset($skuModel); unset($productModel); } /** * @param $record * @return array */ protected function handleProductCategories($record): array { $importCategories = array_filter(explode('|', data_get($record, 'Categories', []))); $productCategories = []; foreach ($importCategories as $categoryName) { $categoryName = trim($categoryName); if (empty($categoryName)) { continue; } $categoryFound = $this->categories->where('name', $categoryName)->first(); if (!$categoryFound) { $categoryFound = $this->categories->where('slug', Str::slug($categoryName))->first(); } if ($categoryFound) { $productCategories[] = $categoryFound->id; } else { $newCategory = Category::query()->create([ 'name' => $categoryName, 'slug' => Str::slug($categoryName), ]); $this->categories->push($newCategory); $productCategories[] = $newCategory->id; } } return $productCategories; } /** * @param $record * @return int|null */ protected function handleProductBrand($record) { $brandName = data_get($record, 'Brand Name'); $brandId = null; if ($brandName) { $brandFound = $this->brands->where('name', $brandName)->first(); if (!$brandFound) { $brandFound = $this->categories->where('slug', $brandName)->first(); } if (!$brandFound) { $newBrand = Brand::query()->create([ 'name' => $brandName, 'slug' => Str::slug($brandName), ]); $this->brands->push($newBrand); $brandFound = $newBrand; } $brandId = $brandFound->id; } return $brandId; } /** * @param $record * @param $productModel */ protected function handleProductImages($record, $productModel) { if ($this->clearExistingImages) { $productModel->clearMediaCollection($productModel->galleryMediaCollection); } $featuredImage = data_get($record, 'Featured Image'); if ($featuredImage) { $media = $this->addMediaFromFile( $productModel, $featuredImage, $productModel->galleryMediaCollection, "product_{$productModel->id}", false, ['featured' => true]); if ($media && !$this->clearExistingImages) { $gallery = $productModel->getMedia($productModel->galleryMediaCollection); foreach ($gallery as $item) { if ($item->id != $media->id) { $item->forgetCustomProperty('featured'); $item->save(); } } } } $images = array_filter(explode('|', data_get($record, 'Images'))); foreach ($images as $image) { if ($featuredImage == $image) { continue; } $this->addMediaFromFile( $productModel, $image, $productModel->galleryMediaCollection, "product_{$productModel->id}", false); } } protected function loadEcommerceCategories() { $this->categories = Category::query()->get(); } protected function loadEcommerceBrands() { $this->brands = Brand::query()->get(); } protected function loadEcommerceAttributes() { $this->attributes = Attribute::with(['options'])->get(); } /** * @param $record * @param string $column * @return array * @throws \Exception */ protected function handleVariationOptions($record, string $column) { $attributes = array_filter(explode('|', data_get($record, $column))); $isGlobal = $column !== 'Attributes'; $variationOptions = []; foreach ($attributes as $attribute) { if (!$isGlobal) { [$code, $value] = explode(':', $attribute); $value = trim($value); } else { $code = $attribute; } $attributeModel = $this->attributes->where('code', trim($code))->first(); if (!$attributeModel) { throw new \Exception("Attribute $code not found"); } if (empty($value) && $attributeModel->required) { throw new \Exception("Attribute $attribute value is empty"); } if ($isGlobal) { $variationOptions[$attributeModel->id] = 1; continue; } if ($attributeModel->options->isNotEmpty()) { if ($attributeModel->type == 'multi_values') { $variationOptions[$attributeModel->id] = ['multi' => []]; $values = array_filter(explode('+', $value)); foreach ($values as $value) { $option = $this->getAttributeOption($attributeModel, $value); $variationOptions[$attributeModel->id]['multi'][] = [$option->id => $value]; } } else { $option = $this->getAttributeOption($attributeModel, $value); $variationOptions[$attributeModel->id] = [$option->id => $value]; } } else { $variationOptions[$attributeModel->id] = $value; } } return $variationOptions; } /**. * @param $attributeModel * @param $value * @return mixed * @throws \Exception */ protected function getAttributeOption($attributeModel, $value) { $option = $attributeModel->options->where('option_value', $value)->first(); if (!$option) { throw new \Exception("Attribute {$attributeModel->code} $value option not found"); } return $option; } /** * @param $record * @return array */ protected function getShippingDetails($record): array { return array_filter([ 'shipping_option' => 'calculate_rates', 'enabled' => data_get($record, 'Shippable') == 1 ? 1 : 0, 'width' => data_get($record, 'Width'), 'height' => data_get($record, 'Height'), 'length' => data_get($record, 'Length'), 'weight' => data_get($record, 'Weight'), ]); } /** * @param $record * @return array * @throws \Exception */ protected function getProductData($record) { $productCategories = $this->handleProductCategories($record); $brandId = $this->handleProductBrand($record); $variationOptions = $this->handleVariationOptions($record, 'Attributes'); $globalOptions = $this->handleVariationOptions($record, 'Global Attributes'); return array_filter([ 'name' => data_get($record, 'Name'), 'caption' => data_get($record, 'Caption'), 'product_code' => data_get($record, 'Parent SKU') ?: null, 'type' => data_get($record, 'Type'), 'status' => data_get($record, 'Status'), 'code' => data_get($record, 'SKU'), 'regular_price' => data_get($record, 'Regular Price'), 'sale_price' => data_get($record, 'Sale Price'), 'allowed_quantity' => '0', 'categories' => $productCategories, 'description' => data_get($record, 'Description'), 'global_options' => $globalOptions, 'variation_options' => $variationOptions, 'shipping' => $this->getShippingDetails($record), 'shippable' => data_get($record, 'Shippable'), 'inventory' => data_get($record, 'Inventory'), 'inventory_value' => data_get($record, 'Inventory Value'), 'brand_id' => $brandId ]); } /** * @param array $productData * @return array */ protected function getSKUData(array $productData) { $skuData = Arr::only($productData, [ 'regular_price', 'sale_price', 'allowed_quantity', 'code', 'status', 'inventory', 'inventory_value', 'shipping', 'product_id', ]); foreach ($productData['variation_options'] as $optionId => $option) { if (is_array($option)) { $key = key($option); if ($key == 'multi') { foreach ($option[$key] as $multiOption) { $skuData['options'][$optionId][] = key($multiOption); } } else { $skuData['options'][$optionId] = $key; } } else { $skuData['options'][$optionId] = $option; } } return $skuData; } protected function initHandler() { $this->loadEcommerceCategories(); $this->loadEcommerceBrands(); $this->loadEcommerceAttributes(); } protected function getValidationRules($data, $model): array { return [ 'name' => 'required|max:191', 'caption' => 'required', 'status' => 'required|in:active,inactive', 'type' => 'required|in:simple,variable', 'inventory' => 'required_if:type,simple', 'inventory_value' => 'required_if:inventory,finite,bucket', 'regular_price' => 'required_if:type,simple', 'code' => 'required_if:type,simple', 'product_code' => 'required_if:type,variable', 'shipping.width' => 'required_if:shippable,1', 'shipping.height' => 'required_if:shippable,1', 'shipping.length' => 'required_if:shippable,1', 'shipping.weight' => 'required_if:shippable,1', 'variation_options' => [ 'required_if:type,variable', function ($attribute, $value, $fail) use ($data) { $global_options = data_get($data, 'global_options', []); if (array_intersect($value, $global_options)) { $fail($attribute . ' should be unique with global attributes'); } } ], 'categories' => 'required', ]; } }