|
|
<?php
|
|
|
|
|
|
class GoodsPropertyTool {
|
|
|
|
|
|
public static function propertyControlTypeList() {
|
|
|
return [
|
|
|
MoveConst::propControlTypeInput => 'input',
|
|
|
MoveConst::propControlTypeYmdTimeSelect => 'input',
|
|
|
MoveConst::propControlTypeYmTimeSelect => 'input',
|
|
|
MoveConst::propControlTypeNumericalProductV2 => 'input',
|
|
|
MoveConst::propControlTypeInputSelect => 'select',
|
|
|
MoveConst::propControlTypeSelect => 'select',
|
|
|
];
|
|
|
}
|
|
|
|
|
|
public static function implodePropertyValues($goodsPropertyList) {
|
|
|
$newPropertyList = [];
|
|
|
foreach($goodsPropertyList as $prop) {
|
|
|
if(!isset($newPropertyList[$prop['template_pid']])) {
|
|
|
$newPropertyList[$prop['template_pid']] = $prop;
|
|
|
$newPropertyList[$prop['template_pid']]['vid'] = [];
|
|
|
$newPropertyList[$prop['template_pid']]['value'] = [];
|
|
|
}
|
|
|
$newPropertyList[$prop['template_pid']]['vid'][] = $prop['vid'];
|
|
|
$newPropertyList[$prop['template_pid']]['value'][] = $prop['value'];
|
|
|
}
|
|
|
return $newPropertyList;
|
|
|
}
|
|
|
|
|
|
public static function explodePropertyValues($goodsPropertyList) {
|
|
|
$newPropertyList = [];
|
|
|
foreach($goodsPropertyList as $prop) {
|
|
|
if (is_array($prop['value'])) {
|
|
|
foreach($prop['value'] as $key => $value) {
|
|
|
$newProp = $prop;
|
|
|
$newProp['value'] = $value;
|
|
|
$newProp['vid'] = $prop['vid'][$key];
|
|
|
$newPropertyList[] = $newProp;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
}
|
|
|
return $newPropertyList;
|
|
|
}
|
|
|
|
|
|
public static function isSelectControlType($controlType) {
|
|
|
return in_array($controlType, [
|
|
|
MoveConst::propControlTypeInputSelect,
|
|
|
MoveConst::propControlTypeSelect,
|
|
|
]);
|
|
|
}
|
|
|
public static function isSingleSelectControlType($controlType, $chooseMaxNum) {
|
|
|
return self::isSelectControlType($controlType) && $chooseMaxNum == 1;
|
|
|
}
|
|
|
|
|
|
public static function isMultiSelectControlType($controlType, $chooseMaxNum) {
|
|
|
return self::isSelectControlType($controlType) && $chooseMaxNum > 1;
|
|
|
}
|
|
|
|
|
|
public static function getPropertyGroupList($allPropertyList, $excludeBrand = false) {
|
|
|
$controlTypeMap = self::propertyControlTypeList();
|
|
|
foreach ($allPropertyList as $key => $property) {
|
|
|
if ($property['is_sale']) {
|
|
|
unset($allPropertyList[$key]);
|
|
|
continue;
|
|
|
}
|
|
|
if ($excludeBrand && $property['name_alias'] == '品牌') {
|
|
|
unset($allPropertyList[$key]);
|
|
|
continue;
|
|
|
}
|
|
|
$allPropertyList[$key]['control_type_name'] = ($property['choose_max_num'] > 1 ? 'multi-' : '') . $controlTypeMap[$property['control_type']];
|
|
|
}
|
|
|
$groupList = [];
|
|
|
$propertyTreeList = self::getPropertyTreeList($allPropertyList, [], $excludeBrand);
|
|
|
$propIdPropertyMap = ZcArrayHelper::changeKeyRow($allPropertyList, 'id');
|
|
|
foreach($propertyTreeList as $tree) {
|
|
|
$topPropInfo = $propIdPropertyMap[$tree['id']];
|
|
|
list(, , $allChildPropList) = self::getPropTreePropIds($tree, $propIdPropertyMap);
|
|
|
$topPropInfo['all_children'] = $allChildPropList;
|
|
|
$groupList[] = $topPropInfo;
|
|
|
}
|
|
|
|
|
|
return $groupList;
|
|
|
}
|
|
|
|
|
|
public static function buildGoodsPropertyList($allPropertyList, $goodsPropertyList) {
|
|
|
$newProps = [];
|
|
|
$properties = ZcArrayHelper::changeKeyRow($allPropertyList, 'ref_pid');
|
|
|
foreach ($goodsPropertyList as $goodsProperty) {
|
|
|
$propertyInfo = $properties[$goodsProperty['ref_pid']];
|
|
|
if (empty($propertyInfo)) {
|
|
|
continue;
|
|
|
}
|
|
|
$newProps[] = [
|
|
|
'ref_pid' => $propertyInfo['ref_pid'],
|
|
|
'template_pid' => $propertyInfo['id'],
|
|
|
'pid' => $propertyInfo['parent_id'],
|
|
|
'vid' => $goodsProperty['vid'],
|
|
|
'value' => $goodsProperty['vvalue'],
|
|
|
'value_unit' => $goodsProperty['punit'] ? $goodsProperty['punit'] : explode(',', $goodsProperty['value_unit'])[0],
|
|
|
];
|
|
|
}
|
|
|
return $newProps;
|
|
|
}
|
|
|
|
|
|
public static function buildEmptyProperty($propertyId, $parentId = 0) {
|
|
|
return [
|
|
|
'template_pid' => $propertyId,
|
|
|
'pid' => $parentId,
|
|
|
'vid' => 0,
|
|
|
'value' => '',
|
|
|
'value_unit' => '',
|
|
|
];
|
|
|
}
|
|
|
|
|
|
public static function getBrandProperty($allPropertyList) {
|
|
|
foreach ($allPropertyList as $property) {
|
|
|
if ($property['name_alias'] == '品牌') {
|
|
|
return $property;
|
|
|
}
|
|
|
}
|
|
|
return [];
|
|
|
}
|
|
|
|
|
|
public static function replaceGoodsPropertyValues($allPropertyList, $oldProps, $replacePropKvMap, $replacePropUnitKvMap = array()) {
|
|
|
$newProps = [];
|
|
|
$changePropIds = [];
|
|
|
$oldProps = ZcArrayHelper::changeKey($oldProps, 'template_pid', true);
|
|
|
|
|
|
$propertyTreeList = self::getPropertyTreeList($allPropertyList, [], true);
|
|
|
$propIdPropertyMap = ZcArrayHelper::changeKeyRow($allPropertyList, 'id');
|
|
|
$topIdPropGroupIdsMap = [];
|
|
|
foreach ($propertyTreeList as $tree) {
|
|
|
list($treeRequirePropIds, $treePropIds) = self::getPropTreePropIds($tree, $propIdPropertyMap);
|
|
|
$topIdPropGroupIdsMap[$tree['id']] = $treePropIds;
|
|
|
}
|
|
|
|
|
|
$brandProperty = self::getBrandProperty($allPropertyList);
|
|
|
$topTemplateIds = array_keys($topIdPropGroupIdsMap);
|
|
|
$oldTemplateIds = array_keys($oldProps);
|
|
|
$replaceTopTemplateIds = [];
|
|
|
foreach ($replacePropKvMap as $propId => $propValue) {
|
|
|
if (in_array($propId, $topTemplateIds)) {
|
|
|
$replaceTopTemplateIds[] = $propId;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
$deleteTemplateIds = [];
|
|
|
foreach (array_intersect($oldTemplateIds, $replaceTopTemplateIds) as $pid) {
|
|
|
$deleteTemplateIds = array_merge($deleteTemplateIds, $topIdPropGroupIdsMap[$pid] ?: []);
|
|
|
}
|
|
|
|
|
|
foreach ($oldProps as $propId => $propValues) {
|
|
|
if (!in_array($propId, $deleteTemplateIds)) {
|
|
|
$newProps[$propId] = $propValues;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
foreach ($replacePropKvMap as $propId => $propVids) {
|
|
|
if ($brandProperty['id'] == $propId) {
|
|
|
continue;
|
|
|
}
|
|
|
if ($newProps[$propId]) {
|
|
|
continue;
|
|
|
}
|
|
|
$changePropIds[] = $propId;
|
|
|
$propertyInfo = $propIdPropertyMap[$propId];
|
|
|
$valueList = self::findPropertyValue($propertyInfo, $propVids);
|
|
|
foreach ($valueList as $value) {
|
|
|
$newProps[$propId][] = [
|
|
|
'template_pid' => $propertyInfo['id'],
|
|
|
'pid' => $propertyInfo['parent_id'],
|
|
|
'vid' => $value['vid'],
|
|
|
'value' => $value['value'],
|
|
|
'value_unit' => $replacePropUnitKvMap[$propId] ? : explode(',', $propertyInfo['value_unit'])[0],
|
|
|
];
|
|
|
}
|
|
|
}
|
|
|
$retNewProps = [];
|
|
|
foreach($newProps as $newProp) {
|
|
|
$retNewProps = array_merge($retNewProps, $newProp);
|
|
|
}
|
|
|
return [$retNewProps, $changePropIds];
|
|
|
}
|
|
|
|
|
|
public static function findPropertyValue($propertyInfo, $vids) {
|
|
|
$valueList = [];
|
|
|
switch ($propertyInfo['control_type']) {
|
|
|
case MoveConst::propControlTypeInput :
|
|
|
case MoveConst::propControlTypeYmdTimeSelect :
|
|
|
case MoveConst::propControlTypeYmTimeSelect :
|
|
|
case MoveConst::propControlTypeNumericalProductV2 :
|
|
|
case MoveConst::propControlTypeRangeYmdTimeSelect :// zzq 暂时没有测试用例
|
|
|
case MoveConst::propControlTypeRangeYmSelect :// zzq 暂时没有测试用例
|
|
|
$valueList[] = [
|
|
|
'vid' => '',
|
|
|
'value' => $vids
|
|
|
];
|
|
|
break;
|
|
|
case MoveConst::propControlTypeInputSelect:
|
|
|
case MoveConst::propControlTypeSelect :
|
|
|
$vids = is_array($vids) ? $vids : [$vids];
|
|
|
foreach ($propertyInfo['values'] as $value) {
|
|
|
if (in_array($value['vid'], $vids)) {
|
|
|
$valueList[] = $value;
|
|
|
}
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
return $valueList;
|
|
|
}
|
|
|
|
|
|
public static function getPropertyTreeList($allPropertyList, $returnFields = [], $excludeBrand = false) {
|
|
|
$parentIdChildPropMap = ZcArrayHelper::changeKey($allPropertyList, 'parent_id', true);
|
|
|
$treeList = [];
|
|
|
foreach ($allPropertyList as $prop) {
|
|
|
if ($prop['parent_id']) {
|
|
|
continue;
|
|
|
}
|
|
|
if ($excludeBrand && $prop['name_alias'] == '品牌') {
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
$propTree = self::getPropTree($parentIdChildPropMap, $prop, $returnFields);
|
|
|
$treeList[] = $propTree;
|
|
|
}
|
|
|
return $treeList;
|
|
|
}
|
|
|
|
|
|
protected static function getPropTreePropIds($propTree, $propIdPropertyMap) {
|
|
|
$treeRequirePropIds = $treePropIds = $allChildPropList = [];
|
|
|
$propStack = [$propTree];
|
|
|
while (true) {
|
|
|
$prop = array_pop($propStack);
|
|
|
if (empty($prop)) {
|
|
|
break;
|
|
|
}
|
|
|
$propInfo = $propIdPropertyMap[$prop['id']];
|
|
|
if ($propInfo['parent_id']) {
|
|
|
$allChildPropList[] = $propInfo;
|
|
|
}
|
|
|
if ($propInfo['required']) {
|
|
|
$treeRequirePropIds[] = $prop['id'];
|
|
|
}
|
|
|
$treePropIds[] = $prop['id'];
|
|
|
if (!empty($prop['child'])) {
|
|
|
$propStack = array_merge($propStack, $prop['child']);
|
|
|
}
|
|
|
if (count($propStack) == 0) {
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
return [$treeRequirePropIds, $treePropIds, $allChildPropList];
|
|
|
}
|
|
|
|
|
|
protected static function getPropTree($parentIdChildPropMap, $parentProp, $returnFields = []) {
|
|
|
$parentId = $parentProp['id'];
|
|
|
$childList = $parentIdChildPropMap[$parentId];
|
|
|
$returnProp = $returnFields ? ZcArrayHelper::filterColumns($parentProp, $returnFields) : $parentProp;
|
|
|
$childTree = [];
|
|
|
if (!empty($childList)) {
|
|
|
foreach ($childList as $childProp) {
|
|
|
$childTree[] = self::getPropTree($parentIdChildPropMap, $childProp);
|
|
|
}
|
|
|
}
|
|
|
$returnProp['child'] = $childTree;
|
|
|
return $returnProp;
|
|
|
}
|
|
|
|
|
|
public static function checkHasOtherKeyWord($word) {
|
|
|
if ((strpos($word, '其它') !== false) || (strpos($word, '其他') !== false) || (stripos($word, 'other') !== false)) {
|
|
|
return true;
|
|
|
} else {
|
|
|
return false;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
public static function checkGoodsNameHasBrand($goodsName, $brandName) {
|
|
|
if (CommonTool::anyEmpty($goodsName, $brandName)) {
|
|
|
return false;
|
|
|
}
|
|
|
$splitPattern = '/[\(\/\)()\s]/isuU';
|
|
|
$brandNameArr = preg_split($splitPattern, strtolower($brandName));
|
|
|
foreach ($brandNameArr as $splitBrandName) {
|
|
|
if (stripos($goodsName, $splitBrandName) !== false) {
|
|
|
return true;
|
|
|
}
|
|
|
}
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
public static function checkBrandNamesIsSame($inputBrandName, $sourceBrandName) {
|
|
|
if (CommonTool::anyEmpty($inputBrandName, $sourceBrandName)) {
|
|
|
return false;
|
|
|
}
|
|
|
$splitPattern = '/[\(\/\)()\s]/isuU';
|
|
|
$inputBrandNameArr = preg_split($splitPattern, strtolower($inputBrandName));
|
|
|
$sourceBrandNameArr = preg_split($splitPattern, strtolower($sourceBrandName));
|
|
|
return !empty(array_intersect($inputBrandNameArr, $sourceBrandNameArr));
|
|
|
}
|
|
|
|
|
|
public static function buildGoodsPropertyListByValueMap($allPropertyList, $nameValueMap, $defaultOptions) {
|
|
|
$parentIdChildPropMap = ZcArrayHelper::changeKey($allPropertyList, 'parent_id', true);
|
|
|
$newProps = [];
|
|
|
foreach ($allPropertyList as $property) {
|
|
|
if ($property['parent_id']) {
|
|
|
continue;
|
|
|
}
|
|
|
if ($property['is_sale']) {
|
|
|
continue;
|
|
|
}
|
|
|
$matchProps = self::matchPropertyTreeValue($property, [], $nameValueMap, $parentIdChildPropMap, $defaultOptions);
|
|
|
if ($matchProps && is_array($matchProps)) {
|
|
|
$newProps = array_merge($newProps, $matchProps);
|
|
|
}
|
|
|
}
|
|
|
return self::explodePropertyValues($newProps);
|
|
|
}
|
|
|
|
|
|
public static function matchPropertyTreeValue($property, $parentVids, $nameValueMap, $parentIdChildPropMap, $defaultOptions) {
|
|
|
$parentVids = $parentVids ?: [];
|
|
|
|
|
|
$currentValue = [];
|
|
|
$matchValueList = [];
|
|
|
$value = $nameValueMap[$property['name_alias']];
|
|
|
$valueList = is_array($value['value']) ? $value['value'] : explode(',', $value['value']);
|
|
|
$valueList = array_map('trim', $valueList);
|
|
|
|
|
|
if (self::isSelectControlType($property['control_type'])) {
|
|
|
$usableValues = self::getPropertyUsableValues($property, $parentVids);
|
|
|
foreach ($usableValues as $v) {
|
|
|
if (in_array($v['value'], $valueList)) {
|
|
|
$currentValue['value'][] = $v['value'];
|
|
|
$currentValue['vid'][] = $v['vid'];
|
|
|
}
|
|
|
}
|
|
|
if (empty($currentValue) && $defaultOptions['select'] == 'otherOrLast') {
|
|
|
$currentValue = self::getPropertyValueOtherOrLast($usableValues);
|
|
|
}
|
|
|
} else {
|
|
|
if (self::getPropertyCanShow($property, $parentVids)) {
|
|
|
if (($property['value_type'] == MoveConst::propValueTypeNumber) && ($valueList[0] || $defaultOptions['number'])) {
|
|
|
$currentValue['value'][] = $valueList[0] ?: $defaultOptions['number'];
|
|
|
} else if (($property['value_type'] == MoveConst::propValueTypeText) && ($valueList[0] || $defaultOptions['text'])) {
|
|
|
$currentValue['value'][] = $valueList[0] ?: $defaultOptions['text'];
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if ($currentValue) {
|
|
|
if ($property['choose_max_num'] > 1) {
|
|
|
$currentValue['value'] = array_slice( $currentValue['value'], 0, $property['choose_max_num']);
|
|
|
$currentValue['vid'] = array_slice( $currentValue['vid'], 0, $property['choose_max_num']);
|
|
|
}
|
|
|
$currentValue['template_pid'] = $property['id'];
|
|
|
$currentValue['pid'] = $property['parent_id'];
|
|
|
$currentValue['value_unit'] = $value['value_unit'] ? : explode(',', $property['value_unit'])[0];
|
|
|
$matchValueList[] = $currentValue;
|
|
|
}
|
|
|
|
|
|
foreach ($parentIdChildPropMap[$property['id']] as $childProperty) {
|
|
|
if ($childProperty['is_sale']) {
|
|
|
continue;
|
|
|
}
|
|
|
$childMathValueList = self::matchPropertyTreeValue($childProperty, $currentValue['vid'], $nameValueMap, $parentIdChildPropMap, $defaultOptions);
|
|
|
if ($childMathValueList) {
|
|
|
$matchValueList = array_merge($matchValueList, $childMathValueList);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return $matchValueList;
|
|
|
}
|
|
|
|
|
|
public static function getPropertyValueOtherOrLast($valueList) {
|
|
|
$matchValue = [];
|
|
|
foreach ($valueList as $v) {
|
|
|
if (self::checkHasOtherKeyWord($v['value'])) {
|
|
|
$matchValue['value'][] = $v['value'];
|
|
|
$matchValue['vid'][] = $v['vid'];
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
if (empty($matchValue) && $valueList) {
|
|
|
$matchValue['value'][] = end($valueList)['value'];
|
|
|
$matchValue['vid'][] = end($valueList)['vid'];
|
|
|
}
|
|
|
|
|
|
return $matchValue;
|
|
|
}
|
|
|
|
|
|
public static function getPropertyCanShow($property, $parentVids) {
|
|
|
if($property['is_condition_show'] && $property['show_vids'] && !in_array($parentVids[0], $property['show_vids'])){
|
|
|
return false;
|
|
|
}
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
public static function getPropertyUsableValues($property, $parentVids) {
|
|
|
if (!self::getPropertyCanShow($property, $parentVids)) {
|
|
|
return [];
|
|
|
}
|
|
|
|
|
|
$usableValues = [];
|
|
|
foreach ($property['values'] as $value) {
|
|
|
if (empty($value['parent_vids']) || array_intersect($parentVids, $value['parent_vids'])) {
|
|
|
$usableValues[] = $value;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return $usableValues;
|
|
|
}
|
|
|
}
|