19
[
 'type' => 'int',
 'backend' => '',
 'frontend' => '',
 'label' => 'XXXX',
 'input' => 'text',
 'frontend_class' => 'validate-greater-than-zero',
 'source' => '',
 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_GLOBAL,
 'visible' => true,
 'required' => true,
 'user_defined' => false,
 'default' => 0,
 'searchable' => false,
 'filterable' => true,
 'comparable' => false,
 'visible_on_front' => false,
 'used_in_product_listing' => true,
 'unique' => false
]

I am adding custom product attribute which works fine, but not able to add validate-greater-than-zero validation.

If we look at any attribute properties in Input Validation for Store Owner there are limited number of validations in select options.

validate-number,validate-digits,validate-email,validate-url,validate-alpha,validate-alphanum

These are the only validations applied in Product attribute section.

asked Jan 5, 2017 at 9:02
1
  • Please see my answer, it will be helping you to validate your attribute value. Commented Jan 17, 2017 at 10:14

3 Answers 3

20
+50

One of the solution is to add a backend model to your attribute which is used to format / validate your attribute value before save and/or after load.

Add a backend class :

[
 'type' => 'int',
 'backend' => '\Foo\Bar\Model\Attribute\Backend\YourAttribute',
 'frontend' => '',
 'label' => 'XXXX',
 'input' => 'text',
 'frontend_class' => 'validate-greater-than-zero',
 'source' => '',
 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_GLOBAL,
 'visible' => true,
 'required' => true,
 'user_defined' => false,
 'default' => 0,
 'searchable' => false,
 'filterable' => true,
 'comparable' => false,
 'visible_on_front' => false,
 'used_in_product_listing' => true,
 'unique' => false
]

Here is an example of your custom class \Foo\Bar\Model\Attribute\Backend\YourAttribute

<?php
namespace Foo\Bar\Model\Attribute\Backend;
/**
 * Class YourAttribute
 */
class YourAttribute extends \Magento\Eav\Model\Entity\Attribute\Backend\AbstractBackend
{
 /**
 * @var int $minimumValueLength
 */
 protected $minimumValueLength = 0;
 /**
 * @param \Magento\Framework\DataObject $object
 *
 * @return $this
 */
 public function afterLoad($object)
 {
 // your after load logic
 return parent::afterLoad($object);
 }
 /**
 * @param \Magento\Framework\DataObject $object
 *
 * @return $this
 */
 public function beforeSave($object)
 {
 $this->validateLength($object);
 return parent::beforeSave($object);
 }
 /**
 * Validate length
 *
 * @param \Magento\Framework\DataObject $object
 *
 * @return bool
 * @throws \Magento\Framework\Exception\LocalizedException
 */
 public function validateLength($object)
 {
 /** @var string $attributeCode */
 $attributeCode = $this->getAttribute()->getAttributeCode();
 /** @var int $value */
 $value = (int)$object->getData($attributeCode);
 /** @var int $minimumValueLength */
 $minimumValueLength = $this->getMinimumValueLength();
 if ($this->getAttribute()->getIsRequired() && $value <= $minimumValueLength) {
 throw new \Magento\Framework\Exception\LocalizedException(
 __('The value of attribute "%1" must be greater than %2', $attributeCode, $minimumValueLength)
 );
 }
 return true;
 }
 /**
 * Get minimum attribute value length
 * 
 * @return int
 */
 public function getMinimumValueLength()
 {
 return $this->minimumValueLength;
 }
}

If you want a simple example of that kind of class you can check

  • \Magento\Customer\Model\Customer\Attribute\Backend\Website
  • all the classes which extend \Magento\Eav\Model\Entity\Attribute\Backend\AbstractBackend
  • the classes into backend_model column in eav_attribute table


EDIT
If you want a class that do nearly the same thing as you want you can take a look at the SKU attribute validation \Magento\Catalog\Model\Product\Attribute\Backend\Sku
I also added the method in the example class


EDIT
Another solution (maybe not the best one) is to create a plugin on the function \Magento\Eav\Helper\Data::getFrontendClasses and add your frontend class here that can be validated in front.

answered Jan 16, 2017 at 15:33
5
  • Thanks for your reply but would it be possible to apply frontend validation. Commented Jan 17, 2017 at 12:04
  • If you take a look at your attribute line in eav_attribute table in the column frontend_class is thee the value validate-greater-than-zero ? Commented Jan 17, 2017 at 12:28
  • Yes but it doesn't work. These are the only classes which works validate-number,validate-digits,validate-email,validate-url,validate-alpha,validate-alphanum. Commented Jan 17, 2017 at 13:18
  • 1
    Can you try my second edit, to add your custom frontend classes ? Commented Jan 17, 2017 at 17:06
  • OK great ! Can you apply the bounty as well please ? Thank you. Commented Jan 19, 2017 at 9:07
13

With the help of Matthéo Geoffray, this is what I did to apply frontend validation for custom attributes.

[
 'type' => 'int',
 'backend' => '',
 'frontend' => '',
 'label' => 'XXXX',
 'input' => 'text',
 'frontend_class' => 'validate-greater-than-zero',
 'source' => '',
 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_GLOBAL,
 'visible' => true,
 'required' => true,
 'user_defined' => false,
 'default' => 0,
 'searchable' => false,
 'filterable' => true,
 'comparable' => false,
 'visible_on_front' => false,
 'used_in_product_listing' => true,
 'unique' => false
]

This is the custom attribute in install script.

I added plugin in di.xml

<type name="Magento\Catalog\Ui\DataProvider\CatalogEavValidationRules">
 <plugin name="namespace_custom_validation_for_product_attribute" type="Namespace\Module\Model\Plugin\Product\ValidationRules"/>
</type>

Here is the plugin code.

<?php
namespace Namespace\Module\Model\Plugin\Product;
use Closure;
class ValidationRules
{
 /**
 * @param \Magento\Catalog\Ui\DataProvider\CatalogEavValidationRules $rulesObject
 * @param callable $proceed
 * @param \Magento\Catalog\Api\Data\ProductAttributeInterface $attribute,
 * @param array $data
 * @return array
 * @SuppressWarnings(PHPMD.UnusedFormalParameter)
 */
 public function aroundBuild(
 \Magento\Catalog\Ui\DataProvider\CatalogEavValidationRules $rulesObject,
 Closure $proceed,
 \Magento\Catalog\Api\Data\ProductAttributeInterface $attribute,
 array $data
 ){
 $rules = $proceed($attribute,$data);
 if($attribute->getAttributeCode() == 'xyz'){ //custom filter
 $validationClasses = explode(' ', $attribute->getFrontendClass());
 foreach ($validationClasses as $class) {
 $rules[$class] = true;
 }
 }
 return $rules;
 }
}

Basically in \Magento\Catalog\Ui\DataProvider\CatalogEavValidationRules, the method called mapRules only matches the frontend class against limited number of validation rules. To apply more validation rules we need to append rules using plugin.

For server side validation, Please refer to Matthéo Geoffray answer.

Matthéo Geoffray
2,7042 gold badges21 silver badges45 bronze badges
answered Jan 18, 2017 at 7:44
0
3

I'm not sure it could be possible from install script. But I'm sure it's possible if you will create "before listener plugin" with function beforeSave() and check value there.

answered Jan 16, 2017 at 13:46

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.