FleetCart/Modules/Product/Entities/Product.php
2023-12-03 14:07:47 +00:00

283 lines
6.9 KiB
PHP

<?php
namespace Modules\Product\Entities;
use Illuminate\Http\Request;
use Modules\Support\Eloquent\Model;
use Modules\Media\Eloquent\HasMedia;
use Modules\Meta\Eloquent\HasMetaData;
use Modules\Support\Search\Searchable;
use Modules\Product\Admin\ProductTable;
use Modules\Support\Eloquent\Sluggable;
use Modules\Support\Eloquent\Translatable;
use Modules\Product\Entities\Concerns\IsNew;
use Illuminate\Database\Eloquent\SoftDeletes;
use Modules\Product\Entities\Concerns\HasStock;
use Modules\Product\Entities\Concerns\Predicates;
use Modules\Product\Entities\Concerns\Filterable;
use Modules\Product\Entities\Concerns\QueryScopes;
use Modules\Product\Entities\Concerns\ModelAccessors;
use Modules\Product\Entities\Concerns\HasSpecialPrice;
use Modules\Product\Entities\Concerns\EloquentRelations;
class Product extends Model
{
use Translatable,
Searchable,
Filterable,
Sluggable,
HasMedia,
HasMetaData,
HasSpecialPrice,
HasStock,
SoftDeletes,
IsNew,
QueryScopes,
ModelAccessors,
Predicates,
EloquentRelations;
/**
* The relations to eager load on every query.
*
* @var array
*/
protected $with = ['translations'];
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'brand_id',
'tax_class_id',
'slug',
'sku',
'price',
'special_price',
'special_price_type',
'special_price_start',
'special_price_end',
'selling_price',
'manage_stock',
'qty',
'in_stock',
'is_virtual',
'is_active',
'new_from',
'new_to',
];
/**
* The attributes that should be cast to native types.
*
* @var array
*/
protected $casts = [
'is_virtual' => 'boolean',
'is_active' => 'boolean',
];
/**
* The attributes that should be mutated to dates.
*
* @var array
*/
protected $dates = [
'special_price_start',
'special_price_end',
'new_from',
'new_to',
'deleted_at',
];
/**
* The accessors to append to the model's array form.
*
* @var array
*/
protected $appends = [
'base_image',
'additional_images',
'media',
'formatted_price',
'formatted_price_range',
'has_percentage_special_price',
'special_price_percent',
'rating_percent',
'does_manage_stock',
'is_in_stock',
'is_out_of_stock',
'is_new',
'variant',
];
/**
* The attributes that are translatable.
*
* @var array
*/
protected array $translatedAttributes = [
'name',
'description',
'short_description',
];
/**
* The attribute that will be slugged.
*
* @var string
*/
protected string $slugAttribute = 'name';
/**
* Perform any actions required after the model boots.
*
* @return void
*/
protected static function booted(): void
{
static::addActiveGlobalScope();
static::saved(function ($product) {
$attributes = request()->all();
if (!empty($attributes)) {
$product->categories()->sync(array_get($attributes, 'categories', []));
$product->tags()->sync(array_get($attributes, 'tags', []));
$product->upSellProducts()->sync(array_get($attributes, 'up_sells', []));
$product->crossSellProducts()->sync(array_get($attributes, 'cross_sells', []));
$product->relatedProducts()->sync(array_get($attributes, 'related_products', []));
}
$product->withoutEvents(function () use ($product) {
$product->update([
'selling_price' => ($product->hasSpecialPrice() ? $product->getSpecialPrice() : $product->price)->amount(),
]);
});
});
}
/**
* Get table data for the resource
*
* @param Request $request
*
* @return ProductTable
*/
public function table(Request $request): ProductTable
{
$query = $this->newQuery()
->withoutGlobalScope('active')
->withName()
->withBaseImage()
->withPrice()
->addSelect(['id', 'is_active', 'created_at', 'updated_at'])
->when($request->has('except'), function ($query) use ($request) {
$query->whereNotIn('id', explode(',', $request->except));
});
return new ProductTable($query);
}
public function clean(): array
{
$cleanExceptAttributes = [
'description',
'short_description',
'translations',
'categories',
'files',
'in_stock',
'brand_id',
'tax_class',
'tax_class_id',
'viewed',
'is_active',
'created_at',
'updated_at',
'deleted_at',
];
return array_except(
$this->toArray(),
$cleanExceptAttributes
);
}
public function url(): string
{
return route('products.show', ['slug' => $this->slug]);
}
/**
* Get the indexable data array for the product.
*
* @return array
*/
public function toSearchableArray(): array
{
# MySQL Full-Text search handles indexing automatically.
if (config('scout.driver') === 'mysql') {
return [];
}
$translations = $this->translations()
->withoutGlobalScope('locale')
->get(['name', 'description', 'short_description']);
return [
'id' => $this->id,
'translations' => $translations,
];
}
public function searchTable(): string
{
return 'product_translations';
}
public function searchKey(): string
{
return 'product_id';
}
public function searchColumns(): array
{
return ['name'];
}
/**
* Help HasMedia trait to extract media
* for this model from the HTTP request.
*
* @return mixed
*/
public function extractMediaFromRequest(): mixed
{
$media = collect(request('media', []));
return [
'base_image' => $media->first(),
'additional_images' =>
$media->except(
$media->keys()->first()
)->toArray(),
'downloads' => request('downloads', []),
];
}
}