field validation framework

This commit is contained in:
yuri
2019-02-06 14:24:20 +02:00
parent 7e54239710
commit 7154fa0f4a
16 changed files with 447 additions and 14 deletions
@@ -0,0 +1,59 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2018 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
* Website: http://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Core\FieldValidators;
use \Espo\ORM\Entity;
class BaseType
{
private $metadata;
private $fieldManagerUtil;
public function __construct(\Espo\Core\Utils\Metadata $metadata, \Espo\Core\Utils\FieldManagerUtil $fieldManagerUtil)
{
$this->metadata = $metadata;
$this->fieldManagerUtil = $fieldManagerUtil;
}
protected function getActualAttributeList(Entity $entity, string $field) : array
{
return $this->getFieldManagerUtil()->getActualAttributeList($entity->getEntityType(), $field);
}
protected function getMetadata() : \Espo\Core\Utils\Metadata
{
return $this->metadata;
}
protected function getFieldManagerUtil() : \Espo\Core\Utils\FieldManagerUtil
{
return $this->fieldManagerUtil;
}
}
@@ -0,0 +1,37 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2018 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
* Website: http://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Core\FieldValidators;
use \Espo\ORM\Entity;
class CurrencyType extends FloatType
{
}
@@ -0,0 +1,37 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2018 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
* Website: http://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Core\FieldValidators;
use \Espo\ORM\Entity;
class FloatType extends IntType
{
}
@@ -0,0 +1,40 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2018 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
* Website: http://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Core\FieldValidators;
use \Espo\ORM\Entity;
class IntType extends BaseType
{
public function checkRequired(\Espo\ORM\Entity $entity, string $field, $validationValue, $data) : bool
{
return $entity->has($field) && $entity->get($field) !== null;
}
}
@@ -0,0 +1,51 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2018 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
* Website: http://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Core\FieldValidators;
use \Espo\ORM\Entity;
class PersonNameType extends BaseType
{
public function checkRequired(\Espo\ORM\Entity $entity, string $field, $validationValue, $data) : bool
{
$isEmpty = true;
foreach ($this->getActualAttributeList($entity, $field) as $attribute) {
if ($attribute === 'salutation' . ucfirst($field)) {
continue;
}
if ($entity->has($attribute) && $entity->get($attribute) !== '') {
$isEmpty = false;
break;
}
}
if ($isEmpty) return false;
return true;
}
}
@@ -0,0 +1,40 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2018 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
* Website: http://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Core\FieldValidators;
use \Espo\ORM\Entity;
class VarcharType extends BaseType
{
public function checkRequired(\Espo\ORM\Entity $entity, string $field, $validationValue, $data) : bool
{
return $entity->has($field) && $entity->get($field) !== '';
}
}
@@ -0,0 +1,41 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2018 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
* Website: http://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Core\Loaders;
class FieldValidatorManager extends Base
{
public function load()
{
return new \Espo\Core\Utils\FieldValidatorManager(
$this->getContainer()->get('metadata'),
$this->getContainer()->get('fieldManagerUtil')
);
}
}
@@ -185,4 +185,14 @@ class FieldManagerUtil
$this->getFieldTypeAttributeListByType($fieldType, $name, 'notActual')
);
}
public function getEntityTypeFieldList($entityType)
{
return array_keys($this->getMetadata()->get(['entityDefs', $entityType, 'fields'], []));
}
public function getEntityTypeFieldParam($entityType, $field, $param)
{
return $this->getMetadata()->get(['entityDefs', $entityType, 'fields', $field, $param]);
}
}
@@ -0,0 +1,79 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2018 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
* Website: http://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Core\Utils;
class FieldValidatorManager
{
private $metadata;
private $fieldManagerUtil;
private $implHash = [];
public function __construct(Metadata $metadata, FieldManagerUtil $fieldManagerUtil)
{
$this->metadata = $metadata;
$this->fieldManagerUtil = $fieldManagerUtil;
}
public function check(\Espo\ORM\Entity $entity, string $field, string $type, $data = null) : bool
{
if (!$data) $data = (object) [];
$validationValue = $this->fieldManagerUtil->getEntityTypeFieldParam($entity->getEntityType(), $field, $type);
if (is_null($validationValue) || $validationValue === false) return true;
$fieldType = $this->fieldManagerUtil->getEntityTypeFieldParam($entity->getEntityType(), $field, 'type');
if (!array_key_exists($fieldType, $this->implHash)) {
$this->loadImpl($fieldType);
}
$impl = $this->implHash[$fieldType];
$methodName = 'check' . ucfirst($type);
if (!method_exists($impl, $methodName)) return true;
return $impl->$methodName($entity, $field, $validationValue, $data);
}
protected function loadImpl(string $fieldType)
{
$className = $this->metadata->get(['fields', $fieldType, 'validatorClassName']);
if (!$className) {
$className = '\\Espo\\Core\\FieldValidators\\' . ucfirst($fieldType) . 'Type';
if (!class_exists($className)) {
$className = '\\Espo\\Core\\FieldValidators\\BaseType';
}
}
$this->implHash[$fieldType] = new $className($this->metadata, $this->fieldManagerUtil);
}
}
@@ -52,6 +52,7 @@
"importDisabled": true
}
},
"validationList": ["required"],
"filter": true,
"personalData": true
}
@@ -26,6 +26,7 @@
"type":"bool"
}
],
"validationList": ["required"],
"filter": true,
"fieldDefs":{
"notNull":false
@@ -30,6 +30,7 @@
"type":"bool"
}
],
"validationList": ["required"],
"filter": true,
"textFilter": true,
"textFilterForeign": true,
@@ -35,6 +35,7 @@
"personalData": true,
"textFilter": true,
"fullTextSearch": true,
"validationList": ["required"],
"fullTextSearchColumnList": [
"first",
"last"
@@ -31,6 +31,7 @@
"type":"bool"
}
],
"validationList": ["required"],
"filter": true,
"personalData": true,
"textFilter": true,
+44 -14
View File
@@ -55,6 +55,7 @@ class Record extends \Espo\Core\Services\Base
'fileStorageManager',
'injectableFactory',
'fieldManagerUtil',
'container',
];
protected $getEntityBeforeUpdate = false;
@@ -117,6 +118,8 @@ class Record extends \Espo\Core\Services\Base
protected $forceSelectAllAttributes = false;
protected $validateSkipFieldList = [];
const MAX_SELECT_TEXT_ATTRIBUTE_LENGTH = 5000;
const FOLLOWERS_LIMIT = 4;
@@ -495,16 +498,49 @@ class Record extends \Espo\Core\Services\Base
return $this->getRepository()->save($entity);
}
protected function isValid($entity)
public function processValidation(Entity $entity, $data)
{
$fieldDefs = $entity->getAttributes();
if ($entity->hasAttribute('name') && !empty($fieldDefs['name']['required'])) {
if (!$entity->get('name')) {
return false;
$fieldList = $this->getFieldManagerUtil()->getEntityTypeFieldList($this->entityType);
foreach ($fieldList as $field) {
if (in_array($field, $this->validateSkipFieldList)) continue;
if (!$entity->isNew()) {
if (!$this->isFieldSetInData($data, $field)) continue;
}
$this->processDataValidationField($entity, $field, $data);
}
}
protected function processDataValidationField(Entity $entity, $field, $data)
{
$fieldType = $this->getFieldManagerUtil()->getEntityTypeFieldParam($this->entityType, $field, 'type');
if (!$fieldType) return;
$fieldValidatorManager = $this->getInjection('container')->get('fieldValidatorManager');
$validationTypeList = $this->getMetadata()->get(['fields', $fieldType, 'validationList'], []);
foreach ($validationTypeList as $validationType) {
$validationValue = $this->getFieldManagerUtil()->getEntityTypeFieldParam($this->entityType, $field, $validationType);
if (is_null($validationValue)) continue;
if (!$fieldValidatorManager->check($entity, $field, $validationType, $validationValue, $data)) {
throw new BadRequest("Validation {$validationType}: {$field}.");
}
}
}
return true;
protected function isFieldSetInData($data, $field)
{
$attributeList = $this->getFieldManagerUtil()->getActualAttributeList($this->entityType, $field);
$isSet = false;
foreach ($attributeList as $attribute) {
if (property_exists($data, $attribute)) {
$isSet = true;
break;
}
}
return $isSet;
}
public function checkAssignment(Entity $entity)
@@ -827,11 +863,9 @@ class Record extends \Espo\Core\Services\Base
$this->populateDefaults($entity, $data);
$this->beforeCreateEntity($entity, $data);
$this->processValidation($entity, $data);
if (!$this->isValid($entity)) {
throw new BadRequest();
}
$this->beforeCreateEntity($entity, $data);
if (!$this->checkAssignment($entity)) {
throw new Forbidden('Assignment permission failure');
@@ -895,10 +929,6 @@ class Record extends \Espo\Core\Services\Base
$this->beforeUpdateEntity($entity, $data);
if (!$this->isValid($entity)) {
throw new BadRequest();
}
if (!$this->checkAssignment($entity)) {
throw new Forbidden();
}
+4
View File
@@ -145,6 +145,10 @@
return Object.keys(this.metadata.get(['entityDefs', entityType, 'fields']) || {});
},
getEntityTypeFieldParam: function (entityType, field, param) {
this.metadata.get(['entityDefs', entityType, 'fields', field, param]);
},
getViewName: function (fieldType) {
if (fieldType in this.defs) {
if ('view' in this.defs[fieldType]) {