<?php
/**
* Copyright (c) 2011-present Qualiteam software Ltd. All rights reserved.
* See https://www.x-cart.com/license-agreement.html for license details.
*/
namespace XC\WheelTireFitment\Model;
use Doctrine\ORM\Mapping as ORM;
use Includes\Utils\Converter as UtilsConverter;
use Includes\Utils\ArrayManager;
use XC\WheelTireFitment\Core\WheelTireProductAttributeFields;
/**
* @ORM\Entity
* @ORM\Table (name="vehicle_attribute_values",
* uniqueConstraints={
* @ORM\UniqueConstraint (name="ih", columns={"id", "hash"})
* }
* )
* @ORM\HasLifecycleCallbacks
*/
class VehicleAttributeValue extends AVehicleAttribute
{
public const FITMENT_TYPE_ORIGINAL = 'OR';
public const FITMENT_TYPE_OPTIONAL = 'OP';
public const FITMENT_TYPE_PLUS_SIZE = 'LS';
public const WHEEL_SIZE_PATTERN_STRING = '{rimDiameter}″x{rimWidth}″';
public const TIRE_SIZE_PATTERN_STRING = '{sectionWidth}/{aspectRatio}R{rimDiameter}';
public const SCHEMA_FRONT_NAME = 'front';
public const SCHEMA_REAR_NAME = 'rear';
public const SCHEMA_WHEEL_NAME = 'wheel';
public const SCHEMA_TIRE_NAME = 'tire';
/**
* @var int
*
* @ORM\Id
* @ORM\GeneratedValue (strategy="AUTO")
* @ORM\Column (type="integer", options={ "unsigned": true })
*/
protected $id;
/**
* @var integer
*
* @ORM\Column (type="integer")
*/
protected $aspectRatio;
/**
* @var integer
*
* @ORM\Column (type="integer")
*/
protected $aspectRatioRear;
/**
* @var integer
*
* @ORM\Column (type="integer")
*/
protected $rimDiameter;
/**
* @var integer
*
* @ORM\Column (type="integer")
*/
protected $rimDiameterRear;
/**
* @var float
*
* @ORM\Column (type="decimal", precision=3, scale=1)
*/
protected $rimWidth;
/**
* @var float
*
* @ORM\Column (type="decimal", precision=3, scale=1)
*/
protected $rimWidthRear;
/**
* @var integer
*
* @ORM\Column (type="integer")
*/
protected $sectionWidth;
/**
* @var integer
*
* @ORM\Column (type="integer")
*/
protected $sectionWidthRear;
/**
* Fitment type (Original, Optional, Plus size)
*
* @var string
*
* @ORM\Column (type="string", options={"fixed": true, "default": "OR"}, length=2)
*/
protected $type = self::FITMENT_TYPE_ORIGINAL;
/**
* Attributes hash
*
* @var string
*
* @ORM\Column (type="string", nullable=true)
*/
protected $hash;
/**
* @var VehicleAttributeGroup
*
* @ORM\ManyToOne (targetEntity="XC\WheelTireFitment\Model\VehicleAttributeGroup", inversedBy="attributes")
* @ORM\JoinColumn (name="vehicleAttributeGroup", referencedColumnName="id", onDelete="CASCADE")
*/
protected $vehicleAttributeGroup;
public function getId(): ?int
{
return $this->id;
}
public function getAspectRatio(): int
{
return $this->aspectRatio;
}
public function setAspectRatio($aspectRatio): void
{
$this->aspectRatio = (int) $aspectRatio;
}
public function getAspectRatioRear(): int
{
return $this->aspectRatioRear;
}
public function setAspectRatioRear($aspectRatioRear): void
{
$this->aspectRatioRear = (int) $aspectRatioRear;
}
public function getRimDiameter(): int
{
return $this->rimDiameter;
}
public function setRimDiameter($rimDiameter): void
{
$this->rimDiameter = (int) $rimDiameter;
}
public function getRimDiameterRear(): int
{
return $this->rimDiameterRear;
}
public function setRimDiameterRear($rimDiameterRear): void
{
$this->rimDiameterRear = (int) $rimDiameterRear;
}
public function getRimWidth(): float
{
return $this->rimWidth;
}
public function setRimWidth($rimWidth): void
{
$this->rimWidth = (float) $rimWidth;
}
public function getRimWidthRear(): float
{
return $this->rimWidthRear;
}
public function setRimWidthRear($rimWidthRear): void
{
$this->rimWidthRear = (float) $rimWidthRear;
}
public function getSectionWidth(): int
{
return $this->sectionWidth;
}
public function setSectionWidth($sectionWidth): void
{
$this->sectionWidth = (int) $sectionWidth;
}
public function getSectionWidthRear(): int
{
return $this->sectionWidthRear;
}
public function setSectionWidthRear($sectionWidthRear): void
{
$this->sectionWidthRear = (int) $sectionWidthRear;
}
public function getType(): string
{
return $this->type;
}
public function setType(string $type): void
{
$this->type = $type;
}
public function getVehicleAttributeGroup(): VehicleAttributeGroup
{
return $this->vehicleAttributeGroup;
}
public function setVehicleAttributeGroup(VehicleAttributeGroup $vehicleAttributeGroup)
{
$this->vehicleAttributeGroup = $vehicleAttributeGroup;
}
public function getHash(): string
{
return $this->hash;
}
public function setHash(string $hash): void
{
$this->hash = $hash;
}
public static function getHashFields(): array
{
return [
'AspectRatio',
'AspectRatioRear',
'RimDiameter',
'RimDiameterRear',
'RimWidth',
'RimWidthRear',
'SectionWidth',
'SectionWidthRear',
'Type',
];
}
public static function getHashDataBy(array $data): array
{
$result = [];
foreach (static::getHashFields() as $fieldName) {
if (!empty($data[$fieldName])) {
$result[$fieldName] = $data[$fieldName];
}
}
return $result;
}
public function getHashData(): array
{
$result = [];
foreach (static::getHashFields() as $fieldName) {
$method = 'get' . UtilsConverter::convertToUpperCamelCase($fieldName);
if (method_exists($this, $method)) {
$result[$fieldName] = $this->$method();
}
}
return $result;
}
public static function calcHash(array $data): string
{
return ArrayManager::md5($data);
}
/**
* @ORM\PrePersist
* @ORM\PreUpdate
*/
public function processBeforeUpdate(): void
{
$data = $this->getHashData();
$this->setHash(static::calcHash($data));
}
public function getWheelReadableSize(bool $isFront = true): string
{
$methodSuffix = $isFront ? '' : 'Rear';
return str_replace(
['{rimDiameter}', '{rimWidth}'],
[
$this->{'getRimDiameter' . $methodSuffix}(),
$this->{'getRimWidth' . $methodSuffix}(),
],
static::WHEEL_SIZE_PATTERN_STRING
);
}
public function getTireReadableSize(bool $isFront = true): string
{
$methodSuffix = $isFront ? '' : 'Rear';
return str_replace(
['{sectionWidth}', '{aspectRatio}', '{rimDiameter}'],
[
$this->{'getSectionWidth' . $methodSuffix}(),
$this->{'getAspectRatio' . $methodSuffix}(),
$this->{'getRimDiameter' . $methodSuffix}(),
],
static::TIRE_SIZE_PATTERN_STRING
);
}
public function getVehicleFrontAttributeValueSchema()
{
return [
static::SCHEMA_FRONT_NAME =>
[
static::SCHEMA_WHEEL_NAME => $this->getWheelReadableSize(),
static::SCHEMA_TIRE_NAME => $this->getTireReadableSize(),
],
];
}
public function getVehicleRearAttributeValueSchema()
{
return [
static::SCHEMA_REAR_NAME =>
[
static::SCHEMA_WHEEL_NAME => $this->getWheelReadableSize(false),
static::SCHEMA_TIRE_NAME => $this->getTireReadableSize(false),
],
];
}
public static function getVisibleFitmentTypes(): array
{
return [
static::FITMENT_TYPE_ORIGINAL,
static::FITMENT_TYPE_OPTIONAL,
static::FITMENT_TYPE_PLUS_SIZE
];
}
public static function getFitmentTypeLabels(): array
{
return [
static::FITMENT_TYPE_ORIGINAL => static::t('[wts] Fitment type Original'),
static::FITMENT_TYPE_OPTIONAL => static::t('[wts] Fitment type Optional'),
static::FITMENT_TYPE_PLUS_SIZE => static::t('[wts] Fitment type Plus Sizes'),
];
}
public static function getFitmentTypeLabel(string $type): string
{
$result = '';
$labels = VehicleAttributeValue::getFitmentTypeLabels();
if (
$type
&& $labels
&& isset($labels[$type])
) {
$result = $labels[$type];
}
return $result;
}
public static function getMapProductVehicleAttributes(): array
{
return [
WheelTireProductAttributeFields::WHEEL_RIM_SIZE_DIAMETER => 'rimDiameter',
WheelTireProductAttributeFields::WHEEL_RIM_SIZE_WIDTH => 'rimWidth',
WheelTireProductAttributeFields::TIRE_SIZE_SECTION_WIDTH => 'sectionWidth',
WheelTireProductAttributeFields::TIRE_SIZE_ASPECT_RATIO => 'aspectRatio',
WheelTireProductAttributeFields::TIRE_SIZE_RIM_DIAMETER => 'rimDiameter',
];
}
public function getProductAttributeFilterValues(array $filterFields = [], string $suffix = ''): array
{
$resultFront = parent::getProductAttributeFilterValues($filterFields);
$resultRear = parent::getProductAttributeFilterValues($filterFields, 'Rear');
$fields = static::getMapProductVehicleAttributes();
foreach ($fields as $productAttributeName => $modelFieldName) {
if (
isset($resultFront[$productAttributeName])
&& $resultFront[$productAttributeName] != $resultRear[$productAttributeName]
) {
$resultFront[$productAttributeName] = [
$resultFront[$productAttributeName],
$resultRear[$productAttributeName],
];
}
}
return $resultFront;
}
public function isMatchingAnyFitment(array $values): array
{
$wheelRes = $this->isMatchingAsWheelFitment($values);
$tireRes = $this->isMatchingAsTireFitment($values);
return [
$wheelRes[0] + $tireRes[0],
$wheelRes[1] || $tireRes[1]
];
}
public function isMatchingAsWheelFitment(array $values): array
{
$wheelValues = array_merge(
$this->getProductAttributeFilterValues(
WheelTireProductAttributeFields::getWheelSizeFields()
),
$this->getProductAttributeFilterValues(
WheelTireProductAttributeFields::getWheelSizeFields(),
'Rear'
)
);
return $this->isMatchingVehicleValuesWithFilterValues(
$wheelValues,
$values
);
}
public function isMatchingAsTireFitment(array $values): array
{
$tireValues = $this->getProductAttributeFilterValues(
WheelTireProductAttributeFields::getTireSizeFields()
);
return $this->isMatchingVehicleValuesWithFilterValues(
$tireValues,
$values
);
}
protected function isMatchingVehicleValuesWithFilterValues(array $vehicleValues, array $filterValues): array
{
$score = 0;
$attrsMatching = [];
foreach ($vehicleValues as $name => $vehicleValue) {
$vehicleValue = self::prepareValue($vehicleValue);
$filterValue = self::prepareValue($filterValues[$name] ?? null);
$intersect = array_intersect($filterValue, $vehicleValue);
$score += count($intersect);
$attrsMatching[$name] = count($intersect) === count($vehicleValue) && count($intersect) === count($filterValue);
}
return [
$score,
count(array_filter($attrsMatching)) === count($vehicleValues)
];
}
protected static function prepareValue($value): array
{
if (!is_array($value)) {
$value = [$value];
}
return $value;
}
}