vendor/pimcore/pimcore/models/DataObject/ClassDefinition/Data/Numeric.php line 564

Open in your IDE?
  1. <?php
  2. /**
  3.  * Pimcore
  4.  *
  5.  * This source file is available under two different licenses:
  6.  * - GNU General Public License version 3 (GPLv3)
  7.  * - Pimcore Commercial License (PCL)
  8.  * Full copyright and license information is available in
  9.  * LICENSE.md which is distributed with this source code.
  10.  *
  11.  *  @copyright  Copyright (c) Pimcore GmbH (http://www.pimcore.org)
  12.  *  @license    http://www.pimcore.org/license     GPLv3 and PCL
  13.  */
  14. namespace Pimcore\Model\DataObject\ClassDefinition\Data;
  15. use Pimcore\Model;
  16. use Pimcore\Model\DataObject\ClassDefinition\Data;
  17. use Pimcore\Normalizer\NormalizerInterface;
  18. class Numeric extends Data implements ResourcePersistenceAwareInterfaceQueryResourcePersistenceAwareInterfaceTypeDeclarationSupportInterfaceEqualComparisonInterfaceVarExporterInterfaceNormalizerInterfacePreSetDataInterface
  19. {
  20.     use Model\DataObject\Traits\DefaultValueTrait;
  21.     use Model\DataObject\Traits\SimpleNormalizerTrait;
  22.     use Model\DataObject\Traits\SimpleComparisonTrait;
  23.     use Extension\ColumnType {
  24.         getColumnType as public genericGetColumnType;
  25.     }
  26.     use Extension\QueryColumnType {
  27.         getQueryColumnType as public genericGetQueryColumnType;
  28.     }
  29.     const DECIMAL_SIZE_DEFAULT 64;
  30.     const DECIMAL_PRECISION_DEFAULT 0;
  31.     /**
  32.      * Static type of this element
  33.      *
  34.      * @internal
  35.      *
  36.      * @var string
  37.      */
  38.     public $fieldtype 'numeric';
  39.     /**
  40.      * @internal
  41.      *
  42.      * @var string|int
  43.      */
  44.     public $width 0;
  45.     /**
  46.      * @internal
  47.      *
  48.      * @var float
  49.      */
  50.     public $defaultValue;
  51.     /**
  52.      * Type for the column to query
  53.      *
  54.      * @internal
  55.      *
  56.      * @var string
  57.      */
  58.     public $queryColumnType 'double';
  59.     /**
  60.      * Type for the column
  61.      *
  62.      * @internal
  63.      *
  64.      * @var string
  65.      */
  66.     public $columnType 'double';
  67.     /**
  68.      * @internal
  69.      *
  70.      * @var bool
  71.      */
  72.     public $integer false;
  73.     /**
  74.      * @internal
  75.      *
  76.      * @var bool
  77.      */
  78.     public $unsigned false;
  79.     /**
  80.      * @internal
  81.      *
  82.      * @var float|null
  83.      */
  84.     public $minValue;
  85.     /**
  86.      * @internal
  87.      *
  88.      * @var float|null
  89.      */
  90.     public $maxValue;
  91.     /**
  92.      * @internal
  93.      *
  94.      * @var bool
  95.      */
  96.     public $unique;
  97.     /**
  98.      * This is the x part in DECIMAL(x, y) and denotes the total amount of digits. In MySQL this is called precision
  99.      * but as decimalPrecision already existed to denote the amount of digits after the point (as it is called on the ExtJS
  100.      * number field), decimalSize was chosen instead.
  101.      *
  102.      * @internal
  103.      *
  104.      * @var int|null
  105.      */
  106.     public $decimalSize;
  107.     /**
  108.      * This is the y part in DECIMAL(x, y) and denotes amount of digits after a comma. In MySQL this is called scale. See
  109.      * commend on decimalSize.
  110.      *
  111.      * @internal
  112.      *
  113.      * @var int|null
  114.      */
  115.     public $decimalPrecision;
  116.     /**
  117.      * @return string
  118.      */
  119.     private function getPhpdocType(): string
  120.     {
  121.         if ($this->getInteger()) {
  122.             return 'int';
  123.         }
  124.         if ($this->isDecimalType()) {
  125.             return 'string';
  126.         }
  127.         return 'float';
  128.     }
  129.     /**
  130.      * @return string|int
  131.      */
  132.     public function getWidth()
  133.     {
  134.         return $this->width;
  135.     }
  136.     /**
  137.      * @param string|int $width
  138.      *
  139.      * @return $this
  140.      */
  141.     public function setWidth($width)
  142.     {
  143.         if (is_numeric($width)) {
  144.             $width = (int)$width;
  145.         }
  146.         $this->width $width;
  147.         return $this;
  148.     }
  149.     /**
  150.      * @return int|null
  151.      */
  152.     public function getDefaultValue()
  153.     {
  154.         if ($this->defaultValue !== null) {
  155.             return $this->toNumeric($this->defaultValue);
  156.         }
  157.         return null;
  158.     }
  159.     /**
  160.      * @param int $defaultValue
  161.      *
  162.      * @return $this
  163.      */
  164.     public function setDefaultValue($defaultValue)
  165.     {
  166.         if ((string)$defaultValue !== '') {
  167.             $this->defaultValue $defaultValue;
  168.         }
  169.         return $this;
  170.     }
  171.     /**
  172.      * @param bool $integer
  173.      */
  174.     public function setInteger($integer)
  175.     {
  176.         $this->integer $integer;
  177.     }
  178.     /**
  179.      * @return bool
  180.      */
  181.     public function getInteger()
  182.     {
  183.         return $this->integer;
  184.     }
  185.     /**
  186.      * @param float|null $maxValue
  187.      */
  188.     public function setMaxValue($maxValue)
  189.     {
  190.         $this->maxValue $maxValue;
  191.     }
  192.     /**
  193.      * @return float|null
  194.      */
  195.     public function getMaxValue()
  196.     {
  197.         return $this->maxValue;
  198.     }
  199.     /**
  200.      * @param float|null $minValue
  201.      */
  202.     public function setMinValue($minValue)
  203.     {
  204.         $this->minValue $minValue;
  205.     }
  206.     /**
  207.      * @return float|null
  208.      */
  209.     public function getMinValue()
  210.     {
  211.         return $this->minValue;
  212.     }
  213.     /**
  214.      * @param bool $unsigned
  215.      */
  216.     public function setUnsigned($unsigned)
  217.     {
  218.         $this->unsigned $unsigned;
  219.     }
  220.     /**
  221.      * @return bool
  222.      */
  223.     public function getUnsigned()
  224.     {
  225.         return $this->unsigned;
  226.     }
  227.     /**
  228.      * @return int|null
  229.      */
  230.     public function getDecimalSize()
  231.     {
  232.         return $this->decimalSize;
  233.     }
  234.     /**
  235.      * @param int|null $decimalSize
  236.      */
  237.     public function setDecimalSize($decimalSize)
  238.     {
  239.         if (!is_numeric($decimalSize)) {
  240.             $decimalSize null;
  241.         }
  242.         $this->decimalSize $decimalSize;
  243.     }
  244.     /**
  245.      * @param int|null $decimalPrecision
  246.      */
  247.     public function setDecimalPrecision($decimalPrecision)
  248.     {
  249.         if (!is_numeric($decimalPrecision)) {
  250.             $decimalPrecision null;
  251.         }
  252.         $this->decimalPrecision $decimalPrecision;
  253.     }
  254.     /**
  255.      * @return int|null
  256.      */
  257.     public function getDecimalPrecision()
  258.     {
  259.         return $this->decimalPrecision;
  260.     }
  261.     /**
  262.      * @return bool
  263.      */
  264.     public function getUnique()
  265.     {
  266.         return $this->unique;
  267.     }
  268.     /**
  269.      * @param bool $unique
  270.      */
  271.     public function setUnique($unique)
  272.     {
  273.         $this->unique $unique;
  274.     }
  275.     /**
  276.      * {@inheritdoc}
  277.      */
  278.     public function getColumnType()
  279.     {
  280.         if ($this->getInteger()) {
  281.             return 'bigint(20)';
  282.         }
  283.         if ($this->isDecimalType()) {
  284.             return $this->buildDecimalColumnType();
  285.         }
  286.         return $this->genericGetColumnType();
  287.     }
  288.     /**
  289.      * {@inheritdoc}
  290.      */
  291.     public function getQueryColumnType()
  292.     {
  293.         if ($this->getInteger()) {
  294.             return 'bigint(20)';
  295.         }
  296.         if ($this->isDecimalType()) {
  297.             return $this->buildDecimalColumnType();
  298.         }
  299.         return $this->genericGetQueryColumnType();
  300.     }
  301.     /**
  302.      * @return bool
  303.      */
  304.     private function isDecimalType(): bool
  305.     {
  306.         return null !== $this->getDecimalSize() || null !== $this->getDecimalPrecision();
  307.     }
  308.     /**
  309.      * @return string
  310.      */
  311.     private function buildDecimalColumnType(): string
  312.     {
  313.         // decimalPrecision already existed in earlier versions to denote the amount of digits after the
  314.         // comma (and is used in ExtJS). To avoid migrations, decimalSize was chosen to denote the total amount
  315.         // of supported digits despite the confusing naming.
  316.         //
  317.         // The two properties used in the class definition translate to the following MySQL naming:
  318.         //
  319.         // DECIMAL(precision, scale) = DECIMAL(decimalSize, decimalPrecision)
  320.         // these are named after what MySQL expects - DECIMAL(precision, scale)
  321.         $precision self::DECIMAL_SIZE_DEFAULT;
  322.         $scale self::DECIMAL_PRECISION_DEFAULT;
  323.         if (null !== $this->decimalSize) {
  324.             $precision = (int)$this->decimalSize;
  325.         }
  326.         if (null !== $this->decimalPrecision) {
  327.             $scale = (int)$this->decimalPrecision;
  328.         }
  329.         if ($precision || $precision 65) {
  330.             throw new \InvalidArgumentException('Decimal precision must be a value between 1 and 65');
  331.         }
  332.         if ($scale || $scale 30 || $scale $precision) {
  333.             throw new \InvalidArgumentException('Decimal scale must be a value between 0 and 30');
  334.         }
  335.         if ($scale $precision) {
  336.             throw new \InvalidArgumentException(sprintf(
  337.                 'Decimal scale can\'t be larger than precision (%d)',
  338.                 $precision
  339.             ));
  340.         }
  341.         return sprintf('DECIMAL(%d, %d)'$precision$scale);
  342.     }
  343.     /**
  344.      * @see ResourcePersistenceAwareInterface::getDataForResource
  345.      *
  346.      * @param float|int|string $data
  347.      * @param null|Model\DataObject\Concrete $object
  348.      * @param mixed $params
  349.      *
  350.      * @return float|int|string|null
  351.      */
  352.     public function getDataForResource($data$object null$params = [])
  353.     {
  354.         $data $this->handleDefaultValue($data$object$params);
  355.         if (is_numeric($data)) {
  356.             return $data;
  357.         }
  358.         return null;
  359.     }
  360.     /**
  361.      * @see ResourcePersistenceAwareInterface::getDataFromResource
  362.      *
  363.      * @param float|int|string $data
  364.      * @param null|Model\DataObject\Concrete $object
  365.      * @param mixed $params
  366.      *
  367.      * @return float|int|string
  368.      */
  369.     public function getDataFromResource($data$object null$params = [])
  370.     {
  371.         if (is_numeric($data)) {
  372.             return $this->toNumeric($data);
  373.         }
  374.         return $data;
  375.     }
  376.     /**
  377.      * @see QueryResourcePersistenceAwareInterface::getDataForQueryResource
  378.      *
  379.      * @param float|int|string $data
  380.      * @param null|Model\DataObject\Concrete $object
  381.      * @param mixed $params
  382.      *
  383.      * @return float|int|string
  384.      */
  385.     public function getDataForQueryResource($data$object null$params = [])
  386.     {
  387.         //TODO same fallback as above
  388.         return $this->getDataForResource($data$object$params);
  389.     }
  390.     /**
  391.      * @see Data::getDataForEditmode
  392.      *
  393.      * @param float|int|string $data
  394.      * @param null|Model\DataObject\Concrete $object
  395.      * @param mixed $params
  396.      *
  397.      * @return float|int|string
  398.      */
  399.     public function getDataForEditmode($data$object null$params = [])
  400.     {
  401.         return $this->getDataForResource($data$object$params);
  402.     }
  403.     /**
  404.      * @see Data::getDataFromEditmode
  405.      *
  406.      * @param float|int|string $data
  407.      * @param null|Model\DataObject\Concrete $object
  408.      * @param mixed $params
  409.      *
  410.      * @return float|int|string
  411.      */
  412.     public function getDataFromEditmode($data$object null$params = [])
  413.     {
  414.         return $this->getDataFromResource($data$object$params);
  415.     }
  416.     /**
  417.      * @see Data::getVersionPreview
  418.      *
  419.      * @param float|int|string $data
  420.      * @param null|Model\DataObject\Concrete $object
  421.      * @param mixed $params
  422.      *
  423.      * @return float|int|string
  424.      */
  425.     public function getVersionPreview($data$object null$params = [])
  426.     {
  427.         return $data;
  428.     }
  429.     /**
  430.      * {@inheritdoc}
  431.      */
  432.     public function checkValidity($data$omitMandatoryCheck false$params = [])
  433.     {
  434.         if (!$omitMandatoryCheck && $this->getMandatory() && $this->isEmpty($data)) {
  435.             throw new Model\Element\ValidationException('Empty mandatory field [ '.$this->getName().' ]');
  436.         }
  437.         if (!$this->isEmpty($data) && !is_numeric($data)) {
  438.             throw new Model\Element\ValidationException('field ['.$this->getName().' ] - invalid numeric data [' $data '] ');
  439.         }
  440.         if (!$this->isEmpty($data) && !$omitMandatoryCheck) {
  441.             $data $this->toNumeric($data);
  442.             if ($data >= PHP_INT_MAX) {
  443.                 throw new Model\Element\ValidationException('Value exceeds PHP_INT_MAX please use an input data type instead of numeric!');
  444.             }
  445.             if ($this->getInteger() && strpos((string) $data'.') !== false) {
  446.                 throw new Model\Element\ValidationException('Value in field [ '.$this->getName().' ] is not an integer');
  447.             }
  448.             if ($this->getMinValue() !== null && $this->getMinValue() > $data) {
  449.                 throw new Model\Element\ValidationException('Value in field [ '.$this->getName().' ] is not at least ' $this->getMinValue());
  450.             }
  451.             if ($this->getMaxValue() !== null && $data $this->getMaxValue()) {
  452.                 throw new Model\Element\ValidationException('Value in field [ '.$this->getName().' ] is bigger than ' $this->getMaxValue());
  453.             }
  454.             if ($this->getUnsigned() && $data 0) {
  455.                 throw new Model\Element\ValidationException('Value in field [ '.$this->getName().' ] is not unsigned (bigger than 0)');
  456.             }
  457.         }
  458.     }
  459.     /**
  460.      * {@inheritdoc}
  461.      */
  462.     public function getForCsvExport($object$params = [])
  463.     {
  464.         $data $this->getDataFromObjectParam($object$params);
  465.         return (string)$data;
  466.     }
  467.     /**
  468.      * {@inheritdoc}
  469.      */
  470.     public function isDiffChangeAllowed($object$params = [])
  471.     {
  472.         return true;
  473.     }
  474.     /**
  475.      * @param string|null $data
  476.      *
  477.      * @return bool
  478.      */
  479.     public function isEmpty($data)
  480.     {
  481.         return strlen($data) < 1;
  482.     }
  483.     /**
  484.      * @param string $value
  485.      *
  486.      * @return float|int|string
  487.      */
  488.     private function toNumeric($value)
  489.     {
  490.         $value str_replace(',''.', (string) $value);
  491.         if ($this->isDecimalType()) {
  492.             return $value;
  493.         }
  494.         if (strpos($value'.') === false) {
  495.             return (int) $value;
  496.         }
  497.         return (float) $value;
  498.     }
  499.     /**
  500.      * { @inheritdoc }
  501.      */
  502.     public function preSetData(/** mixed */ $container/**  mixed */ $data/** array */ $params = []) // : mixed
  503.     {
  504.         if (!is_null($data) && $this->getDecimalPrecision()) {
  505.             $data round($data$this->getDecimalPrecision());
  506.         }
  507.         return $data;
  508.     }
  509.     /**
  510.      * {@inheritdoc}
  511.      */
  512.     public function isFilterable(): bool
  513.     {
  514.         return true;
  515.     }
  516.     /**
  517.      * {@inheritdoc}
  518.      */
  519.     protected function doGetDefaultValue($object$context = [])
  520.     {
  521.         return $this->getDefaultValue() ?? null;
  522.     }
  523.     /**
  524.      * @param float|int|string $oldValue
  525.      * @param float|int|string $newValue
  526.      *
  527.      * @return bool
  528.      */
  529.     public function isEqual($oldValue$newValue): bool
  530.     {
  531.         return $this->toNumeric($oldValue) == $this->toNumeric($newValue);
  532.     }
  533.     /**
  534.      * {@inheritdoc}
  535.      */
  536.     public function getParameterTypeDeclaration(): ?string
  537.     {
  538.         return '?' $this->getPhpdocType();
  539.     }
  540.     /**
  541.      * {@inheritdoc}
  542.      */
  543.     public function getReturnTypeDeclaration(): ?string
  544.     {
  545.         return '?' $this->getPhpdocType();
  546.     }
  547.     /**
  548.      * {@inheritdoc}
  549.      */
  550.     public function getPhpdocInputType(): ?string
  551.     {
  552.         return $this->getPhpdocType() . '|null';
  553.     }
  554.     /**
  555.      * {@inheritdoc}
  556.      */
  557.     public function getPhpdocReturnType(): ?string
  558.     {
  559.         return $this->getPhpdocType() . '|null';
  560.     }
  561. }