Merge pull request #17807 from atm-john/new_validation_method_for_common_object
New : Create validation method for common object
This commit is contained in:
commit
5201d87ba7
@ -105,6 +105,15 @@ if ($action == 'add' && !empty($permissiontoadd)) {
|
||||
$error++;
|
||||
setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv($val['label'])), null, 'errors');
|
||||
}
|
||||
|
||||
// Validation of fields values
|
||||
if ($conf->global->MAIN_FEATURE_LEVEL >= 2 || !empty($conf->global->MAIN_ACTIVATE_VALIDATION_RESULT)) {
|
||||
if (!$error && !empty($val['validate']) && is_callable(array($object, 'validateField'))) {
|
||||
if (!$object->validateField($object->fields, $key, $value)) {
|
||||
$error++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fill array 'array_options' with data from add form
|
||||
@ -204,6 +213,15 @@ if ($action == 'update' && !empty($permissiontoadd)) {
|
||||
$error++;
|
||||
setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv($val['label'])), null, 'errors');
|
||||
}
|
||||
|
||||
// Validation of fields values
|
||||
if ($conf->global->MAIN_FEATURE_LEVEL >= 2 || !empty($conf->global->MAIN_ACTIVATE_VALIDATION_RESULT)) {
|
||||
if (!$error && !empty($val['validate']) && is_callable(array($object, 'validateField'))) {
|
||||
if (!$object->validateField($object->fields, $key, $value)) {
|
||||
$error++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fill array 'array_options' with data from add form
|
||||
|
||||
@ -73,6 +73,11 @@ abstract class CommonObject
|
||||
*/
|
||||
public $errors = array();
|
||||
|
||||
/**
|
||||
* @var array To store error results of ->validateField()
|
||||
*/
|
||||
public $validateFieldsErrors = array();
|
||||
|
||||
/**
|
||||
* @var string ID to identify managed object
|
||||
*/
|
||||
@ -123,14 +128,12 @@ abstract class CommonObject
|
||||
*/
|
||||
protected $table_ref_field = '';
|
||||
|
||||
/**
|
||||
* 0=Default, 1=View may be restricted to sales representative only if no permission to see all or to company of external user if external user
|
||||
* @var integer
|
||||
/**
|
||||
* @var integer 0=Default, 1=View may be restricted to sales representative only if no permission to see all or to company of external user if external user
|
||||
*/
|
||||
public $restrictiononfksoc = 0;
|
||||
|
||||
|
||||
|
||||
// Following vars are used by some objects only. We keep this property here in CommonObject to be able to provide common method using them.
|
||||
|
||||
/**
|
||||
@ -6422,6 +6425,16 @@ abstract class CommonObject
|
||||
$val = $this->fields[$key];
|
||||
}
|
||||
|
||||
// Validation tests and output
|
||||
$fieldValidationErrorMsg = '';
|
||||
$validationClass = '';
|
||||
$fieldValidationErrorMsg = $this->getFieldError($key);
|
||||
if (!empty($fieldValidationErrorMsg)) {
|
||||
$validationClass = ' --error'; // the -- is use as class state in css : .--error can't be be defined alone it must be define with another class like .my-class.--error or input.--error
|
||||
} else {
|
||||
$validationClass = ' --success'; // the -- is use as class state in css : .--success can't be be defined alone it must be define with another class like .my-class.--success or input.--success
|
||||
}
|
||||
|
||||
$out = '';
|
||||
$type = '';
|
||||
$isDependList=0;
|
||||
@ -6513,6 +6526,11 @@ abstract class CommonObject
|
||||
}
|
||||
}
|
||||
|
||||
// Add validation state class
|
||||
if (!empty($validationClass)) {
|
||||
$morecss.= ' '.$validationClass;
|
||||
}
|
||||
|
||||
if (in_array($type, array('date'))) {
|
||||
$tmp = explode(',', $size);
|
||||
$newsize = $tmp[0];
|
||||
@ -6979,6 +6997,12 @@ abstract class CommonObject
|
||||
if ($type == 'date') $out.=' (YYYY-MM-DD)';
|
||||
elseif ($type == 'datetime') $out.=' (YYYY-MM-DD HH:MM:SS)';
|
||||
*/
|
||||
|
||||
// Display error message for field
|
||||
if (!empty($fieldValidationErrorMsg) && function_exists('getFieldErrorIcon')) {
|
||||
$out .= ' '.getFieldErrorIcon($fieldValidationErrorMsg);
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
@ -7318,6 +7342,228 @@ abstract class CommonObject
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* clear validation message result for a field
|
||||
*
|
||||
* @param string $fieldKey Key of attribute to clear
|
||||
* @return null
|
||||
*/
|
||||
public function clearFieldError($fieldKey)
|
||||
{
|
||||
$this->error = '';
|
||||
unset($this->validateFieldsErrors[$fieldKey]);
|
||||
}
|
||||
|
||||
/**
|
||||
* set validation error message a field
|
||||
*
|
||||
* @param string $fieldKey Key of attribute
|
||||
* @param string $msg the field error message
|
||||
* @return null
|
||||
*/
|
||||
public function setFieldError($fieldKey, $msg = '')
|
||||
{
|
||||
global $langs;
|
||||
if (empty($msg)) { $msg = $langs->trans("UnknowError"); }
|
||||
|
||||
$this->error = $this->validateFieldsErrors[$fieldKey] = $msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* get field error message
|
||||
*
|
||||
* @param string $fieldKey Key of attribute
|
||||
* @return string
|
||||
*/
|
||||
public function getFieldError($fieldKey)
|
||||
{
|
||||
if (!empty($this->validateFieldsErrors[$fieldKey])) {
|
||||
return $this->validateFieldsErrors[$fieldKey];
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return validation test result for a field
|
||||
*
|
||||
* @param array $val Array of properties of field to show
|
||||
* @param string $fieldKey Key of attribute
|
||||
* @param string $fieldValue value of attribute
|
||||
* @return bool return false if fail true on success, see $this->error for error message
|
||||
*/
|
||||
public function validateField($val, $fieldKey, $fieldValue)
|
||||
{
|
||||
global $langs;
|
||||
|
||||
if (!class_exists('Validate')) { require_once DOL_DOCUMENT_ROOT . '/core/class/validate.class.php'; }
|
||||
|
||||
$this->clearFieldError($fieldKey);
|
||||
|
||||
if (!isset($val[$fieldKey])) {
|
||||
$this->setFieldError($fieldKey, $langs->trans('FieldNotFoundInObject'));
|
||||
return false;
|
||||
}
|
||||
|
||||
$param = array();
|
||||
$param['options'] = array();
|
||||
$type = $val[$fieldKey]['type'];
|
||||
|
||||
$required = false;
|
||||
if (isset($val[$fieldKey]['notnull']) && $val[$fieldKey]['notnull'] === 1) {
|
||||
// 'notnull' is set to 1 if not null in database. Set to -1 if we must set data to null if empty ('' or 0).
|
||||
$required = true;
|
||||
}
|
||||
|
||||
$maxSize = 0;
|
||||
$minSize = 0;
|
||||
|
||||
//
|
||||
// PREPARE Elements
|
||||
//
|
||||
|
||||
// Convert var to be able to share same code than showOutputField of extrafields
|
||||
if (preg_match('/varchar\((\d+)\)/', $type, $reg)) {
|
||||
$type = 'varchar'; // convert varchar(xx) int varchar
|
||||
$maxSize = $reg[1];
|
||||
} elseif (preg_match('/varchar/', $type)) {
|
||||
$type = 'varchar'; // convert varchar(xx) int varchar
|
||||
}
|
||||
|
||||
if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) {
|
||||
$type = 'select';
|
||||
}
|
||||
|
||||
if (preg_match('/^integer:(.*):(.*)/i', $val['type'], $reg)) {
|
||||
$type = 'link';
|
||||
}
|
||||
|
||||
if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) {
|
||||
$param['options'] = $val['arrayofkeyval'];
|
||||
}
|
||||
|
||||
if (preg_match('/^integer:(.*):(.*)/i', $val['type'], $reg)) {
|
||||
$type = 'link';
|
||||
$param['options'] = array($reg[1].':'.$reg[2]=>$reg[1].':'.$reg[2]);
|
||||
} elseif (preg_match('/^sellist:(.*):(.*):(.*):(.*)/i', $val['type'], $reg)) {
|
||||
$param['options'] = array($reg[1].':'.$reg[2].':'.$reg[3].':'.$reg[4] => 'N');
|
||||
$type = 'sellist';
|
||||
} elseif (preg_match('/^sellist:(.*):(.*):(.*)/i', $val['type'], $reg)) {
|
||||
$param['options'] = array($reg[1].':'.$reg[2].':'.$reg[3] => 'N');
|
||||
$type = 'sellist';
|
||||
} elseif (preg_match('/^sellist:(.*):(.*)/i', $val['type'], $reg)) {
|
||||
$param['options'] = array($reg[1].':'.$reg[2] => 'N');
|
||||
$type = 'sellist';
|
||||
}
|
||||
|
||||
//
|
||||
// TEST Value
|
||||
//
|
||||
|
||||
// Use Validate class to allow external Modules to use data validation part instead of concentrate all test here (factoring) or just for reuse
|
||||
$validate = new Validate($this->db, $langs);
|
||||
|
||||
|
||||
// little trick : to perform tests with good performances sort tests by quick to low
|
||||
|
||||
//
|
||||
// COMMON TESTS
|
||||
//
|
||||
|
||||
// Required test and empty value
|
||||
if ($required && !$validate->isNotEmptyString($fieldValue)) {
|
||||
$this->setFieldError($fieldKey, $validate->error);
|
||||
return false;
|
||||
} elseif (!$required && !$validate->isNotEmptyString($fieldValue)) {
|
||||
// if no value sent and the field is not mandatory, no need to perform tests
|
||||
return true;
|
||||
}
|
||||
|
||||
// MAX Size test
|
||||
if (!empty($maxSize) && !$validate->isMaxLength($fieldValue, $maxSize)) {
|
||||
$this->setFieldError($fieldKey, $validate->error);
|
||||
return false;
|
||||
}
|
||||
|
||||
// MIN Size test
|
||||
if (!empty($minSize) && !$validate->isMinLength($fieldValue, $minSize)) {
|
||||
$this->setFieldError($fieldKey, $validate->error);
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// TESTS for TYPE
|
||||
//
|
||||
|
||||
if (in_array($type, array('date', 'datetime', 'timestamp'))) {
|
||||
if (!$validate->isTimestamp($fieldValue)) {
|
||||
$this->setFieldError($fieldKey, $validate->error);
|
||||
return false;
|
||||
} else { return true; }
|
||||
} elseif ($type == 'duration') {
|
||||
if (!$validate->isDuration($fieldValue)) {
|
||||
$this->setFieldError($fieldKey, $validate->error);
|
||||
return false;
|
||||
} else { return true; }
|
||||
} elseif (in_array($type, array('double', 'real', 'price'))) {
|
||||
// is numeric
|
||||
if (!$validate->isDuration($fieldValue)) {
|
||||
$this->setFieldError($fieldKey, $validate->error);
|
||||
return false;
|
||||
} else { return true; }
|
||||
} elseif ($type == 'boolean') {
|
||||
if (!$validate->isBool($fieldValue)) {
|
||||
$this->setFieldError($fieldKey, $validate->error);
|
||||
return false;
|
||||
} else { return true; }
|
||||
} elseif ($type == 'mail') {
|
||||
if (!$validate->isEmail($fieldValue)) {
|
||||
$this->setFieldError($fieldKey, $validate->error);
|
||||
return false;
|
||||
}
|
||||
} elseif ($type == 'url') {
|
||||
if (!$validate->isUrl($fieldValue)) {
|
||||
$this->setFieldError($fieldKey, $validate->error);
|
||||
return false;
|
||||
} else { return true; }
|
||||
} elseif ($type == 'phone') {
|
||||
if (!$validate->isPhone($fieldValue)) {
|
||||
$this->setFieldError($fieldKey, $validate->error);
|
||||
return false;
|
||||
} else { return true; }
|
||||
} elseif ($type == 'select' || $type == 'radio') {
|
||||
if (!isset($param['options'][$fieldValue])) {
|
||||
$this->error = $langs->trans('RequireValidValue');
|
||||
return false;
|
||||
} else { return true; }
|
||||
} elseif ($type == 'sellist' || $type == 'chkbxlst') {
|
||||
$param_list = array_keys($param['options']);
|
||||
$InfoFieldList = explode(":", $param_list[0]);
|
||||
$value_arr = explode(',', $fieldValue);
|
||||
$value_arr = array_map(array($this->db, 'escape'), $value_arr);
|
||||
|
||||
$selectkey = "rowid";
|
||||
if (count($InfoFieldList) > 4 && !empty($InfoFieldList[4])) {
|
||||
$selectkey = $InfoFieldList[2];
|
||||
}
|
||||
|
||||
if (!isInDb($value_arr, $InfoFieldList[0], $selectkey)) {
|
||||
$this->setFieldError($fieldKey, $validate->error);
|
||||
return false;
|
||||
} else { return true; }
|
||||
} elseif ($type == 'link') {
|
||||
$param_list = array_keys($param['options']); // $param_list='ObjectName:classPath'
|
||||
$InfoFieldList = explode(":", $param_list[0]);
|
||||
$classname = $InfoFieldList[0];
|
||||
$classpath = $InfoFieldList[1];
|
||||
if (!$validate->isFetchable($fieldValue, $classname, $classpath)) {
|
||||
$this->setFieldError($fieldKey, $validate->error);
|
||||
return false;
|
||||
} else { return true; }
|
||||
}
|
||||
|
||||
// if no test failled all is ok
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to show lines of extrafields with output datas.
|
||||
|
||||
309
htdocs/core/class/validate.class.php
Normal file
309
htdocs/core/class/validate.class.php
Normal file
@ -0,0 +1,309 @@
|
||||
<?php
|
||||
/* Copyright (C) 2021 John BOTELLA <john.botella@atm-consulting.fr>
|
||||
*
|
||||
* This program 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
|
||||
* any later version.
|
||||
*
|
||||
* This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file htdocs/core/class/validate.class.php
|
||||
* \ingroup core
|
||||
* \brief File for Utils class
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Class toolbox to validate values
|
||||
*/
|
||||
class Validate
|
||||
{
|
||||
|
||||
/**
|
||||
* @var DoliDb Database handler (result of a new DoliDB)
|
||||
*/
|
||||
public $db;
|
||||
|
||||
/**
|
||||
* @var Translate $outputLang
|
||||
*/
|
||||
public $outputLang;
|
||||
|
||||
/**
|
||||
* @var string Error string
|
||||
* @see $errors
|
||||
*/
|
||||
public $error;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param DoliDB $db Database handler
|
||||
* @param Translate $outputLang output lang for error
|
||||
* @return null
|
||||
*/
|
||||
public function __construct($db, $outputLang = false)
|
||||
{
|
||||
global $langs;
|
||||
|
||||
if ($outputLang) {
|
||||
$this->outputLang = $langs;
|
||||
} else {
|
||||
$this->outputLang = $outputLang;
|
||||
}
|
||||
|
||||
$outputLang->load('validate');
|
||||
|
||||
$this->db = $db;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use to clear errors msg or other ghost vars
|
||||
* @return null
|
||||
*/
|
||||
protected function clear()
|
||||
{
|
||||
$this->error = '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Use to clear errors msg or other ghost vars
|
||||
*
|
||||
* @param string $errMsg your error message
|
||||
* @return null
|
||||
*/
|
||||
protected function setError($errMsg)
|
||||
{
|
||||
$this->error = $errMsg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for e-mail validity
|
||||
*
|
||||
* @param string $email e-mail address to validate
|
||||
* @param int $maxLength string max length
|
||||
* @return boolean Validity is ok or not
|
||||
*/
|
||||
public function isEmail($email, $maxLength = false)
|
||||
{
|
||||
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||
$this->error = $this->outputLang->trans('RequireValidEmail');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for price validity
|
||||
*
|
||||
* @param string $price Price to validate
|
||||
* @return boolean Validity is ok or not
|
||||
*/
|
||||
public function isPrice($price)
|
||||
{
|
||||
if (!preg_match('/^[0-9]{1,10}(\.[0-9]{1,9})?$/ui', $price)) {
|
||||
$this->error = $this->outputLang->trans('RequireValidValue');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for timestamp validity
|
||||
*
|
||||
* @param string|int $stamp timestamp to validate
|
||||
* @return boolean Validity is ok or not
|
||||
*/
|
||||
public function isTimestamp($stamp)
|
||||
{
|
||||
if (!is_numeric($stamp) && (int) $stamp == $stamp) {
|
||||
$this->error = $this->outputLang->trans('RequireValidDate');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for phone validity
|
||||
*
|
||||
* @param string $phone Phone string to validate
|
||||
* @return boolean Validity is ok or not
|
||||
*/
|
||||
public function isPhone($phone)
|
||||
{
|
||||
if (!preg_match('/^[+0-9. ()-]*$/ui', $phone)) {
|
||||
$this->error = $this->outputLang->trans('RequireValidPhone');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for string max length validity
|
||||
*
|
||||
* @param string $string to validate
|
||||
* @param int $length max length
|
||||
* @return boolean Validity is ok or not
|
||||
*/
|
||||
public function isMaxLength($string, $length)
|
||||
{
|
||||
if (strlen($string) > $length) {
|
||||
$this->error = $this->outputLang->trans('RequireMaxLength', $length);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for string not empty
|
||||
*
|
||||
* @param string $string to validate
|
||||
* @return boolean Validity is ok or not
|
||||
*/
|
||||
public function isNotEmptyString($string)
|
||||
{
|
||||
if (!strlen($string)) {
|
||||
$this->error = $this->outputLang->trans('RequireANotEmptyValue');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for string min length validity
|
||||
*
|
||||
* @param string $string to validate
|
||||
* @param int $length max length
|
||||
* @return boolean Validity is ok or not
|
||||
*/
|
||||
public function isMinLength($string, $length)
|
||||
{
|
||||
if (!strlen($string) < $length) {
|
||||
$this->error = $this->outputLang->trans('RequireMinLength', $length);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check url validity
|
||||
*
|
||||
* @param string $url to validate
|
||||
* @return boolean Validity is ok or not
|
||||
*/
|
||||
public function isUrl($url)
|
||||
{
|
||||
if (!filter_var($url, FILTER_VALIDATE_URL)) {
|
||||
$this->error = $this->outputLang->trans('RequireValidUrl');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check Duration validity
|
||||
*
|
||||
* @param string $duration to validate
|
||||
* @return boolean Validity is ok or not
|
||||
*/
|
||||
public function isDuration($duration)
|
||||
{
|
||||
if (!is_int($duration) && $duration >= 0) {
|
||||
$this->error = $this->outputLang->trans('RequireValidDuration');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for boolean validity
|
||||
*
|
||||
* @param boolean $bool Boolean to validate
|
||||
* @return boolean Validity is ok or not
|
||||
*/
|
||||
public function isBool($bool)
|
||||
{
|
||||
if (!(is_null($bool) || is_bool($bool) || preg_match('/^[0|1]{1}$/ui', $bool))) {
|
||||
$this->error = $this->outputLang->trans('RequireValidBool');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for all values in db
|
||||
*
|
||||
* @param array $values Boolean to validate
|
||||
* @param string $table the db table name without MAIN_DB_PREFIX
|
||||
* @param string $col the target col
|
||||
* @return boolean Validity is ok or not
|
||||
* @throws Exception
|
||||
*/
|
||||
public function isInDb($values, $table, $col)
|
||||
{
|
||||
if (!is_array($values)) {
|
||||
$value_arr = array($values);
|
||||
} else {
|
||||
$value_arr = $values;
|
||||
}
|
||||
|
||||
if (!count($value_arr)) {
|
||||
$this->error = $this->outputLang->trans('RequireValue');
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($value_arr as $val) {
|
||||
$sql = 'SELECT ' . $col . ' FROM ' . MAIN_DB_PREFIX . $table . " WHERE " . $col ." = '" . $this->db->escape($val) . "'"; // nore quick than count(*) to check existing of a row
|
||||
$resql = $this->db->getRow($sql);
|
||||
if ($resql) {
|
||||
continue;
|
||||
} else {
|
||||
$this->error = $this->outputLang->trans('RequireValidExistingElement');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for all values in db
|
||||
*
|
||||
* @param array $values Boolean to validate
|
||||
* @param string $classname the class name
|
||||
* @param string $classpath the class path
|
||||
* @return boolean Validity is ok or not
|
||||
* @throws Exception
|
||||
*/
|
||||
public function isFetchable($values, $classname, $classpath)
|
||||
{
|
||||
if (!empty($classpath)) {
|
||||
if (dol_include_once($classpath)) {
|
||||
if ($classname && class_exists($classname)) {
|
||||
/** @var CommonObject $object */
|
||||
$object = new $classname($this->db);
|
||||
|
||||
if (!is_callable(array($object, 'fetch')) || !is_callable(array($object, 'isExistingObject'))) {
|
||||
$this->error = $this->outputLang->trans('BadSetupOfFieldFetchNotCallable');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!empty($object->table_element) && $object->isExistingObject($object->table_element, $values)) {
|
||||
return true;
|
||||
} else { $this->error = $this->outputLang->trans('RequireValidExistingElement'); }
|
||||
} else { $this->error = $this->outputLang->trans('BadSetupOfFieldClassNotFoundForValidation'); }
|
||||
} else { $this->error = $this->outputLang->trans('BadSetupOfFieldFileNotFound'); }
|
||||
} else { $this->error = $this->outputLang->trans('BadSetupOfField'); }
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -9921,6 +9921,24 @@ function dolGetButtonTitleSeparator($moreClass = "")
|
||||
return '<span class="button-title-separator '.$moreClass.'" ></span>';
|
||||
}
|
||||
|
||||
/**
|
||||
* get field error icon
|
||||
*
|
||||
* @param string $fieldValidationErrorMsg message to add in tooltip
|
||||
* @return string html output
|
||||
*/
|
||||
function getFieldErrorIcon($fieldValidationErrorMsg)
|
||||
{
|
||||
$out = '';
|
||||
if (!empty($fieldValidationErrorMsg)) {
|
||||
$out.= '<span class="field-error-icon classfortooltip" title="'.dol_escape_htmltag($fieldValidationErrorMsg, 1).'" role="alert" >'; // role alert is used for accessibility
|
||||
$out.= '<span class="fa fa-exclamation-circle" aria-hidden="true" ></span>'; // For accessibility icon is separated and aria-hidden
|
||||
$out.= '</span>';
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function dolGetButtonTitle : this kind of buttons are used in title in list
|
||||
*
|
||||
|
||||
@ -176,6 +176,9 @@ function rebuildObjectClass($destdir, $module, $objectname, $newmask, $readdir =
|
||||
}
|
||||
$texttoinsert .= "),";
|
||||
}
|
||||
if ($val['validate']) {
|
||||
$texttoinsert .= " 'validate'=>'".$val['validate']."',";
|
||||
}
|
||||
if ($val['comment']) {
|
||||
$texttoinsert .= " 'comment'=>\"".preg_replace('/"/', '', $val['comment'])."\"";
|
||||
}
|
||||
|
||||
@ -143,4 +143,5 @@ AsciiToHtmlConverter=Ascii to HTML converter
|
||||
AsciiToPdfConverter=Ascii to PDF converter
|
||||
TableNotEmptyDropCanceled=Table not empty. Drop has been canceled.
|
||||
ModuleBuilderNotAllowed=The module builder is available but not allowed to your user.
|
||||
ImportExportProfiles=Import and export profiles
|
||||
ImportExportProfiles=Import and export profiles
|
||||
ValidateModBuilderDesc=Put 1 if this field need to be validated with $this->validateField() or 0 if validation required
|
||||
|
||||
19
htdocs/langs/en_US/validate.lang
Normal file
19
htdocs/langs/en_US/validate.lang
Normal file
@ -0,0 +1,19 @@
|
||||
# Dolibarr language file - Source file is en_US - users
|
||||
RequireValidValue = Value not valid
|
||||
RequireAtLeastXString = Requires at least % character(s)
|
||||
RequireXStringMax = Requires % character(s) max
|
||||
RequireAtLeastXDigits = Requires at least % digit(s)
|
||||
RequireXDigitsMax = Requires % digit(s) max
|
||||
RequireValidEmail = Email address is not valid
|
||||
RequireMaxLength = Length must be less than %s chars
|
||||
RequireMinLength = Length must be more than %s char(s)
|
||||
RequireValidUrl = Require valid URL
|
||||
RequireValidDate = Require a valid date
|
||||
RequireANotEmptyValue = Is required
|
||||
RequireValidDuration = Require a valid duration
|
||||
RequireValidExistingElement = Require an existing value
|
||||
RequireValidBool = Require a valid boolean
|
||||
BadSetupOfField = Error bad setup of field
|
||||
BadSetupOfFieldClassNotFoundForValidation = Error bad setup of field : Class not found for validation
|
||||
BadSetupOfFieldFileNotFound = Error bad setup of field : File not found for inclusion
|
||||
BadSetupOfFieldFetchNotCallable = Error bad setup of field : Fetch not callable on class
|
||||
@ -1303,7 +1303,8 @@ if ($dirins && $action == 'addproperty' && empty($cancel) && !empty($module) &&
|
||||
'visible'=>GETPOST('propvisible', 'int'), 'enabled'=>GETPOST('propenabled', 'int'),
|
||||
'position'=>GETPOST('propposition', 'int'), 'notnull'=>GETPOST('propnotnull', 'int'), 'index'=>GETPOST('propindex', 'int'), 'searchall'=>GETPOST('propsearchall', 'int'),
|
||||
'isameasure'=>GETPOST('propisameasure', 'int'), 'comment'=>GETPOST('propcomment', 'alpha'), 'help'=>GETPOST('prophelp', 'alpha'),
|
||||
'css'=>GETPOST('propcss', 'aZ09'), 'cssview'=>GETPOST('propcssview', 'aZ09'), 'csslist'=>GETPOST('propcsslist', 'aZ09')
|
||||
'css'=>GETPOST('propcss', 'aZ09'), 'cssview'=>GETPOST('propcssview', 'aZ09'), 'csslist'=>GETPOST('propcsslist', 'aZ09'),
|
||||
'validate' => GETPOST('propvalidate', 'int')
|
||||
);
|
||||
|
||||
if (!empty($addfieldentry['arrayofkeyval']) && !is_array($addfieldentry['arrayofkeyval'])) {
|
||||
@ -2680,6 +2681,7 @@ if ($module == 'initmodule') {
|
||||
print '<th>'.$langs->trans("KeyForTooltip").'</th>';
|
||||
print '<th class="center">'.$langs->trans("ShowOnCombobox").'</th>';
|
||||
//print '<th class="center">'.$langs->trans("Disabled").'</th>';
|
||||
print '<th>'.$form->textwithpicto($langs->trans("Validate"), $langs->trans("ValidateModBuilderDesc")).'</th>';
|
||||
print '<th>'.$langs->trans("Comment").'</th>';
|
||||
print '<th></th>';
|
||||
print '</tr>';
|
||||
@ -2712,6 +2714,7 @@ if ($module == 'initmodule') {
|
||||
print '<td><input type="text" size="2" name="prophelp" value="'.dol_escape_htmltag(GETPOST('prophelp', 'alpha')).'"></td>';
|
||||
print '<td class="center"><input type="text" class="center maxwidth50" name="propshowoncombobox" value="'.dol_escape_htmltag(GETPOST('propshowoncombobox', 'alpha')).'"></td>';
|
||||
//print '<td class="center"><input type="text" size="2" name="propdisabled" value="'.dol_escape_htmltag(GETPOST('propdisabled', 'alpha')).'"></td>';
|
||||
print '<td><input type="number" step="1" min="0" max="1" class="text maxwidth100" name="propvalidate" value="'.dol_escape_htmltag(GETPOST('propvalidate', 'alpha')).'"></td>';
|
||||
print '<td><input class="text maxwidth100" name="propcomment" value="'.dol_escape_htmltag(GETPOST('propcomment', 'alpha')).'"></td>';
|
||||
print '<td class="center">';
|
||||
print '<input class="button" type="submit" name="add" value="'.$langs->trans("Add").'">';
|
||||
@ -2753,6 +2756,7 @@ if ($module == 'initmodule') {
|
||||
$prophelp = $propval['help'];
|
||||
$propshowoncombobox = $propval['showoncombobox'];
|
||||
//$propdisabled=$propval['disabled'];
|
||||
$propvalidate = $propval['validate'];
|
||||
$propcomment = $propval['comment'];
|
||||
|
||||
print '<tr class="oddeven">';
|
||||
@ -2823,6 +2827,9 @@ if ($module == 'initmodule') {
|
||||
print '<input class="center maxwidth50" name="propshowoncombobox" value="'.dol_escape_htmltag($propshowoncombobox).'">';
|
||||
print '</td>';
|
||||
print '<td>';
|
||||
print '<input type="number" step="1" min="0" max="1" class="text maxwidth100" name="propvalidate" value="'.dol_escape_htmltag($propvalidate).'">';
|
||||
print '</td>';
|
||||
print '<td>';
|
||||
print '<input class="maxwidth100" name="propcomment" value="'.dol_escape_htmltag($propcomment).'">';
|
||||
print '</td>';
|
||||
print '<td class="center">';
|
||||
@ -2888,6 +2895,9 @@ if ($module == 'initmodule') {
|
||||
/*print '<td class="center">';
|
||||
print $propdisabled?$propdisabled:'';
|
||||
print '</td>';*/
|
||||
print '<td class="center">';
|
||||
print $propvalidate ? dol_escape_htmltag($propvalidate) : '';
|
||||
print '</td>';
|
||||
print '<td class="tdoverflowmax200">';
|
||||
print '<span title="'.dol_escape_htmltag($propcomment).'">';
|
||||
print dol_escape_htmltag($propcomment);
|
||||
|
||||
@ -91,7 +91,7 @@ class MyObject extends CommonObject
|
||||
* 'arrayofkeyval' to set a list of values if type is a list of predefined values. For example: array("0"=>"Draft","1"=>"Active","-1"=>"Cancel"). Note that type can be 'integer' or 'varchar'
|
||||
* 'autofocusoncreate' to have field having the focus on a create form. Only 1 field should have this property set to 1.
|
||||
* 'comment' is not used. You can store here any text of your choice. It is not used by application.
|
||||
*
|
||||
* 'validate' is 1 if need to validate with $this->validateField()
|
||||
* Note: To have value dynamic, you can set value to 0 in definition and edit the value on the fly into the constructor.
|
||||
*/
|
||||
|
||||
@ -102,15 +102,15 @@ class MyObject extends CommonObject
|
||||
public $fields = array(
|
||||
'rowid' => array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>1, 'visible'=>-2, 'noteditable'=>1, 'notnull'=> 1, 'index'=>1, 'position'=>1, 'comment'=>'Id', 'css'=>'left'),
|
||||
'entity' => array('type'=>'integer', 'label'=>'Entity', 'enabled'=>1, 'visible'=>0, 'notnull'=> 1, 'default'=>1, 'index'=>1, 'position'=>10),
|
||||
'ref' => array('type'=>'varchar(128)', 'label'=>'Ref', 'enabled'=>1, 'visible'=>1, 'noteditable'=>0, 'default'=>'', 'notnull'=> 1, 'showoncombobox'=>1, 'index'=>1, 'position'=>20, 'searchall'=>1, 'comment'=>'Reference of object'),
|
||||
'label' => array('type'=>'varchar(255)', 'label'=>'Label', 'enabled'=>1, 'visible'=>1, 'position'=>30, 'searchall'=>1, 'css'=>'minwidth300', 'cssview'=>'wordbreak', 'help'=>'Help text', 'showoncombobox'=>2),
|
||||
'amount' => array('type'=>'price', 'label'=>'Amount', 'enabled'=>1, 'visible'=>1, 'default'=>'null', 'position'=>40, 'searchall'=>0, 'isameasure'=>1, 'help'=>'Help text for amount'),
|
||||
'qty' => array('type'=>'real', 'label'=>'Qty', 'enabled'=>1, 'visible'=>1, 'default'=>'0', 'position'=>45, 'searchall'=>0, 'isameasure'=>1, 'help'=>'Help text for quantity', 'css'=>'maxwidth75imp'),
|
||||
'fk_soc' => array('type'=>'integer:Societe:societe/class/societe.class.php:1:status=1 AND entity IN (__SHARED_ENTITIES__)', 'picto'=>'company', 'label'=>'ThirdParty', 'visible'=> 1, 'enabled'=>1, 'position'=>50, 'notnull'=>-1, 'index'=>1, 'help'=>'LinkToThirparty'),
|
||||
'fk_project' => array('type'=>'integer:Project:projet/class/project.class.php:1', 'label'=>'Project', 'picto'=>'project', 'enabled'=>1, 'visible'=>-1, 'position'=>52, 'notnull'=>-1, 'index'=>1),
|
||||
'description' => array('type'=>'text', 'label'=>'Description', 'enabled'=>1, 'visible'=>3, 'position'=>60),
|
||||
'note_public' => array('type'=>'html', 'label'=>'NotePublic', 'enabled'=>1, 'visible'=>0, 'position'=>61),
|
||||
'note_private' => array('type'=>'html', 'label'=>'NotePrivate', 'enabled'=>1, 'visible'=>0, 'position'=>62),
|
||||
'ref' => array('type'=>'varchar(128)', 'label'=>'Ref', 'enabled'=>1, 'visible'=>1, 'noteditable'=>0, 'default'=>'', 'notnull'=> 1, 'showoncombobox'=>1, 'index'=>1, 'position'=>20, 'searchall'=>1, 'comment'=>'Reference of object', 'validate'=>1),
|
||||
'label' => array('type'=>'varchar(255)', 'label'=>'Label', 'enabled'=>1, 'visible'=>1, 'position'=>30, 'searchall'=>1, 'css'=>'minwidth300', 'cssview'=>'wordbreak', 'help'=>'Help text', 'showoncombobox'=>2, 'validate'=>1),
|
||||
'amount' => array('type'=>'price', 'label'=>'Amount', 'enabled'=>1, 'visible'=>1, 'default'=>'null', 'position'=>40, 'searchall'=>0, 'isameasure'=>1, 'help'=>'Help text for amount', 'validate'=>1),
|
||||
'qty' => array('type'=>'real', 'label'=>'Qty', 'enabled'=>1, 'visible'=>1, 'default'=>'0', 'position'=>45, 'searchall'=>0, 'isameasure'=>1, 'help'=>'Help text for quantity', 'css'=>'maxwidth75imp', 'validate'=>1),
|
||||
'fk_soc' => array('type'=>'integer:Societe:societe/class/societe.class.php:1:status=1 AND entity IN (__SHARED_ENTITIES__)', 'picto'=>'company', 'label'=>'ThirdParty', 'visible'=> 1, 'enabled'=>1, 'position'=>50, 'notnull'=>-1, 'index'=>1, 'help'=>'LinkToThirparty', 'validate'=>1),
|
||||
'fk_project' => array('type'=>'integer:Project:projet/class/project.class.php:1', 'label'=>'Project', 'picto'=>'project', 'enabled'=>1, 'visible'=>-1, 'position'=>52, 'notnull'=>-1, 'index'=>1, 'validate'=>1),
|
||||
'description' => array('type'=>'text', 'label'=>'Description', 'enabled'=>1, 'visible'=>3, 'position'=>60, 'validate'=>1),
|
||||
'note_public' => array('type'=>'html', 'label'=>'NotePublic', 'enabled'=>1, 'visible'=>0, 'position'=>61, 'validate'=>1),
|
||||
'note_private' => array('type'=>'html', 'label'=>'NotePrivate', 'enabled'=>1, 'visible'=>0, 'position'=>62, 'validate'=>1),
|
||||
'date_creation' => array('type'=>'datetime', 'label'=>'DateCreation', 'enabled'=>1, 'visible'=>-2, 'notnull'=> 1, 'position'=>500),
|
||||
'tms' => array('type'=>'timestamp', 'label'=>'DateModification', 'enabled'=>1, 'visible'=>-2, 'notnull'=> 0, 'position'=>501),
|
||||
//'date_validation ' =>array('type'=>'datetime', 'label'=>'DateCreation', 'enabled'=>1, 'visible'=>-2, 'position'=>502),
|
||||
@ -120,7 +120,7 @@ class MyObject extends CommonObject
|
||||
'last_main_doc' => array('type'=>'varchar(255)', 'label'=>'LastMainDoc', 'enabled'=>1, 'visible'=>0, 'notnull'=>0, 'position'=>600),
|
||||
'import_key' => array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>1, 'visible'=>-2, 'notnull'=>-1, 'index'=>0, 'position'=>1000),
|
||||
'model_pdf' => array('type'=>'varchar(255)', 'label'=>'Model pdf', 'enabled'=>1, 'visible'=>0, 'notnull'=>-1, 'position'=>1010),
|
||||
'status' => array('type'=>'smallint', 'label'=>'Status', 'enabled'=>1, 'visible'=>1, 'notnull'=> 1, 'default'=>0, 'index'=>1, 'position'=>1000, 'arrayofkeyval'=>array(0=>'Draft', 1=>'Validated', 9=>'Canceled')),
|
||||
'status' => array('type'=>'smallint', 'label'=>'Status', 'enabled'=>1, 'visible'=>1, 'notnull'=> 1, 'default'=>0, 'index'=>1, 'position'=>1000, 'arrayofkeyval'=>array(0=>'Draft', 1=>'Validated', 9=>'Canceled'), 'validate'=>1),
|
||||
);
|
||||
|
||||
/**
|
||||
|
||||
@ -234,10 +234,12 @@ input.button.massactionconfirmed {
|
||||
margin: 4px;
|
||||
}
|
||||
|
||||
input:invalid, select:invalid {
|
||||
input:invalid, select:invalid, input.--error , select.--error {
|
||||
border-color: #ea1212;
|
||||
}
|
||||
|
||||
.field-error-icon { color: #ea1212; !important; }
|
||||
|
||||
/* Focus definitions must be after standard definition */
|
||||
textarea:focus {
|
||||
border: 1px solid #aaa !important;
|
||||
@ -435,7 +437,7 @@ input.pageplusone {
|
||||
transform: scale(-1, 1);
|
||||
}
|
||||
|
||||
select:invalid {
|
||||
select:invalid, select.--error {
|
||||
color: gray;
|
||||
}
|
||||
input:disabled, textarea:disabled, select[disabled='disabled']
|
||||
@ -2097,7 +2099,7 @@ span.widthpictotitle.pictotitle {
|
||||
vertical-align: middle;
|
||||
margin-top: -3px
|
||||
}
|
||||
.pictowarning, .pictoerror, .pictopreview {
|
||||
.pictowarning, .pictoerror, .pictopreview, .picto.error {
|
||||
padding-<?php echo $left; ?>: 3px;
|
||||
}
|
||||
.pictowarning {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user