Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support localized calculated fields in object bricks #5390

Expand Up @@ -630,7 +630,7 @@ private function getDataForField($object, $key, $fielddefinition, $objectFromVer

if ($fielddefinition instanceof DataObject\ClassDefinition\Data\CalculatedValue) {
$fieldData = new DataObject\Data\CalculatedValue($fielddefinition->getName());
$fieldData->setContextualData('object', null, null, null);
$fieldData->setContextualData('object', null, null, null, null, null, $fielddefinition);
$value = $fielddefinition->getDataForEditmode($fieldData, $object, ['objectFromVersion' => $objectFromVersion]);
} else {
$value = $fielddefinition->getDataForEditmode($fieldData, $object, ['objectFromVersion' => $objectFromVersion]);
Expand Down
Expand Up @@ -99,6 +99,7 @@ As said before, the richness of the context information depends on the location
| fieldName | the name of the attribute inside the brick |
| index | the name of the brick |
| keyDefinition | the calculated-value field definition |
| position | the language ("en", "de", ...) if calculated field is localized |


#### Fieldcollections
Expand Down
57 changes: 45 additions & 12 deletions models/DataObject/ClassDefinition/Data/CalculatedValue.php
Expand Up @@ -158,16 +158,16 @@ public function getDataForQueryResource($data, $object = null, $params = [])
/**
* @see Data::getDataForEditmode
*
* @param float $data
* @param null|Model\DataObject\AbstractObject $object
* @param mixed $params
* @param Model\DataObject\Data\CalculatedValue $data
* @param DataObject\Concrete $object
* @param array $params
*
* @return float
* @return string|null
*/
public function getDataForEditmode($data, $object = null, $params = [])
{
if ($data instanceof Model\DataObject\Data\CalculatedValue) {
$data = Model\DataObject\Service::getCalculatedFieldValueForEditMode($object, [], $data);
return Model\DataObject\Service::getCalculatedFieldValueForEditMode($object, $params, $data);
}

return $data;
Expand Down Expand Up @@ -303,9 +303,15 @@ public function getGetterCode($class)
$code .= "\t" . '$data' . " = new \\Pimcore\\Model\\DataObject\\Data\\CalculatedValue('" . $key . "');\n";
$code .= "\t" . '$data->setContextualData("object", null, null, null);' . "\n";

$code .= "\t" . '$data = Service::getCalculatedFieldValue($this, $data);' . "\n";
if($class instanceof DataObject\Objectbrick\Definition) {
$code .= "\t" . '$object = $this->getObject();' . "\n";
} else {
$code .= "\t" . '$object = $this;' . "\n";
}

$code .= "\t" . '$data = \\Pimcore\\Model\\DataObject\\Service::getCalculatedFieldValue($object, $data);' . "\n";
$code .= "\treturn " . '$data' . ";\n";
$code .= "\t" . "}\n\n";
$code .= "}\n\n";

return $code;
}
Expand Down Expand Up @@ -338,12 +344,32 @@ public function getGetterCodeLocalizedfields($class)
$code .= "\t\t" . '}' . "\n";
$code .= "\t" . '}' . "\n";

if($class instanceof DataObject\Objectbrick\Definition) {
$ownerType = 'objectbrick';
$ownerName = $class->getClassDefinitions()[0]['fieldname']; // todo this is not really correct. Actually we need to find out the name of the brick container (an instance of \Pimcore\Model\DataObject\Objectbrick). This must happen during runtime as one brick can be used in multiple brick containers.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is the right interpretation of the comment ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This means that we cannot determine the name of the class with the brick container field when the brick gets saved. Actually we need to add some code in the generated getter function to determine the brick container field during runtime but I did not find a way to do that because the generated brick class does not know anything in which brick container / data object class it is being used.
And because of that I chose a way to at least enhance the status quo (although this solution is not perfect) by setting the $ownerName to the first configured brick container field of the object brick.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, just noticed something.

foreach ($result['data'] as $language => &$data) {

The calculator only gets called if there are other fields with data in the localized field container?

What do you think?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just take it from $this ?

image

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is fieldname the calculated value field in the brick or the brick container field in the data object class? I need the latter.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the one in the data object class

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, then have overseen this. Thanks, I will change it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. My test was positive.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you also check this "I noticed something" thing ?

$index = $class->getKey();

$code .= "\t" . '$object = $this->getObject();' . "\n";
} else {
$ownerType = 'localizedfield';
$ownerName = 'localizedfields';
$index = null;

$code .= "\t" . '$object = $this;' . "\n";
}

if($class instanceof DataObject\Fieldcollection\Definition) {
$code .= "\t" . '$fieldDefinition = $this->getDefinition()->getFieldDefinition("localizedfields")->getFieldDefinition("'.$key.'");' . "\n";
} else {
$code .= "\t" . '$fieldDefinition = $this->getClass()->getFieldDefinition("localizedfields")->getFieldDefinition("'.$key.'");' . "\n";
}

$code .= "\t" . '$data' . " = new \\Pimcore\\Model\\DataObject\\Data\\CalculatedValue('" . $key . "');\n";
$code .= "\t" . '$data->setContextualData("localizedfield", "localizedfields", null, $language);' . "\n";
$code .= "\t" . '$data->setContextualData("'.$ownerType.'", "'.$ownerName.'", '.($index===null?'null':'"'.$index.'"').', $language, null, null, $fieldDefinition);' . "\n";

$code .= "\t" . '$data = Service::getCalculatedFieldValue($this, $data);' . "\n";
$code .= "\t" . '$data = \\Pimcore\\Model\\DataObject\\Service::getCalculatedFieldValue($object, $data);' . "\n";
$code .= "\treturn " . '$data' . ";\n";
$code .= "\t" . "}\n\n";
$code .= "}\n\n";

return $code;
}
Expand Down Expand Up @@ -373,7 +399,7 @@ public function getGetterCodeObjectbrick($brickClass)

$code .= "\t" . '$data = DataObject\Service::getCalculatedFieldValue($this->getObject(), $data);' . "\n";
$code .= "\treturn " . '$data' . ";\n";
$code .= "\t" . "}\n\n";
$code .= "}\n\n";

return $code;
}
Expand Down Expand Up @@ -495,11 +521,18 @@ public function getSetterCodeFieldcollection($fieldcollectionDefinition)
public function getSetterCodeLocalizedfields($class)
{
$key = $this->getName();
if ($class instanceof DataObject\Objectbrick\Definition) {
$classname = 'Objectbrick\\Data\\' . ucfirst($class->getKey());
} elseif ($class instanceof DataObject\Fieldcollection\Definition) {
$classname = 'FieldCollection\\Data\\' . ucfirst($class->getKey());
} else {
$classname = $class->getName();
}

$code = '/**' . "\n";
$code .= '* Set ' . str_replace(['/**', '*/', '//'], '', $this->getName()) . ' - ' . str_replace(['/**', '*/', '//'], '', $this->getTitle()) . "\n";
$code .= '* @param ' . $this->getPhpdocType() . ' $' . $key . "\n";
$code .= '* @return \\Pimcore\\Model\\DataObject\\' . ucfirst($class->getName()) . "\n";
$code .= '* @return \\Pimcore\\Model\\DataObject\\' . ucfirst($classname) . "\n";
$code .= '*/' . "\n";
$code .= 'public function set' . ucfirst($key) . ' (' . '$' . $key . ', $language = null) {' . "\n";

Expand Down
5 changes: 4 additions & 1 deletion models/DataObject/ClassDefinition/Data/Localizedfields.php
Expand Up @@ -144,7 +144,10 @@ public function getDataForEditmode($data, $object = null, $params = [])
$fieldDefinition = $this->getFielddefinition($key);
if ($fieldDefinition instanceof CalculatedValue) {
$childData = new DataObject\Data\CalculatedValue($fieldDefinition->getName());
$childData->setContextualData('localizedfield', $this->getName(), null, $language);
$ownerType = $params['context']['containerType'] ?? 'localizedfield';
$ownerName = $params['fieldname'] ?? $this->getName();
$index = $params['context']['containerKey'] ?? null;
$childData->setContextualData($ownerType, $ownerName, $index, $language, null, null, $fieldDefinition);
$value = $fieldDefinition->getDataForEditmode($childData, $object, $params);
} else {
$value = $fieldDefinition->getDataForEditmode($value, $object, $params);
Expand Down
31 changes: 13 additions & 18 deletions models/DataObject/ClassDefinition/Data/Objectbricks.php
Expand Up @@ -20,6 +20,7 @@
use Pimcore\Model;
use Pimcore\Model\DataObject;
use Pimcore\Model\DataObject\ClassDefinition\Data;
use Pimcore\Model\DataObject\Objectbrick;
use Pimcore\Model\Webservice;
use Pimcore\Tool;

Expand All @@ -37,7 +38,7 @@ class Objectbricks extends Data implements CustomResourcePersistingInterface
*
* @var string
*/
public $phpdocType = '\\Pimcore\\Model\\DataObject\\Objectbrick';
public $phpdocType = Objectbrick::class;

/**
* @var array
Expand Down Expand Up @@ -110,11 +111,11 @@ public function getDataForEditmode($data, $object = null, $params = [])
$getter = 'get' . ucfirst($allowedBrickType);
$params = [
'objectFromVersion' => $params['objectFromVersion'],
'context' => [
'context' => [
'containerType' => 'objectbrick',
'containerKey' => $allowedBrickType],
'fieldname' => $this->getName()

'containerKey' => $allowedBrickType,
],
'fieldname' => $this->getName(),
];

$editmodeData[] = $this->doGetDataForEditmode($getter, $data, $params, $allowedBrickType);
Expand Down Expand Up @@ -173,13 +174,11 @@ private function doGetDataForEditmode($getter, $data, $params, $allowedBrickType
$calculatedChilds = [];
self::collectCalculatedValueItems($collectionDef->getFieldDefinitions(), $calculatedChilds);

if ($calculatedChilds) {
foreach ($calculatedChilds as $fd) {
$fieldData = new DataObject\Data\CalculatedValue($fd->getName());
$fieldData->setContextualData('objectbrick', $this->getName(), $allowedBrickType, $fd->getName(), null, null, $fd);
$fieldData = $fd->getDataForEditmode($fieldData, $data->getObject(), $params);
$brickData[$fd->getName()] = $fieldData;
}
foreach ($calculatedChilds as $fd) {
$fieldData = new DataObject\Data\CalculatedValue($fd->getName());
$fieldData->setContextualData('objectbrick', $this->getName(), $allowedBrickType, $fd->getName(), null, null, $fd);
$fieldData = $fd->getDataForEditmode($fieldData, $data->getObject(), $params);
$brickData[$fd->getName()] = $fieldData;
}

$brickDefinition = DataObject\Objectbrick\Definition::getByKey($allowedBrickType);
Expand Down Expand Up @@ -244,7 +243,7 @@ private function getDataForField($item, $key, $fielddefinition, $level, $baseObj
}
$data = [];

if ($fielddefinition instanceof DataObject\ClassDefinition\Data\Href) {
if ($fielddefinition instanceof ManyToOneRelation) {
$data = $relations[0];
} else {
foreach ($relations as $rel) {
Expand Down Expand Up @@ -1046,7 +1045,7 @@ public function classSaved($class, $params = [])

/**
* @param $container
* @param array $list
* @param CalculatedValue[] $list
*/
public static function collectCalculatedValueItems($container, &$list = [])
{
Expand All @@ -1055,10 +1054,6 @@ public static function collectCalculatedValueItems($container, &$list = [])
foreach ($container as $childDef) {
if ($childDef instanceof Model\DataObject\ClassDefinition\Data\CalculatedValue) {
$list[] = $childDef;
} else {
if (method_exists($childDef, 'getFieldDefinitions')) {
self::collectCalculatedValueItems($childDef->getFieldDefinitions(), $list);
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion models/DataObject/Localizedfield.php
Expand Up @@ -379,7 +379,7 @@ public function getLocalizedValue($name, $language = null, $ignoreFallbackLangua

if ($fieldDefinition instanceof Model\DataObject\ClassDefinition\Data\CalculatedValue) {
$valueData = new Model\DataObject\Data\CalculatedValue($fieldDefinition->getName());
$valueData->setContextualData('localizedfield', 'localizedfields', null, $language);
$valueData->setContextualData('localizedfield', 'localizedfields', null, $language, null, null, $fieldDefinition);
$data = Service::getCalculatedFieldValue($this->getObject(), $valueData);

return $data;
Expand Down
39 changes: 19 additions & 20 deletions models/DataObject/Service.php
Expand Up @@ -1431,28 +1431,28 @@ public static function enrichLayoutPermissions(&$layout, $allowedView, $allowedE
}

/**
* @param $object
* @param Concrete $object
* @param array $params
* @param $data Model\DataObject\Data\CalculatedValue
*
* @return mixed|null
* @return string|null
*/
public static function getCalculatedFieldValueForEditMode($object, $params = [], $data)
{
if (!$data) {
return;
}

$fieldname = $data->getFieldname();
$ownerType = $data->getOwnerType();
$fd = null;
if ($ownerType === 'object') {
$fd = $object->getClass()->getFieldDefinition($fieldname);
} elseif ($ownerType === 'localizedfield') {
$fd = $object->getClass()->getFieldDefinition('localizedfields')->getFieldDefinition($fieldname);
} elseif ($ownerType === 'classificationstore') {
$fd = $data->getKeyDefinition();
} elseif ($ownerType === 'fieldcollection' || $ownerType === 'objectbrick') {
$fd = $data->getKeyDefinition();
$fd = $data->getKeyDefinition();

if($fd === null) {
if ($ownerType === 'object') {
$fd = $object->getClass()->getFieldDefinition($fieldname);
} elseif ($ownerType === 'localizedfield') {
$fd = $object->getClass()->getFieldDefinition('localizedfields')->getFieldDefinition($fieldname);
}
}

if (!$fd instanceof Model\DataObject\ClassDefinition\Data\CalculatedValue) {
Expand Down Expand Up @@ -1496,15 +1496,14 @@ public static function getCalculatedFieldValue($object, $data)
}
$fieldname = $data->getFieldname();
$ownerType = $data->getOwnerType();
$fd = null;
if ($ownerType === 'object') {
$fd = $object->getClass()->getFieldDefinition($fieldname);
} elseif ($ownerType === 'localizedfield') {
$fd = $object->getClass()->getFieldDefinition('localizedfields')->getFieldDefinition($fieldname);
} elseif ($ownerType === 'classificationstore') {
$fd = $data->getKeyDefinition();
} elseif ($ownerType === 'fieldcollection' || $ownerType === 'objectbrick') {
$fd = $data->getKeyDefinition();

$fd = $data->getKeyDefinition();
if($fd === null) {
if ($ownerType === 'object') {
$fd = $object->getClass()->getFieldDefinition($fieldname);
} elseif ($ownerType === 'localizedfield') {
$fd = $object->getClass()->getFieldDefinition('localizedfields')->getFieldDefinition($fieldname);
}
}

if (!$fd instanceof Model\DataObject\ClassDefinition\Data\CalculatedValue) {
Expand Down