sarga/packages/Webkul/Product/src/Models/Product.php

543 lines
14 KiB
PHP
Raw Normal View History

2018-07-27 06:22:12 +00:00
<?php
namespace Webkul\Product\Models;
use Exception;
use Illuminate\Support\Collection;
2018-07-27 06:22:12 +00:00
use Illuminate\Database\Eloquent\Model;
2020-07-30 12:15:54 +00:00
use Webkul\Attribute\Models\AttributeFamilyProxy;
use Webkul\Attribute\Models\AttributeProxy;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Webkul\Product\Database\Factories\ProductFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
2020-07-30 12:15:54 +00:00
use Webkul\Attribute\Repositories\AttributeRepository;
use Webkul\Category\Models\CategoryProxy;
use Webkul\Inventory\Models\InventorySourceProxy;
use Illuminate\Database\Eloquent\Factories\HasFactory;
2019-02-18 07:30:40 +00:00
use Webkul\Product\Contracts\Product as ProductContract;
use Webkul\Product\Database\Eloquent\Builder;
use Webkul\Product\Type\AbstractType;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
2019-02-18 07:30:40 +00:00
class Product extends Model implements ProductContract
2018-07-27 06:22:12 +00:00
{
use HasFactory;
/**
* The attributes that are mass assignable.
*
* @var $fillable
*/
2020-03-04 06:32:53 +00:00
protected $fillable = [
'type',
'attribute_family_id',
'sku',
'parent_id',
];
2018-07-27 09:30:48 +00:00
/**
* The attributes that should be cast.
*
* @var $casts
*/
protected $casts = [
'additional' => 'array',
];
/**
* The type of product.
*
* @var $typeInstance
*/
2019-06-28 14:18:52 +00:00
protected $typeInstance;
2021-07-20 09:24:22 +00:00
/**
* Loaded attribute values.
*
* @var $loadedAttributeValues
*/
public static $loadedAttributeValues = [];
/**
* The "booted" method of the model.
*
* @return void
*/
protected static function booted(): void
{
parent::boot();
2018-08-01 06:11:33 +00:00
static::deleting(function ($product) {
foreach ($product->product_flats as $productFlat) {
$productFlat->unsearchable();
}
foreach ($product->variants as $variant) {
foreach ($variant->product_flats as $productFlat) {
$productFlat->unsearchable();
}
}
});
}
2018-09-10 09:31:34 +00:00
2021-07-20 09:24:22 +00:00
/**
* Refresh the loaded attribute values.
*
* @return void
*/
public function refreshloadedAttributeValues(): void
2021-07-20 09:24:22 +00:00
{
self::$loadedAttributeValues = [];
}
2018-08-01 06:11:33 +00:00
/**
* Get the product attribute family that owns the product.
*/
public function attribute_family(): BelongsTo
2018-08-01 06:11:33 +00:00
{
2019-02-18 07:30:40 +00:00
return $this->belongsTo(AttributeFamilyProxy::modelClass());
2018-08-01 06:11:33 +00:00
}
/**
* Get the product attribute values that owns the product.
*/
public function attribute_values(): HasMany
{
2019-02-18 07:30:40 +00:00
return $this->hasMany(ProductAttributeValueProxy::modelClass());
}
/**
* Get the product flat entries that are associated with product.
* May be one for each locale and each channel.
*/
public function product_flats(): HasMany
{
return $this->hasMany(ProductFlatProxy::modelClass(), 'product_id');
}
/**
2018-08-09 04:35:13 +00:00
* Get the product variants that owns the product.
*/
public function variants(): HasMany
{
return $this->hasMany(static::class, 'parent_id');
}
2018-08-21 10:58:55 +00:00
/**
* Get the product reviews that owns the product.
*/
public function reviews(): HasMany
2018-08-21 10:58:55 +00:00
{
2019-02-18 07:30:40 +00:00
return $this->hasMany(ProductReviewProxy::modelClass());
2018-08-21 10:58:55 +00:00
}
2018-08-09 04:35:13 +00:00
/**
* Get the product that owns the product.
*/
public function parent(): BelongsTo
2018-08-09 04:35:13 +00:00
{
return $this->belongsTo(static::class, 'parent_id');
2018-08-09 04:35:13 +00:00
}
2018-07-27 09:30:48 +00:00
/**
* The categories that belong to the product.
*/
public function categories(): BelongsToMany
2018-07-27 09:30:48 +00:00
{
2019-02-18 07:30:40 +00:00
return $this->belongsToMany(CategoryProxy::modelClass(), 'product_categories');
2018-07-27 09:30:48 +00:00
}
2018-07-31 07:50:54 +00:00
/**
* The inventories that belong to the product.
*/
public function inventories(): HasMany
2018-07-31 07:50:54 +00:00
{
2019-02-18 07:30:40 +00:00
return $this->hasMany(ProductInventoryProxy::modelClass(), 'product_id');
2018-08-09 04:35:13 +00:00
}
/**
* The ordered inventories that belong to the product.
*/
public function ordered_inventories(): HasMany
{
2019-02-18 07:30:40 +00:00
return $this->hasMany(ProductOrderedInventoryProxy::modelClass(), 'product_id');
}
2018-08-09 04:35:13 +00:00
/**
* The inventory sources that belong to the product.
*/
public function inventory_sources(): BelongsToMany
2018-08-09 04:35:13 +00:00
{
return $this->belongsToMany(InventorySourceProxy::modelClass(), 'product_inventories')
->withPivot('id', 'qty');
2018-07-31 07:50:54 +00:00
}
/**
* The super attributes that belong to the product.
*/
public function super_attributes(): BelongsToMany
2018-07-31 07:50:54 +00:00
{
2019-02-18 07:30:40 +00:00
return $this->belongsToMany(AttributeProxy::modelClass(), 'product_super_attributes');
2018-07-31 07:50:54 +00:00
}
2018-08-09 04:35:13 +00:00
/**
* The images that belong to the product.
*/
public function images(): HasMany
2018-08-09 04:35:13 +00:00
{
2019-02-18 07:30:40 +00:00
return $this->hasMany(ProductImageProxy::modelClass(), 'product_id');
2018-08-09 04:35:13 +00:00
}
/**
* The videos that belong to the product.
*/
public function videos(): HasMany
{
return $this->hasMany(ProductVideoProxy::modelClass(), 'product_id');
}
2019-01-04 13:39:27 +00:00
/**
* The images that belong to the product.
*/
public function getBaseImageUrlAttribute()
{
$image = $this->images()
->first();
2019-01-04 13:39:27 +00:00
return $image->url ?? null;
2019-01-04 13:39:27 +00:00
}
2018-07-31 07:50:54 +00:00
/**
* The related products that belong to the product.
*/
public function related_products(): BelongsToMany
2018-07-31 07:50:54 +00:00
{
return $this->belongsToMany(static::class, 'product_relations', 'parent_id', 'child_id')
->limit(4);
2018-07-31 07:50:54 +00:00
}
/**
* The up sells that belong to the product.
*/
public function up_sells(): BelongsToMany
2018-07-31 07:50:54 +00:00
{
return $this->belongsToMany(static::class, 'product_up_sells', 'parent_id', 'child_id')
->limit(4);
2018-07-31 07:50:54 +00:00
}
/**
* The cross sells that belong to the product.
*/
public function cross_sells(): BelongsToMany
2018-07-31 07:50:54 +00:00
{
return $this->belongsToMany(static::class, 'product_cross_sells', 'parent_id', 'child_id')
->limit(4);
2018-07-31 07:50:54 +00:00
}
2018-09-05 10:56:42 +00:00
2018-09-10 09:20:08 +00:00
/**
2019-06-28 14:18:52 +00:00
* The images that belong to the product.
2018-09-10 09:20:08 +00:00
*/
public function downloadable_samples(): HasMany
2018-09-10 09:20:08 +00:00
{
2019-06-28 14:18:52 +00:00
return $this->hasMany(ProductDownloadableSampleProxy::modelClass());
}
2019-06-28 14:18:52 +00:00
/**
* The images that belong to the product.
*/
public function downloadable_links(): HasMany
2019-06-28 14:18:52 +00:00
{
return $this->hasMany(ProductDownloadableLinkProxy::modelClass());
2019-08-19 09:30:24 +00:00
}
/**
* Get the grouped products that owns the product.
*/
public function grouped_products(): HasMany
2019-08-19 09:30:24 +00:00
{
return $this->hasMany(ProductGroupedProductProxy::modelClass());
2019-08-21 13:54:26 +00:00
}
/**
* Get the bundle options that owns the product.
*/
public function bundle_options(): HasMany
2019-08-21 13:54:26 +00:00
{
return $this->hasMany(ProductBundleOptionProxy::modelClass());
2020-06-02 12:43:34 +00:00
}
/**
* Get the product customer group prices that owns the product.
*/
public function customer_group_prices(): HasMany
2020-06-02 12:43:34 +00:00
{
return $this->hasMany(ProductCustomerGroupPriceProxy::modelClass());
2018-09-10 09:20:08 +00:00
}
/**
* Get inventory source quantity.
*
* @param $inventorySourceId
*
* @return bool
*/
public function inventory_source_qty($inventorySourceId): bool
{
return $this->inventories()
->where('inventory_source_id', $inventorySourceId)
->sum('qty');
}
2018-10-05 11:59:43 +00:00
/**
* Get type instance.
2019-06-28 14:18:52 +00:00
*
* @return AbstractType
* @throws \Exception
2018-10-05 11:59:43 +00:00
*/
public function getTypeInstance(): AbstractType
2018-10-05 11:59:43 +00:00
{
2020-02-20 06:12:17 +00:00
if ($this->typeInstance) {
2019-06-28 14:18:52 +00:00
return $this->typeInstance;
2020-02-20 06:12:17 +00:00
}
2018-10-05 11:59:43 +00:00
2021-10-05 08:56:28 +00:00
$this->typeInstance = app(config('product_types.' . $this->type . '.class'));
if (!$this->typeInstance instanceof AbstractType) {
throw new Exception("Please ensure the product type '{$this->type}' is configured in your application.");
}
2019-06-28 14:18:52 +00:00
$this->typeInstance->setProduct($this);
2018-10-05 11:59:43 +00:00
2019-06-28 14:18:52 +00:00
return $this->typeInstance;
}
2018-10-05 11:59:43 +00:00
2019-06-28 14:18:52 +00:00
/**
* Is saleable.
2019-06-28 14:18:52 +00:00
*
* @param string $key
*
2019-06-28 14:18:52 +00:00
* @return bool
* @throws \Exception
2019-06-28 14:18:52 +00:00
*/
public function isSaleable(): bool
2019-06-28 14:18:52 +00:00
{
return $this->getTypeInstance()
->isSaleable();
2019-06-28 14:18:52 +00:00
}
2018-10-05 11:59:43 +00:00
2019-06-28 14:18:52 +00:00
/**
* Total quantity.
*
2019-06-28 14:18:52 +00:00
* @return integer
* @throws \Exception
2019-06-28 14:18:52 +00:00
*/
public function totalQuantity(): int
2019-06-28 14:18:52 +00:00
{
return $this->getTypeInstance()
->totalQuantity();
}
/**
* Have sufficient quantity.
*
* @param int $qty
*
* @return bool
* @throws \Exception
*/
public function haveSufficientQuantity(int $qty): bool
{
return $this->getTypeInstance()
->haveSufficientQuantity($qty);
2019-06-28 14:18:52 +00:00
}
/**
* Is stockable.
*
2019-06-28 14:18:52 +00:00
* @return bool
* @throws \Exception
2019-06-28 14:18:52 +00:00
*/
public function isStockable(): bool
2019-06-28 14:18:52 +00:00
{
return $this->getTypeInstance()
->isStockable();
2019-06-28 14:18:52 +00:00
}
2018-08-09 04:35:13 +00:00
/**
* Get an attribute from the model.
*
* @param string $key
*
2018-08-09 04:35:13 +00:00
* @return mixed
*/
public function getAttribute($key)
2018-09-20 10:01:51 +00:00
{
if (!method_exists(static::class, $key)
&& !in_array($key, [
'pivot',
'parent_id',
'attribute_family_id',
])
&& !isset($this->attributes[$key])) {
2018-10-12 08:22:06 +00:00
if (isset($this->id)) {
2018-08-22 07:05:17 +00:00
$this->attributes[$key] = '';
$attribute = core()
->getSingletonInstance(AttributeRepository::class)
2020-07-30 12:15:54 +00:00
->getAttributeByCode($key);
2018-08-09 04:35:13 +00:00
2018-10-12 08:22:06 +00:00
$this->attributes[$key] = $this->getCustomAttributeValue($attribute);
2018-08-22 07:05:17 +00:00
return $this->getAttributeValue($key);
2018-08-09 04:35:13 +00:00
}
}
return parent::getAttribute($key);
}
2018-08-01 06:11:33 +00:00
/**
* Retrieve product attributes.
*
* @param Group $group
* @param bool $skipSuperAttribute
*
* @return \Illuminate\Support\Collection
* @throws \Exception
*/
public function getEditableAttributes($group = null, $skipSuperAttribute = true): Collection
{
return $this->getTypeInstance()
->getEditableAttributes($group, $skipSuperAttribute);
2018-08-01 06:11:33 +00:00
}
2018-08-30 13:22:15 +00:00
2018-10-10 10:26:27 +00:00
/**
* Get an product attribute value.
*
* @return mixed
*/
public function getCustomAttributeValue($attribute)
{
if (!$attribute) {
2018-10-10 10:26:27 +00:00
return;
2020-02-20 06:12:17 +00:00
}
2018-10-10 10:26:27 +00:00
2021-10-06 12:26:08 +00:00
$locale = core()->checkRequestedLocaleCodeInRequestedChannel();
2021-06-08 09:54:51 +00:00
$channel = core()->getRequestedChannelCode();
2018-10-10 10:26:27 +00:00
if (array_key_exists($this->id, self::$loadedAttributeValues)
&& array_key_exists($attribute->id, self::$loadedAttributeValues[$this->id])) {
2021-07-20 09:24:22 +00:00
return self::$loadedAttributeValues[$this->id][$attribute->id];
2021-07-20 07:47:06 +00:00
}
2019-01-15 11:54:41 +00:00
if ($attribute->value_per_channel) {
if ($attribute->value_per_locale) {
$attributeValue = $this->attribute_values()
->where('channel', $channel)
->where('locale', $locale)
->where('attribute_id', $attribute->id)
->first();
2018-10-10 10:26:27 +00:00
} else {
$attributeValue = $this->attribute_values()
->where('channel', $channel)
->where('attribute_id', $attribute->id)
->first();
2018-10-10 10:26:27 +00:00
}
} else {
2019-01-15 11:54:41 +00:00
if ($attribute->value_per_locale) {
$attributeValue = $this->attribute_values()
->where('locale', $locale)
->where('attribute_id', $attribute->id)
->first();
2018-10-10 10:26:27 +00:00
} else {
$attributeValue = $this->attribute_values()
->where('attribute_id', $attribute->id)
->first();
2018-10-10 10:26:27 +00:00
}
}
2021-07-20 09:24:22 +00:00
return self::$loadedAttributeValues[$this->id][$attribute->id] = $attributeValue[ProductAttributeValue::$attributeTypeFields[$attribute->type]] ?? null;
2018-10-10 10:26:27 +00:00
}
/**
* Attributes to array.
*
* @return array
*/
public function attributesToArray(): array
{
$attributes = parent::attributesToArray();
$hiddenAttributes = $this->getHidden();
if (isset($this->id)) {
$familyAttributes = $this->checkInLoadedFamilyAttributes();
foreach ($familyAttributes as $attribute) {
if (in_array($attribute->code, $hiddenAttributes)) {
continue;
}
$attributes[$attribute->code] = $this->getCustomAttributeValue($attribute);
}
}
return $attributes;
}
2018-08-30 13:22:15 +00:00
/**
* Overrides the default Eloquent query builder.
2020-07-30 12:15:54 +00:00
*
* @param \Illuminate\Database\Query\Builder $query
*
* @return \Webkul\Product\Database\Eloquent\Builder
2018-08-30 13:22:15 +00:00
*/
public function newEloquentBuilder($query)
{
2020-07-30 12:15:54 +00:00
return new Builder($query);
2018-08-30 13:22:15 +00:00
}
2019-04-16 11:07:52 +00:00
/**
* Return the product id attribute.
*/
public function getProductIdAttribute()
{
2019-04-18 07:22:51 +00:00
return $this->id;
2019-04-16 11:07:52 +00:00
}
2019-04-18 07:22:51 +00:00
/**
* Return the product attribute.
*/
public function getProductAttribute()
{
return $this;
}
/**
* Check in loaded family attributes.
*
* @return object
*/
public function checkInLoadedFamilyAttributes(): object
{
static $loadedFamilyAttributes = [];
if (array_key_exists($this->attribute_family_id, $loadedFamilyAttributes)) {
return $loadedFamilyAttributes[$this->attribute_family_id];
}
return $loadedFamilyAttributes[$this->attribute_family_id] = core()
->getSingletonInstance(AttributeRepository::class)
->getFamilyAttributes($this->attribute_family);
}
/**
* Create a new factory instance for the model.
*
* @return ProductFactory
*/
protected static function newFactory(): ProductFactory
{
return ProductFactory::new();
}
}