<?php
/**
* Pimcore
*
* This source file is available under two different licenses:
* - GNU General Public License version 3 (GPLv3)
* - Pimcore Commercial License (PCL)
* Full copyright and license information is available in
* LICENSE.md which is distributed with this source code.
*
* @copyright Copyright (c) Pimcore GmbH (http://www.pimcore.org)
* @license http://www.pimcore.org/license GPLv3 and PCL
*/
namespace Pimcore\Model\DataObject\ClassDefinition\Data;
use InvalidArgumentException;
use Pimcore\Model;
use Pimcore\Model\DataObject;
use Pimcore\Model\DataObject\ClassDefinition\Data;
use Pimcore\Model\DataObject\ClassDefinition\Service;
use Pimcore\Model\DataObject\Concrete;
use Pimcore\Normalizer\NormalizerInterface;
class Select extends Data implements
ResourcePersistenceAwareInterface,
QueryResourcePersistenceAwareInterface,
TypeDeclarationSupportInterface,
EqualComparisonInterface,
VarExporterInterface,
\JsonSerializable,
NormalizerInterface,
LayoutDefinitionEnrichmentInterface,
FieldDefinitionEnrichmentInterface
{
use Model\DataObject\Traits\SimpleComparisonTrait;
use Extension\ColumnType;
use Extension\QueryColumnType;
use DataObject\Traits\SimpleNormalizerTrait;
use DataObject\Traits\DefaultValueTrait;
use DataObject\ClassDefinition\DynamicOptionsProvider\SelectionProviderTrait;
/**
* Static type of this element
*
* @internal
*
* @var string
*/
public $fieldtype = 'select';
/**
* Available options to select
*
* @internal
*
* @var array|null
*/
public $options;
/**
* @internal
*
* @var string|int
*/
public $width = 0;
/**
* @internal
*
* @var string|null
*/
public $defaultValue;
/**
* Options provider class
*
* @internal
*
* @var string
*/
public $optionsProviderClass;
/**
* Options provider data
*
* @internal
*
* @var string
*/
public $optionsProviderData;
/**
* Type for the column to query
*
* @internal
*
* @var string
*/
public $queryColumnType = 'varchar';
/**
* Type for the column
*
* @internal
*
* @var string
*/
public $columnType = 'varchar';
/**
* Column length
*
* @internal
*
* @var int
*/
public $columnLength = 190;
/**
* @internal
*
* @var bool
*/
public $dynamicOptions = false;
/**
* @return int
*/
public function getColumnLength()
{
return $this->columnLength;
}
/**
* @param int|null $columnLength
*
* @return $this
*/
public function setColumnLength($columnLength)
{
if ($columnLength) {
$this->columnLength = $columnLength;
}
return $this;
}
/**
* Correct old column definitions (e.g varchar(255)) to the new format
*
* @param string $type
*/
private function correctColumnDefinition($type)
{
if (preg_match("/(.*)\((\d+)\)/i", $this->$type, $matches)) {
$this->{'set' . ucfirst($type)}($matches[1]);
if ($matches[2] > 190) {
$matches[2] = 190;
}
$this->setColumnLength($matches[2] <= 190 ? $matches[2] : 190);
}
}
/**
* {@inheritdoc}
*/
public function getColumnType()
{
$this->correctColumnDefinition('columnType');
return $this->columnType . '(' . $this->getColumnLength() . ')';
}
/**
* {@inheritdoc}
*/
public function getQueryColumnType()
{
$this->correctColumnDefinition('queryColumnType');
return $this->queryColumnType . '(' . $this->getColumnLength() . ')';
}
/**
* @return array
*/
public function getOptions()
{
return $this->options;
}
/**
* @param array|null $options
*
* @return $this
*/
public function setOptions(?array $options)
{
if (is_array($options)) {
$this->options = [];
foreach ($options as $option) {
$option = (array)$option;
if (!array_key_exists('key', $option) || !array_key_exists('value', $option)) {
throw new InvalidArgumentException('Please provide select options as associative array with fields "key" and "value"');
}
$this->options[] = $option;
}
} else {
$this->options = null;
}
return $this;
}
/**
* @return string|int
*/
public function getWidth()
{
return $this->width;
}
/**
* @param string|int $width
*
* @return $this
*/
public function setWidth($width)
{
if (is_numeric($width)) {
$width = (int)$width;
}
$this->width = $width;
return $this;
}
/**
* @see ResourcePersistenceAwareInterface::getDataForResource
*
* @param string $data
* @param null|DataObject\Concrete $object
* @param mixed $params
*
* @return string
*/
public function getDataForResource($data, $object = null, $params = [])
{
$data = $this->handleDefaultValue($data, $object, $params);
return $data;
}
/**
* @see ResourcePersistenceAwareInterface::getDataFromResource
*
* @param string $data
* @param null|DataObject\Concrete $object
* @param mixed $params
*
* @return string
*/
public function getDataFromResource($data, $object = null, $params = [])
{
return $data;
}
/**
* @see QueryResourcePersistenceAwareInterface::getDataForQueryResource
*
* @param string $data
* @param null|DataObject\Concrete $object
* @param mixed $params
*
* @return string
*/
public function getDataForQueryResource($data, $object = null, $params = [])
{
return $this->getDataForResource($data, $object, $params);
}
/**
* @see Data::getDataForEditmode
*
* @param string $data
* @param null|DataObject\Concrete $object
* @param mixed $params
*
* @return string
*/
public function getDataForEditmode($data, $object = null, $params = [])
{
return $this->getDataForResource($data, $object, $params);
}
/**
* @see Data::getDataFromEditmode
*
* @param string $data
* @param null|DataObject\Concrete $object
* @param mixed $params
*
* @return string
*/
public function getDataFromEditmode($data, $object = null, $params = [])
{
return $this->getDataFromResource($data, $object, $params);
}
/**
* @see Data::getVersionPreview
*
* @param string $data
* @param null|DataObject\Concrete $object
* @param mixed $params
*
* @return string
*/
public function getVersionPreview($data, $object = null, $params = [])
{
return htmlspecialchars($data, ENT_QUOTES, 'UTF-8');
}
/**
* {@inheritdoc}
*/
public function isDiffChangeAllowed($object, $params = [])
{
return true;
}
/** See parent class.
* @param mixed $data
* @param DataObject\Concrete|null $object
* @param mixed $params
*
* @return array|null
*/
public function getDiffDataForEditMode($data, $object = null, $params = [])
{
$result = [];
$diffdata = [];
$diffdata['data'] = $data;
$diffdata['disabled'] = false;
$diffdata['field'] = $this->getName();
$diffdata['key'] = $this->getName();
$diffdata['type'] = $this->fieldtype;
$value = '';
foreach ($this->options as $option) {
if ($option['value'] == $data) {
$value = $option['key'];
break;
}
}
$diffdata['value'] = $value;
$diffdata['title'] = !empty($this->title) ? $this->title : $this->name;
$result[] = $diffdata;
return $result;
}
/**
* {@inheritdoc}
*/
public function checkValidity($data, $omitMandatoryCheck = false, $params = [])
{
if (!$omitMandatoryCheck && $this->getMandatory() && $this->isEmpty($data)) {
throw new Model\Element\ValidationException('Empty mandatory field [ ' . $this->getName() . ' ]');
}
}
/**
* @param string|null $data
*
* @return bool
*/
public function isEmpty($data)
{
return strlen($data) < 1;
}
/**
* @param DataObject\ClassDefinition\Data\Select $masterDefinition
*/
public function synchronizeWithMasterDefinition(DataObject\ClassDefinition\Data $masterDefinition)
{
$this->options = $masterDefinition->options;
$this->columnLength = $masterDefinition->columnLength;
$this->defaultValue = $masterDefinition->defaultValue;
$this->optionsProviderClass = $masterDefinition->optionsProviderClass;
$this->optionsProviderData = $masterDefinition->optionsProviderData;
}
/**
* @return string|null
*/
public function getDefaultValue()
{
return $this->defaultValue;
}
/**
* @param string|null $defaultValue
*/
public function setDefaultValue($defaultValue)
{
$this->defaultValue = $defaultValue;
}
/**
* @return string
*/
public function getOptionsProviderClass()
{
return $this->optionsProviderClass;
}
/**
* @param string $optionsProviderClass
*/
public function setOptionsProviderClass($optionsProviderClass)
{
$this->optionsProviderClass = $optionsProviderClass;
}
/**
* @return string
*/
public function getOptionsProviderData()
{
return $this->optionsProviderData;
}
/**
* @param string $optionsProviderData
*/
public function setOptionsProviderData($optionsProviderData)
{
$this->optionsProviderData = $optionsProviderData;
}
/**
* { @inheritdoc }
*/
public function enrichFieldDefinition(/** array */ $context = []) /** : Data */
{
$this->doEnrichDefinitionDefinition(null, $this->getName(),
'fielddefinition', DataObject\ClassDefinition\Helper\OptionsProviderResolver::MODE_SELECT, $context);
return $this;
}
/**
* {@inheritdoc}
*/
public function enrichLayoutDefinition(/*?Concrete */ $object, /** array */ $context = []) // : self
{
$this->doEnrichDefinitionDefinition($object, $this->getName(),
'layout', DataObject\ClassDefinition\Helper\OptionsProviderResolver::MODE_SELECT, $context);
return $this;
}
/**
* @param string|null $data
* @param DataObject\Concrete|null $object
* @param array $params
*
* @return array|string
*/
public function getDataForGrid($data, $object = null, $params = [])
{
$optionsProvider = DataObject\ClassDefinition\Helper\OptionsProviderResolver::resolveProvider(
$this->getOptionsProviderClass(),
DataObject\ClassDefinition\Helper\OptionsProviderResolver::MODE_SELECT
);
if ($optionsProvider) {
$context = $params['context'] ?? [];
$context['object'] = $object;
if ($object) {
$context['class'] = $object->getClass();
}
$context['fieldname'] = $this->getName();
$options = $optionsProvider->{'getOptions'}($context, $this);
$this->setOptions($options);
if (isset($params['purpose']) && $params['purpose'] == 'editmode') {
$result = $data;
} else {
$result = ['value' => $data ?? null, 'options' => $this->getOptions()];
}
return $result;
}
return $data;
}
/**
* returns sql query statement to filter according to this data types value(s)
*
* @param string|array $value
* @param string $operator
* @param array $params optional params used to change the behavior
*
* @return string|null
*/
public function getFilterConditionExt($value, $operator, $params = [])
{
$value = is_array($value) ? current($value) : $value;
$name = $params['name'] ?: $this->name;
$db = \Pimcore\Db::get();
$key = $db->quoteIdentifier($name);
if (!empty($params['brickPrefix'])) {
$key = $params['brickPrefix'].$key;
}
if ($operator === '=') {
return $key.' = '."\"$value\"".' ';
}
if ($operator === 'LIKE') {
return $key.' LIKE '."\"%$value%\"".' ';
}
return null;
}
/**
* {@inheritdoc}
*/
public function isFilterable(): bool
{
return true;
}
/**
* {@inheritdoc}
*/
protected function doGetDefaultValue($object, $context = [])
{
/** @var DataObject\ClassDefinition\DynamicOptionsProvider\SelectOptionsProviderInterface|null $optionsProvider */
$optionsProvider = DataObject\ClassDefinition\Helper\OptionsProviderResolver::resolveProvider(
$this->getOptionsProviderClass(),
DataObject\ClassDefinition\Helper\OptionsProviderResolver::MODE_SELECT
);
if ($optionsProvider) {
$context['object'] = $object;
if ($object) {
$context['class'] = $object->getClass();
}
$context['fieldname'] = $this->getName();
if (!isset($context['purpose'])) {
$context['purpose'] = 'layout';
}
return $optionsProvider->getDefaultValue($context, $this);
}
return $this->getDefaultValue();
}
/**
* @return $this
*/
#[\ReturnTypeWillChange]
public function jsonSerialize()// : static
{
if ($this->getOptionsProviderClass() && Service::doRemoveDynamicOptions()) {
$this->options = null;
}
return $this;
}
/**
* {@inheritdoc}
*/
public function resolveBlockedVars(): array
{
$blockedVars = parent::resolveBlockedVars();
if ($this->getOptionsProviderClass()) {
$blockedVars[] = 'options';
}
return $blockedVars;
}
/**
* {@inheritdoc}
*/
public function getParameterTypeDeclaration(): ?string
{
return '?string';
}
/**
* {@inheritdoc}
*/
public function getReturnTypeDeclaration(): ?string
{
return '?string';
}
/**
* {@inheritdoc}
*/
public function getPhpdocInputType(): ?string
{
return 'string|null';
}
/**
* {@inheritdoc}
*/
public function getPhpdocReturnType(): ?string
{
return 'string|null';
}
}