Sfoglia il codice sorgente

Prerequisites to the portal forms:
- finalize form fields in the order of their dependencies
- introduced the SelectObjectField which will implement an autocomplete (currently remains a drop-down whatever the number of items)
- code refactoring

git-svn-id: http://svn.code.sf.net/p/itop/code/trunk@3951 a333f486-631f-4898-b8df-5754b55c2be0

romainq 9 anni fa
parent
commit
eed8eb3bb5

+ 1 - 0
sources/autoload.php

@@ -30,6 +30,7 @@ require_once APPROOT . 'sources/form/field/stringfield.class.inc.php';
 require_once APPROOT . 'sources/form/field/textareafield.class.inc.php';
 require_once APPROOT . 'sources/form/field/multiplechoicesfield.class.inc.php';
 require_once APPROOT . 'sources/form/field/selectfield.class.inc.php';
+require_once APPROOT . 'sources/form/field/selectobjectfield.class.inc.php';
 require_once APPROOT . 'sources/form/field/checkboxfield.class.inc.php';
 require_once APPROOT . 'sources/form/field/radiofield.class.inc.php';
 require_once APPROOT . 'sources/form/validator/validator.class.inc.php';

+ 15 - 1
sources/form/field/field.class.inc.php

@@ -378,5 +378,19 @@ abstract class Field
 	 *
 	 * @return boolean
 	 */
-	abstract public function Validate();
+	public function Validate()
+	{
+		$this->SetValid(true);
+		$this->EmptyErrorMessages();
+		foreach ($this->GetValidators() as $oValidator)
+		{
+			if (!preg_match($oValidator->GetRegExp(true), $this->GetCurrentValue()))
+			{
+				$this->SetValid(false);
+				$this->AddErrorMessage($oValidator->GetErrorMessage());
+			}
+		}
+
+		return $this->GetValid();
+	}
 }

+ 102 - 0
sources/form/field/selectobjectfield.class.inc.php

@@ -0,0 +1,102 @@
+<?php
+
+// Copyright (C) 2010-2016 Combodo SARL
+//
+//   This file is part of iTop.
+//
+//   iTop is free software; you can redistribute it and/or modify	
+//   it under the terms of the GNU Affero General Public License as published by
+//   the Free Software Foundation, either version 3 of the License, or
+//   (at your option) any later version.
+//
+//   iTop 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 Affero General Public License for more details.
+//
+//   You should have received a copy of the GNU Affero General Public License
+//   along with iTop. If not, see <http://www.gnu.org/licenses/>
+
+namespace Combodo\iTop\Form\Field;
+
+use \Closure;
+use Combodo\iTop\Form\Validator\NotEmptyExtKeyValidator;
+
+/**
+ * Description of SelectObjectField
+ *
+ */
+class SelectObjectField extends Field
+{
+	protected $sOqlQuery;
+	protected $iMaximumComboLength;
+	protected $iMinAutoCompleteChars;
+
+	public function __construct($sId, Closure $onFinalizeCallback = null)
+	{
+		parent::__construct($sId, $onFinalizeCallback);
+		$this->sOqlQuery = null;
+		$this->iMaximumComboLength = null;
+		$this->iMinAutoCompleteChars = 3;
+	}
+
+	public function SetOqlQuery($sOqlQuery)
+	{
+		$this->sOqlQuery = $sOqlQuery;
+	}
+
+	public function SetMaximumComboLength($iMaximumComboLength)
+	{
+		$this->iMaximumComboLength = $iMaximumComboLength;
+	}
+
+	public function SetMinAutoCompleteChars($iMinAutoCompleteChars)
+	{
+		$this->iMinAutoCompleteChars = $iMinAutoCompleteChars;
+	}
+
+	/**
+	 * Sets if the field is mandatory or not.
+	 * Setting the value will automatically add/remove a MandatoryValidator to the Field
+	 *
+	 * @param boolean $bMandatory
+	 * @return \Combodo\iTop\Form\Field\Field
+	 */
+	public function SetMandatory($bMandatory)
+	{
+		// Before changing the property, we check if it was already mandatory. If not, we had the mandatory validator
+		if ($bMandatory && !$this->bMandatory)
+		{
+			$this->AddValidator(new NotEmptyExtKeyValidator());
+		}
+
+		if (!$bMandatory)
+		{
+			foreach ($this->aValidators as $iKey => $oValue)
+			{
+				if ($oValue::Getname() === NotEmptyExtKeyValidator::GetName())
+				{
+					unset($this->aValidators[$iKey]);
+				}
+			}
+		}
+
+		$this->bMandatory = $bMandatory;
+		return $this;
+	}
+
+	public function GetOqlQuery()
+	{
+		return $this->sOqlQuery;
+	}
+
+	public function GetMaximumComboLength()
+	{
+		return $this->iMaximumComboLength;
+	}
+
+	public function GetMinAutoCompleteChars()
+	{
+		return $this->iMinAutoCompleteChars;
+	}
+}

+ 0 - 22
sources/form/field/textfield.class.inc.php

@@ -29,26 +29,4 @@ use \Combodo\iTop\Form\Field\Field;
 abstract class TextField extends Field
 {
 
-	/**
-	 * Checks the validators to see if the field's current value is valid.
-	 * Then sets $bValid and $aErrorMessages.
-	 *
-	 * @return boolean
-	 */
-	public function Validate()
-	{
-		$this->SetValid(true);
-		$this->EmptyErrorMessages();
-		foreach ($this->GetValidators() as $oValidator)
-		{
-			if (!preg_match($oValidator->GetRegExp(true), $this->GetCurrentValue()))
-			{
-				$this->SetValid(false);
-				$this->AddErrorMessage($oValidator->GetErrorMessage());
-			}
-		}
-
-		return $this->GetValid();
-	}
-
 }

+ 38 - 7
sources/form/form.class.inc.php

@@ -397,16 +397,47 @@ class Form
 	}
 
 	/**
-	 *
+	 * Finalizes each field, following the dependencies so that a field can compute its value or other properties,
+	 * depending on other fields
 	 */
     public function Finalize()
     {
-        //TODO : Call GetOrderedFields
-        // Must call OnFinalize on each fields, regarding the dependencies order
-        // On a SubFormField, will call its own Finalize
-        foreach ($this->aFields as $sId => $oField)
-        {
-            $oField->OnFinalize();
+		$aFieldList = array(); // Fields ordered by dependence
+		// Clone the dependency data : $aDependencies will be truncated as the fields are added to the list
+		$aDependencies = $this->aDependencies;
+		$bMadeProgress = true; // Safety net in case of circular references
+		while ($bMadeProgress && count($aFieldList) < count($this->aFields))
+		{
+			$bMadeProgress = false;
+			foreach ($this->aFields as $sId => $oField)
+			{
+				if (array_key_exists($sId, $aFieldList)) continue;
+				if (isset($aDependencies[$sId]) && count($aDependencies[$sId]) > 0) continue;
+
+				// Add the field at the end of the list
+				$aFieldList[$sId] = $oField;
+				$bMadeProgress = true;
+
+				// Track that this dependency has been solved
+				foreach ($aDependencies as $sImpactedBy => $aSomeFields)
+				{
+					foreach ($aSomeFields as $i => $sSomeId)
+					{
+						if ($sSomeId == $sId)
+						{
+							unset($aDependencies[$sImpactedBy][$i]);
+						}
+					}
+				}
+			}
+		}
+		if (!$bMadeProgress)
+		{
+			throw new Exception('Unmet dependencies: '.implode(', ', array_keys($aDependencies)));
+		}
+		foreach ($aFieldList as $sId => $oField)
+		{
+			$oField->OnFinalize();
         }
     }
 

+ 1 - 1
sources/renderer/console/consoleformrenderer.class.inc.php

@@ -20,7 +20,6 @@ namespace Combodo\iTop\Renderer\Console;
 
 use Combodo\iTop\Form\Form;
 use Combodo\iTop\Renderer\FormRenderer;
-use Combodo\iTop\Renderer\RenderingOutput;
 use \Dict;
 
 require_once('fieldrenderer/consolesimplefieldrenderer.class.inc.php');
@@ -36,6 +35,7 @@ class ConsoleFormRenderer extends FormRenderer
 		$this->AddSupportedField('HiddenField', 'ConsoleSimpleFieldRenderer');
 		$this->AddSupportedField('StringField', 'ConsoleSimpleFieldRenderer');
 		$this->AddSupportedField('SelectField', 'ConsoleSimpleFieldRenderer');
+		$this->AddSupportedField('SelectObjectField', 'ConsoleSimpleFieldRenderer');
 		$this->AddSupportedField('SubFormField', 'ConsoleSubFormFieldRenderer');
 	}
 }

+ 42 - 0
sources/renderer/console/fieldrenderer/consolesimplefieldrenderer.class.inc.php

@@ -82,6 +82,46 @@ class ConsoleSimpleFieldRenderer extends FieldRenderer
 					$oOutput->AddHtml('<span class="form_validation"></span>');
 					$oOutput->AddHtml('</td>');
 					break;
+
+				case 'Combodo\\iTop\\Form\\Field\\SelectObjectField':
+					$oOutput->AddHtml('<td class="form-field-content">');
+					if ($this->oField->GetReadOnly())
+					{
+						$oSearch = \DBSearch::FromOQL($this->oField->GetOqlQuery());
+						$oSearch->AddCondition('id', $this->oField->GetCurrentValue());
+						$oSet = new DBObjectSet($oSearch);
+						$oObject = $oSet->Fetch();
+						if ($oObject)
+						{
+							$sCurrentLabel = $oObject->Get('friendlyname');
+						}
+						else
+						{
+							$sCurrentLabel = '';
+						}
+						$oOutput->AddHtml('<input type="hidden" id="'.$this->oField->GetGlobalId().'" value="' . htmlentities($this->oField->GetCurrentValue(), ENT_QUOTES, 'UTF-8') . '"/>');
+						$oOutput->AddHtml('<span class="form-field-data">'.htmlentities($sCurrentLabel, ENT_QUOTES, 'UTF-8').'</span>');
+					}
+					else
+					{
+						$oSearch = \DBSearch::FromOQL($this->oField->GetOqlQuery());
+						$oSet = new \DBObjectSet($oSearch);
+						$oSet->OptimizeColumnLoad(array($oSearch->GetClassAlias() => array('friendlyname')));
+						$oOutput->AddHtml('<select class="form-field-data" id="'.$this->oField->GetGlobalId().'">');
+						$oOutput->AddHtml('<option value="0">'.Dict::S('UI:SelectOne').'</option>');
+						while ($oObject = $oSet->Fetch())
+						{
+							$iObject = $oObject->GetKey();
+							$sLabel = $oObject->Get('friendlyname');
+							// Note : The test is a double equal on purpose as the type of the value received from the XHR is not always the same as the type of the allowed values. (eg : string vs int)
+							$sSelectedAtt = ($this->oField->GetCurrentValue() == $iObject) ? 'selected' : '';
+							$oOutput->AddHtml('<option value="'.$iObject.'" '.$sSelectedAtt.' >'.htmlentities($sLabel, ENT_QUOTES, 'UTF-8').'</option>');
+						}
+						$oOutput->AddHtml('</select>');
+					}
+					$oOutput->AddHtml('<span class="form_validation"></span>');
+					$oOutput->AddHtml('</td>');
+					break;
 			}
 			$oOutput->AddHtml('</tr>');
 			$oOutput->AddHtml('</table>');
@@ -106,6 +146,7 @@ EOF
 				);
 				break;
 			case 'Combodo\\iTop\\Form\\Field\\SelectField':
+			case 'Combodo\\iTop\\Form\\Field\\SelectObjectField':
 				$oOutput->AddJs(
 <<<EOF
                     $("#{$this->oField->GetGlobalId()}").off("change").on("change", function(){
@@ -169,6 +210,7 @@ EOF
 		switch ($sFieldClass)
 		{
 			case 'Combodo\\iTop\\Form\\Field\\SelectField':
+			case 'Combodo\\iTop\\Form\\Field\\SelectObjectField':
 				$oOutput->AddJs(
 					<<<EOF
 	                    $("[data-field-id='{$this->oField->GetId()}'][data-form-path='{$this->oField->GetFormPath()}']").form_field('option', 'get_current_value_callback', function(me){ return $(me.element).find('select').val();});