Foundations for the new form system

SVN:trunk[3889]
This commit is contained in:
Guillaume Lajarige
2016-01-28 10:37:32 +00:00
parent 3ecd768982
commit 1f4ca07b5f
22 changed files with 2204 additions and 0 deletions

42
sources/autoload.php Normal file
View File

@@ -0,0 +1,42 @@
<?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/>
/**
* This is a "manual autoloader" for now that is meant to evolve into a real autoloader.
*/
require_once APPROOT . 'sources/form/form.class.inc.php';
require_once APPROOT . 'sources/form/formmanager.class.inc.php';
require_once APPROOT . 'sources/form/field/field.class.inc.php';
require_once APPROOT . 'sources/form/field/textfield.class.inc.php';
require_once APPROOT . 'sources/form/field/hiddenfield.class.inc.php';
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/checkboxfield.class.inc.php';
require_once APPROOT . 'sources/form/field/radiofield.class.inc.php';
require_once APPROOT . 'sources/form/validator/validator.class.inc.php';
require_once APPROOT . 'sources/form/validator/mandatoryvalidator.class.inc.php';
require_once APPROOT . 'sources/form/validator/notemptyvalidator.class.inc.php';
require_once APPROOT . 'sources/form/validator/integervalidator.class.inc.php';
require_once APPROOT . 'sources/renderer/formrenderer.class.inc.php';
require_once APPROOT . 'sources/renderer/fieldrenderer.class.inc.php';
require_once APPROOT . 'sources/renderer/renderingoutput.class.inc.php';
require_once APPROOT . 'sources/renderer/bootstrap/bsformrenderer.class.inc.php';
require_once APPROOT . 'sources/renderer/bootstrap/fieldrenderer/bssimplefieldrenderer.class.inc.php';

View File

@@ -0,0 +1,33 @@
<?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 \Combodo\iTop\Form\Field\MultipleChoicesField;
/**
* Description of CheckboxField
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
*/
class CheckboxField extends MultipleChoicesField
{
const DEFAULT_MULTIPLE_VALUES_ENABLED = true;
}

View File

@@ -0,0 +1,250 @@
<?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\Validator;
use \Combodo\iTop\Form\Validator\MandatoryValidator;
/**
* Description of Field
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
*/
abstract class Field
{
const DEFAULT_LABEL = '';
const DEFAULT_READ_ONLY = false;
const DEFAULT_MANDATORY = false;
const DEFAULT_VALID = true;
protected $sId;
protected $sLabel;
protected $bReadOnly;
protected $bMandatory;
protected $aValidators;
protected $bValid;
protected $aErrorMessages;
protected $currentValue;
protected $onFinalizeCallback;
/**
*
* @param Closure $callback (Used in the $oForm->AddField($sId, ..., function() use ($oManager, $oForm, '...') { ... } ); )
*/
public function __construct($sId, Closure $onFinalizeCallback = null)
{
$this->sId = $sId;
$this->sLabel = static::DEFAULT_LABEL;
$this->bReadOnly = static::DEFAULT_READ_ONLY;
$this->bMandatory = static::DEFAULT_MANDATORY;
$this->aValidators = array();
$this->bValid = static::DEFAULT_VALID;
$this->aErrorMessages = array();
$this->onFinalizeCallback = $onFinalizeCallback;
}
public function GetId()
{
return $this->sId;
}
public function GetLabel()
{
return $this->sLabel;
}
public function GetReadOnly()
{
return $this->bReadOnly;
}
public function GetMandatory()
{
return $this->bMandatory;
}
public function GetValidators()
{
return $this->aValidators;
}
/**
* Returns the current validation state of the field (true|false).
* It DOESN'T make the validation, see Validate() instead.
*
* @return boolean
*/
public function GetValid()
{
return $this->bValid;
}
public function GetErrorMessages()
{
return $this->aErrorMessages;
}
public function GetCurrentValue()
{
return $this->currentValue;
}
public function SetLabel($sLabel)
{
$this->sLabel = $sLabel;
return $this;
}
public function SetReadOnly($bReadOnly)
{
$this->bReadOnly = $bReadOnly;
return $this;
}
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 MandatoryValidator());
}
if (!$bMandatory)
{
foreach ($this->aValidators as $iKey => $oValue)
{
if ($oValue::Getname() === MandatoryValidator::GetName())
{
unset($this->aValidators[$iKey]);
}
}
}
$this->bMandatory = $bMandatory;
return $this;
}
public function SetValidators($aValidators)
{
$this->aValidators = $aValidators;
return $this;
}
/**
* Note : Function is protected as bValid should not be set from outside
*
* @param boolean $bValid
* @return \Combodo\iTop\Form\Field\Field
*/
protected function SetValid($bValid)
{
$this->bValid = $bValid;
return $this;
}
/**
* Note : Function is protected as aErrorMessages should not be set from outside
*
* @param array $aErrorMessages
* @return \Combodo\iTop\Form\Field\Field
*/
protected function SetErrorMessages($aErrorMessages)
{
$this->aErrorMessages = $aErrorMessages;
return $this;
}
public function SetCurrentValue($currentValue)
{
$this->currentValue = $currentValue;
return $this;
}
public function SetOnFinalizeCallback(Closure $onFinalizeCallback)
{
$this->onFinalizeCallback = $onFinalizeCallback;
return $this;
}
public function AddValidator(Validator $oValidator)
{
$this->aValidators[] = $oValidator;
return $this;
}
public function RemoveValidator(Validator $oValidator)
{
foreach ($this->aValidators as $iKey => $oValue)
{
if ($oValue === $oValidator)
{
unset($this->aValidators[$iKey]);
}
}
return $this;
}
/**
* Note : Function is protected as aErrorMessages should not be add from outside
*
* @param string $sErrorMessage
* @return \Combodo\iTop\Field\Field
*/
protected function AddErrorMessage($sErrorMessage)
{
$this->aErrorMessages[] = $sErrorMessage;
return $this;
}
/**
* Note : Function is protected as aErrorMessages should not be set from outside
*
* @return \Combodo\iTop\Field\Field
*/
protected function EmptyErrorMessages()
{
$this->aErrorMessages = array();
return $this;
}
public function OnCancel()
{
// Overload when needed
}
public function OnFinalize()
{
if ($this->onFinalizeCallback !== null)
{
// Note : We MUST have a temp variable to call the Closure. otherwise it won't work when the Closure is a class member
$callback = $this->onFinalizeCallback;
$callback();
}
}
/**
* Checks the validators to see if the field's current value is valid.
* Then sets $bValid and $aErrorMessages.
*
* @return boolean
*/
abstract public function Validate();
}

View File

@@ -0,0 +1,32 @@
<?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 \Combodo\iTop\Form\Field\TextField;
/**
* Description of HiddenField
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
*/
class HiddenField extends TextField
{
}

View File

@@ -0,0 +1,177 @@
<?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\Field\Field;
/**
* Description of MultipleChoicesField
*
* Choices = Set of items that can be picked
* Values = Items that have been picked
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
*/
abstract class MultipleChoicesField extends Field
{
const DEFAULT_MULTIPLE_VALUES_ENABLED = false;
protected $bMultipleValuesEnabled;
protected $aChoices;
public function __construct($sId, Closure $onFinalizeCallback = null)
{
parent::__construct($sId, $onFinalizeCallback);
$this->bMultipleValuesEnabled = static::DEFAULT_MULTIPLE_VALUES_ENABLED;
$this->aChoices = array();
$this->currentValue = array();
}
public function GetCurrentValue()
{
$value = null;
if (!empty($this->currentValue))
{
if ($this->bMultipleValuesEnabled)
{
$value = $this->currentValue;
}
else
{
reset($this->currentValue);
$value = current($this->currentValue);
}
}
return $value;
}
/**
* Sets the current value for the MultipleChoicesField.
*
* @param mixed $currentValue Can be either an array of values (in case of multiple values) or just a simple value
* @return \Combodo\iTop\Form\Field\MultipleChoicesField
*/
public function SetCurrentValue($currentValue)
{
if (is_array($currentValue))
{
$this->currentValue = $currentValue;
}
elseif (is_null($currentValue))
{
$this->currentValue = array();
}
else
{
$this->currentValue = array($currentValue);
}
return $this;
}
public function GetMultipleValuesEnabled()
{
return $this->bMultipleValuesEnabled;
}
public function SetMultipleValuesEnabled($bMultipleValuesEnabled)
{
$this->bMultipleValuesEnabled = $bMultipleValuesEnabled;
return $this;
}
public function SetValues($aValues)
{
$this->currentValue = $aValues;
return $this;
}
public function AddValue($value)
{
$this->currentValue = $value;
return $this;
}
public function RemoveValue($value)
{
if (array_key_exists($value, $this->currentValue))
{
unset($this->currentValue[$sId]);
}
return $this;
}
public function IsAmongValues($value)
{
return in_array($value, $this->currentValue);
}
public function GetChoices()
{
return $this->aChoices;
}
public function SetChoices($aChoices)
{
$this->aChoices = $aChoices;
return $this;
}
public function AddChoice($sId, $choice = null)
{
if ($choice === null)
{
$choice = $sId;
}
$this->aChoices[$sId] = $choice;
return $this;
}
public function RemoveChoice($sId)
{
if (in_array($sId, $this->aChoices))
{
unset($this->aChoices[$sId]);
}
return $this;
}
public function Validate()
{
$this->SetValid(true);
$this->EmptyErrorMessages();
foreach ($this->GetValidators() as $oValidator)
{
foreach ($this->currentValue as $value)
{
if (!preg_match($oValidator->GetRegExp(true), $value))
{
$this->SetValid(false);
$this->AddErrorMessage($oValidator->GetErrorMessage());
}
}
}
return $this->GetValid();
}
}

View File

@@ -0,0 +1,33 @@
<?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 \Combodo\iTop\Form\Field\MultipleChoicesField;
/**
* Description of RadioField
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
*/
class RadioField extends MultipleChoicesField
{
const DEFAULT_MULTIPLE_VALUES_ENABLED = false;
}

View File

@@ -0,0 +1,84 @@
<?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\Field\MultipleChoicesField;
/**
* Description of SelectField
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
*/
class SelectField extends MultipleChoicesField
{
const DEFAULT_NULL_CHOICE_LABEL = 'TOTR: - Choisir une valeur -';
const DEFAULT_STARTS_WITH_NULL_CHOICE = true;
protected $bStartsWithNullChoice;
public function __construct($sId, Closure $onFinalizeCallback = null)
{
parent::__construct($sId, $onFinalizeCallback);
$this->bStartsWithNullChoice = static::DEFAULT_STARTS_WITH_NULL_CHOICE;
}
/**
* Returns if the select starts with a dummy choice before its choices.
* This can be useful when you want to force the user to explicitly select a choice.
*
* @return boolean
*/
public function GetStartsWithNullChoice()
{
return $this->bStartsWithNullChoice;
}
public function SetStartsWithNullChoice($bStartsWithNullChoice)
{
$this->bStartsWithNullChoice = $bStartsWithNullChoice;
if (!array_key_exists(null, $this->aChoices))
{
$this->aChoices = array(null => static::DEFAULT_NULL_CHOICE_LABEL) + $this->aChoices;
}
return $this;
}
/**
* Sets the choices for the fields
* Overloads the methods for the super class in order to put a dummy choice first if necessary.
*
* @param array $aChoices
* @return \Combodo\iTop\Form\Field\SelectField
*/
public function SetChoices($aChoices)
{
if ($this->bStartsWithNullChoice && !array_key_exists(null, $aChoices))
{
$aChoices = array(null => static::DEFAULT_NULL_CHOICE_LABEL) + $aChoices;
}
parent::SetChoices($aChoices);
return $this;
}
}

View File

@@ -0,0 +1,32 @@
<?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 \Combodo\iTop\Form\Field\TextField;
/**
* Description of StringField
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
*/
class StringField extends TextField
{
}

View File

@@ -0,0 +1,32 @@
<?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 \Combodo\iTop\Form\Field\TextField;
/**
* Description of TextAreaField
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
*/
class TextAreaField extends TextField
{
}

View File

@@ -0,0 +1,54 @@
<?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 \Combodo\iTop\Form\Field\Field;
/**
* Description of TextField
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
*/
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();
}
}

View File

@@ -0,0 +1,277 @@
<?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;
use \Exception;
use \Dict;
use \Combodo\iTop\Form\Field\Field;
/**
* Description of Form
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
*/
class Form
{
protected $sId;
protected $aFields;
protected $aDependencies;
protected $bValid;
protected $aErrorMessages;
public function __construct($sId)
{
$this->sId = $sId;
$this->aFields = array();
$this->aDependencies = array();
$this->bValid = true;
$this->aErrorMessages = array();
}
public function GetId()
{
return $this->sId;
}
public function GetFields()
{
return $this->aFields;
}
public function GetDependencies()
{
return $this->aDependencies;
}
/**
* Returns the current validation state of the form (true|false).
* It DOESN'T make the validation, see Validate() instead.
*
* @return boolean
*/
public function GetValid()
{
return $this->bValid;
}
/**
* Note : Function is protected as bValid should not be set from outside
*
* @param boolean $bValid
* @return \Combodo\iTop\Form\Form
*/
protected function SetValid($bValid)
{
$this->bValid = $bValid;
return $this;
}
public function GetErrorMessages()
{
return $this->aErrorMessages;
}
/**
* Note : Function is protected as aErrorMessages should not be set from outside
*
* @param array $aErrorMessages
* @param string $sFieldId
* @return \Combodo\iTop\Form\Form
*/
protected function SetErrorMessages($aErrorMessages, $sFieldId = null)
{
if ($sFieldId === null)
{
$this->aErrorMessages = $aErrorMessages;
}
else
{
$this->aErrorMessages[$sFieldId] = $aErrorMessages;
}
return $this;
}
/**
* If $sFieldId is not set, the $sErrorMessage will be added to the general form messages
*
* Note : Function is protected as aErrorMessages should not be add from outside
*
* @param string $sErrorMessage
* @param string $sFieldId
* @return \Combodo\iTop\Form\Form
*/
protected function AddErrorMessage($sErrorMessage, $sFieldId = '_main')
{
if (!isset($this->aErrorMessages[$sFieldId]))
{
$this->aErrorMessages[$sFieldId] = array();
}
$this->aErrorMessages[$sFieldId][] = $sErrorMessage;
return $this;
}
/**
* Note : Function is protected as aErrorMessages should not be set from outside
*
* @return \Combodo\iTop\Form\Form
*/
protected function EmptyErrorMessages()
{
$this->aErrorMessages = array();
return $this;
}
public function GetField($sId)
{
if (!array_key_exists($sId, $this->aFields))
{
throw new Exception('Field with ID "' . $sId . '" was not found in the Form.');
}
return $this->aFields[$sId];
}
public function HasField($sId)
{
return array_key_exists($sId, $this->aFields);
}
public function AddField(Field $oField, $aDependsOnIds = array())
{
$this->aFields[$oField->GetId()] = $oField;
return $this;
}
public function RemoveField($sId)
{
if (array_key_exists($sId, $this->aFields))
{
unset($this->aFields[$sId]);
}
return $this;
}
/**
* Returns a array (list) of the fields ordered by their dependencies.
*
* @return array
*/
public function GetOrderedFields()
{
// TODO : Do this so it flatten the array
return $this->aFields;
}
/**
* Returns an array of field ids the $sFieldId depends on.
*
* @param string $sFieldId
* @return array
* @throws Exception
*/
public function GetFieldDependencies($sFieldId)
{
if (!array_key_exists($sFieldId, $this->aDependencies))
{
throw new Exception('Field with ID "' . $sFieldId . '" had no dependancies declared in the Form.');
}
return $this->aDependencies[$sFieldId];
}
public function AddFieldDependencies($sFieldId, array $aDependsOnIds)
{
foreach ($aDependsOnIds as $sDependsOnId)
{
$this->AddFieldDependency($sFieldId, $sDependsOnId);
}
return $this;
}
public function AddFieldDependency($sFieldId, $sDependsOnId)
{
if (!array_key_exists($sFieldId, $this->aDependencies))
{
$this->aDependencies[$sFieldId] = array();
}
$this->aDependencies[$sFieldId][] = $sDependsOnId;
return $this;
}
/**
* Returns a hash array of the fields impacts on other fields. Key being the field that impacts the fields stored in the value as a regular array
* (It kind of reversed the dependencies array)
*
* eg :
* - 'service' => array('subservice', 'template')
* - 'subservice' => array()
* - ...
*
* @return array
*/
public function GetFieldsImpacts()
{
$aRes = array();
foreach ($this->aDependencies as $sImpactedFieldId => $aDependentFieldsIds)
{
foreach ($aDependentFieldsIds as $sDependentFieldId)
{
if (!array_key_exists($sDependentFieldId, $aRes))
{
$aRes[$sDependentFieldId] = array();
}
$aRes[$sDependentFieldId][] = $sImpactedFieldId;
}
}
return $aRes;
}
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();
}
}
public function Validate()
{
$this->SetValid(true);
$this->EmptyErrorMessages();
foreach ($this->aFields as $oField)
{
if (!$oField->Validate())
{
$this->SetValid(false);
foreach ($oField->GetErrorMessages() as $sErrorMessage)
{
$this->AddErrorMessage(Dict::S($sErrorMessage), $oField->Getid());
}
}
}
return $this->GetValid();
}
}

View File

@@ -0,0 +1,94 @@
<?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;
use \Combodo\iTop\Form\Form;
use \Combodo\iTop\Renderer\FormRenderer;
/**
* Description of formmanager
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
*/
abstract class FormManager
{
protected $oForm;
protected $oRenderer;
static function FromJSON($sJson)
{
// Overload in child class when needed
$aJson = json_decode($sJson, true);
$oFormManager = new static();
$sFormRendererClass = $aJson['formrenderer_class'];
$oFormRenderer = new $sFormRendererClass();
$oFormRenderer->SetEndpoint($aJson['formrenderer_endpoint']);
$oFormManager->SetRenderer($oFormRenderer);
return $oFormManager;
}
public function __construct()
{
// Overload in child class when needed
}
public function GetForm()
{
return $this->oForm;
}
public function GetRenderer()
{
return $this->oRenderer;
}
public function SetRenderer(FormRenderer $oRenderer)
{
$this->oRenderer = $oRenderer;
return $this;
}
public function GetClass()
{
return get_class($this);
}
public function ToJSON()
{
// Overload in child class when needed
return array(
'id' => $this->oForm->GetId(),
'formmanager_class' => $this->GetClass(),
'formrenderer_class' => get_class($this->GetRenderer()),
'formrenderer_endpoint' => $this->GetRenderer()->GetEndpoint()
);
}
abstract public function Build();
abstract public function OnUpdate($aArgs = null);
abstract public function OnSubmit($aArgs = null);
abstract public function OnCancel($aArgs = null);
}

View File

@@ -0,0 +1,35 @@
<?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\Validator;
use \Combodo\iTop\Form\Validator\Validator;
/**
* Description of IntegerValidator
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
*/
class IntegerValidator extends Validator
{
const VALIDATOR_NAME = 'integer';
const DEFAULT_REGEXP = '^[0-9]+$';
const DEFAULT_ERROR_MESSAGE = 'TOTR: MUST NOT BE AN INTEGER MESSAGE';
}

View File

@@ -0,0 +1,37 @@
<?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\Validator;
use \Combodo\iTop\Form\Validator\Validator;
/**
* Description of MandatoryValidator
*
* MandatoryValidator is different than NotEmptyValidator as it doesn't apply to text input only
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
*/
class MandatoryValidator extends Validator
{
const VALIDATOR_NAME = 'mandatory';
const DEFAULT_REGEXP = '.*\S.*';
const DEFAULT_ERROR_MESSAGE = 'TOTR: MANDATORY MESSAGE';
}

View File

@@ -0,0 +1,35 @@
<?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\Validator;
use \Combodo\iTop\Form\Validator\Validator;
/**
* Description of NotEmptyExtKeyValidator
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
*/
class NotEmptyExtKeyValidator extends Validator
{
const VALIDATOR_NAME = 'notemptyextkey';
const DEFAULT_REGEXP = '^[1-9]+$';
const DEFAULT_ERROR_MESSAGE = 'TOTR: MUST SELECT ONE';
}

View File

@@ -0,0 +1,35 @@
<?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\Validator;
use \Combodo\iTop\Form\Validator\Validator;
/**
* Description of NotEmptyValidator
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
*/
class NotEmptyValidator extends Validator
{
const VALIDATOR_NAME = 'notempty';
const DEFAULT_REGEXP = '.*\S.*';
const DEFAULT_ERROR_MESSAGE = 'TOTR: MUST NOT BE EMPTY MESSAGE';
}

View File

@@ -0,0 +1,108 @@
<?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\Validator;
/**
* Description of Validator
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
*/
class Validator
{
const VALIDATOR_NAME = 'expression';
const DEFAULT_REGEXP = '';
const DEFAULT_ERROR_MESSAGE = 'TOTR: Core:Validator:Default';
protected $sRegExp;
protected $sErrorMessage;
public static function GetName()
{
return static::VALIDATOR_NAME;
}
/**
*
* @param Closure $callback (Used in the $oForm->AddField($sId, ..., function() use ($oManager, $oForm, '...') { ... } ); )
*/
public function __construct($sRegExp = null, $sErrorMessage = null)
{
$this->sRegExp = ($sRegExp === null) ? static::DEFAULT_REGEXP : $sRegExp;
$this->sErrorMessage = ($sErrorMessage === null) ? static::DEFAULT_ERROR_MESSAGE : $sErrorMessage;
$this->ComputeConstraints();
}
/**
* Returns the regular expression of the validator.
*
* @param boolean $bWithSlashes If true, surrounds $sRegExp with '/'. Used with preg_match & co
* @return string
*/
public function GetRegExp($bWithSlashes = false)
{
return ($bWithSlashes) ? '/' . $this->sRegExp . '/' : $this->sRegExp;
}
public function GetErrorMessage()
{
return $this->sErrorMessage;
}
public function SetRegExp($sRegExp)
{
$this->sRegExp = $sRegExp;
$this->ComputeConstraints();
return $this;
}
public function SetErrorMessage($sErrorMessage)
{
$this->sErrorMessage = $sErrorMessage;
$this->ComputeConstraints();
return $this;
}
/**
* Computes the regular expression and error message when changing constraints on the validator.
* Should be called in the validator's setters.
*/
public function ComputeConstraints()
{
$this->ComputeRegularExpression();
$this->ComputeErrorMessage();
}
/**
* Computes the regular expression when changing constraints on the validator.
*/
public function ComputeRegularExpression()
{
// Overload when necessary
}
/**
* Computes the error message when changing constraints on the validator.
*/
public function ComputeErrorMessage()
{
// Overload when necessary
}
}

View File

@@ -0,0 +1,232 @@
<?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\Renderer\Bootstrap;
use \Dict;
use \MetaModel;
use \Combodo\iTop\Renderer\FormRenderer;
use \Combodo\iTop\Form\Form;
/**
* Description of formrenderer
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
*/
class BsFormRenderer extends FormRenderer
{
const ENUM_RENDER_MODE_EXPLODED = 'exploded';
const ENUM_RENDER_MODE_JOINED = 'joined';
public function __construct(Form $oForm = null)
{
parent::__construct($oForm);
$this->AddSupportedField('HiddenField', 'BsSimpleFieldRenderer');
$this->AddSupportedField('StringField', 'BsSimpleFieldRenderer');
$this->AddSupportedField('TextAreaField', 'BsSimpleFieldRenderer');
$this->AddSupportedField('SelectField', 'BsSimpleFieldRenderer');
$this->AddSupportedField('RadioField', 'BsSimpleFieldRenderer');
$this->AddSupportedField('CheckboxField', 'BsSimpleFieldRenderer');
}
/**
* Registers a Renderer class for the specified Field class.
*
* If the Field class is not fully qualified, a default namespace will be prepend (see FormRenderer::AddSupportedField).
* If the Renderer clas is not fully qualified, the default "Combodo\iTop\Renderer\Bootstrap\FieldRenderer" will be prepend.
*
* @param string $sFieldClass
* @param string $sRendererClass
*/
public function AddSupportedField($sFieldClass, $sRendererClass)
{
$sRendererClass = (strpos($sRendererClass, '\\') !== false) ? $sRendererClass : 'Combodo\\iTop\\Renderer\\Bootstrap\\FieldRenderer\\' . $sRendererClass;
parent::AddSupportedField($sFieldClass, $sRendererClass);
}
public function Render()
{
$this->InitOutputs();
foreach ($this->oForm->GetFields() as $oField)
{
$this->aOutputs[] = $this->PrepareOutputForField($oField);
}
return $this->aOutputs;
}
/**
* Renders a field of $oObject identified by its attribute code ($sFieldId).
*
* $sMode allows to defined if the result must a traditional array
* containing the differents parts for the field or a string concataning all
* those parts in one html tag.
*
* Typically, $sMode 'joined' is used when RenderField is called directly from a twig template.
* Otherwise, the 'exploded' parameter is used to allow the renderer to optimize the assets.
*
* $iDesiredFlags is only used with $sMode = 'joined' to set the field flags as an information.
*
* @param cmdbAbstractObject $oObject
* @param string $sFieldId
* @param integer $iDesiredFlags
* @param string $sMode 'joined'|'exploded'
* @return mixed
*/
public function RenderField($oObject, $sFieldId, $iDesiredFlags = OPT_ATT_NORMAL, $sMode = 'joined')
{
// Building field
$oAttDef = MetaModel::GetAttributeDef(get_class($oObject), $sFieldId);
$oField = $oAttDef->GetFormField($oObject);
$aOutput = $this->PrepareOutputForField($oField, $sMode);
if ($sMode === static::ENUM_RENDER_MODE_JOINED)
{
$res = '<div class="form_field" data-field-id="' . $oField->GetId() . '" data-field-flags="' . $iDesiredFlags . '">' .
$aOutput['html'] .
'</div>';
}
else
{
$res = $aOutput;
}
return $res;
}
/**
* Returns the output for the $oField. Output format depends on the $sMode.
*
* If $sMode = 'exploded', output is an has array with id / html / js_inline / js_files / css_inline / css_files / validators
* Else if $sMode = 'joined', output is a string with everything in it
*
* @param Combodo\iTop\Form\Field\Field $oField
* @param string $sMode 'exploded'|'joined'
* @return mixed
*/
protected function PrepareOutputForField($oField, $sMode = 'exploded')
{
$output = array(
'id' => $oField->GetId(),
'html' => '',
'js_inline' => '',
'css_inline' => '',
'js_files' => array(),
'css_files' => array(),
'validators' => null
);
$sFieldRendererClass = $this->GetFieldRendererClass($oField);
// TODO : We might want to throw an exception instead when there is no renderer for that field
if ($sFieldRendererClass !== null)
{
$oFieldRenderer = new $sFieldRendererClass($oField);
$oFieldRenderer->SetEndpoint($this->GetEndpoint());
$oRenderingOutput = $oFieldRenderer->Render();
// HTML
if ($oRenderingOutput->GetHtml() !== '')
{
if ($sMode === static::ENUM_RENDER_MODE_EXPLODED)
{
$output['html'] = $oRenderingOutput->GetHtml();
}
else
{
$output['html'] .= $oRenderingOutput->GetHtml();
}
}
// JS files
foreach ($oRenderingOutput->GetJsFiles() as $sJsFile)
{
if ($sMode === static::ENUM_RENDER_MODE_EXPLODED)
{
if (!in_array($sJsFile, $output['js_files']))
{
$output['js_files'][] = $sJsFile;
}
}
else
{
$output['html'] .= '<script src="' . $sJsFile . '" type="text/javascript"></script>';
}
}
// JS inline
if ($oRenderingOutput->GetJs() !== '')
{
if ($sMode === static::ENUM_RENDER_MODE_EXPLODED)
{
$output['js_inline'] .= ' ' . $oRenderingOutput->GetJs();
}
else
{
$output['html'] .= '<script type="text/javascript">' . $oRenderingOutput->GetJs() . '</script>';
}
}
// CSS files
foreach ($oRenderingOutput->GetCssFiles() as $sCssFile)
{
if ($sMode === static::ENUM_RENDER_MODE_EXPLODED)
{
if (!in_array($sCssFile, $output['css_files']))
{
$output['css_files'][] = $sCssFile;
}
}
else
{
$output['html'] .= '<link href="' . $sCssFile . '" rel="stylesheet" />';
}
}
// CSS inline
if ($oRenderingOutput->GetCss() !== '')
{
if ($sMode === static::ENUM_RENDER_MODE_EXPLODED)
{
$output['css_inline'] .= ' ' . $oRenderingOutput->GetCss();
}
else
{
$output['html'] .= '<style>' . $oRenderingOutput->GetCss() . '</style>';
}
}
// Validators
foreach ($oField->GetValidators() as $oValidator)
{
$output['validators'][$oValidator::GetName()] = array(
'reg_exp' => $oValidator->GetRegExp(),
'message' => Dict::S($oValidator->GetErrorMessage())
);
}
// Subfields
// TODO
}
return $output;
}
}

View File

@@ -0,0 +1,201 @@
<?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\Renderer\Bootstrap\FieldRenderer;
use \Dict;
use \Combodo\iTop\Renderer\FieldRenderer;
use \Combodo\iTop\Renderer\RenderingOutput;
/**
* Description of BsSimpleFieldRenderer
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
*/
class BsSimpleFieldRenderer extends FieldRenderer
{
public function Render()
{
$oOutput = new RenderingOutput();
$sFieldClass = get_class($this->oField);
$sFieldId = 'field_' . spl_object_hash($this->oField);
$sFieldMandatoryClass = ($this->oField->GetMandatory()) ? 'form_mandatory' : '';
// TODO : Shouldn't we have a field type so we don't have to maintain FQN classname ?
// Rendering field in edition mode
if (!$this->oField->GetReadOnly())
{
switch ($sFieldClass)
{
case 'Combodo\\iTop\\Form\\Field\\StringField':
$oOutput->AddHtml('<div class="form-group ' . $sFieldMandatoryClass . '">');
if ($this->oField->GetLabel() !== '')
{
$oOutput->AddHtml('<label for="' . $sFieldId . '" class="control-label">' . $this->oField->GetLabel() . '</label>');
}
$oOutput->AddHtml('<div class="help-block"></div>');
$oOutput->AddHtml('<input type="text" id="' . $sFieldId . '" name="' . $this->oField->GetId() . '" value="' . $this->oField->GetCurrentValue() . '" class="form-control" />');
$oOutput->AddHtml('</div>');
break;
case 'Combodo\\iTop\\Form\\Field\\TextAreaField':
$oOutput->AddHtml('<div class="form-group ' . $sFieldMandatoryClass . '">');
if ($this->oField->GetLabel() !== '')
{
$oOutput->AddHtml('<label for="' . $sFieldId . '" class="control-label">' . $this->oField->GetLabel() . '</label>');
}
$oOutput->AddHtml('<div class="help-block"></div>');
$oOutput->AddHtml('<textarea id="' . $sFieldId . '" name="' . $this->oField->GetId() . '" class="form-control" rows="8">' . $this->oField->GetCurrentValue() . '</textarea>');
$oOutput->AddHtml('</div>');
break;
case 'Combodo\\iTop\\Form\\Field\\SelectField':
$oOutput->AddHtml('<div class="form-group ' . $sFieldMandatoryClass . '">');
if ($this->oField->GetLabel() !== '')
{
$oOutput->AddHtml('<label for="' . $sFieldId . '" class="control-label">' . $this->oField->GetLabel() . '</label>');
}
$oOutput->AddHtml('<div class="help-block"></div>');
$oOutput->AddHtml('<select id="' . $sFieldId . '" name="' . $this->oField->GetId() . '" ' . ( ($this->oField->GetMultipleValuesEnabled()) ? 'multiple' : '' ) . ' class="form-control">');
foreach ($this->oField->GetChoices() as $sChoice => $sLabel)
{
// 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() == $sChoice) ? 'selected' : '';
$oOutput->AddHtml('<option value="' . $sChoice . '" ' . $sSelectedAtt . ' >' . $sLabel . '</option>');
}
$oOutput->AddHtml('</select>');
$oOutput->AddHtml('</div>');
break;
case 'Combodo\\iTop\\Form\\Field\\RadioField':
case 'Combodo\\iTop\\Form\\Field\\CheckboxField':
$sFieldType = ($sFieldClass === 'Combodo\\iTop\\Form\\Field\\RadioField') ? 'radio' : 'checkbox';
$oOutput->AddHtml('<div class="form-group ' . $sFieldMandatoryClass . '" id="' . $sFieldId . '">');
if ($this->oField->GetLabel() !== '')
{
$oOutput->AddHtml('<div><label class="control-label">' . $this->oField->GetLabel() . '</label></div>');
}
$oOutput->AddHtml('<div class="help-block"></div>');
$oOutput->AddHtml('<div class="btn-group" data-toggle="buttons">');
$i = 0;
foreach ($this->oField->GetChoices() as $sChoice => $sLabel)
{
// 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)
$sCheckedAtt = ($this->oField->IsAmongValues($sChoice)) ? 'checked' : '';
$sCheckedClass = ($this->oField->IsAmongValues($sChoice)) ? 'active' : '';
$oOutput->AddHtml('<label class="btn btn-default ' . $sCheckedClass . '"><input type="' . $sFieldType . '" name="' . $this->oField->GetId() . '" id="' . $this->oField->GetId() . $i . '" value="' . $sChoice . '" ' . $sCheckedAtt . ' />' . $sLabel . '</label>');
$i++;
}
$oOutput->AddHtml('</div>');
$oOutput->AddHtml('</div>');
break;
case 'Combodo\\iTop\\Form\\Field\\HiddenField':
$oOutput->AddHtml('<input type="hidden" id="' . $sFieldId . '" name="' . $this->oField->GetId() . '" value="' . $this->oField->GetCurrentValue() . '"/>');
break;
}
}
// ... and in read-only mode
else
{
// ... specific rendering for fields with mulltiple values
if (($this->oField instanceof Combodo\iTop\Form\Field\MultipleChoicesField) && ($this->oField->GetMultipleValuesEnabled()))
{
// TODO
}
// ... clasic rendering for fields with only one value
else
{
switch ($sFieldClass)
{
case 'Combodo\\iTop\\Form\\Field\\StringField':
case 'Combodo\\iTop\\Form\\Field\\TextAreaField':
$oOutput->AddHtml('<div class="form-group">');
if ($this->oField->GetLabel() !== '')
{
$oOutput->AddHtml('<label for="' . $sFieldId . '" class="control-label">' . $this->oField->GetLabel() . '</label>');
}
$oOutput->AddHtml('<div class="form-control-static">' . $this->oField->GetCurrentValue() . '</div>');
$oOutput->AddHtml('<input type="hidden" id="' . $sFieldId . '" name="' . $this->oField->GetId() . '" value="' . $this->oField->GetCurrentValue() . '" class="form-control" />');
$oOutput->AddHtml('</div>');
break;
case 'Combodo\\iTop\\Form\\Field\\RadioField':
case 'Combodo\\iTop\\Form\\Field\\SelectField': // TODO : This should be check for external key, as we would display it differently
$aFieldChoices = $this->oField->GetChoices();
$sFieldValue = (isset($aFieldChoices[$this->oField->GetCurrentValue()])) ? $aFieldChoices[$this->oField->GetCurrentValue()] : Dict::S('UI:UndefinedObject');
$oOutput->AddHtml('<div class="form-group">');
if ($this->oField->GetLabel() !== '')
{
$oOutput->AddHtml('<label for="' . $sFieldId . '" class="control-label">' . $this->oField->GetLabel() . '</label>');
}
$oOutput->AddHtml('<div class="form-control-static">' . $sFieldValue . '</div>');
$oOutput->AddHtml('<input type="hidden" id="' . $sFieldId . '" name="' . $this->oField->GetId() . '" value="' . $this->oField->GetCurrentValue() . '" class="form-control" />');
$oOutput->AddHtml('</div>');
break;
}
}
}
// JS FieldChange trigger (:input are not always at the same depth)
switch ($sFieldClass)
{
case 'Combodo\\iTop\\Form\\Field\\StringField':
case 'Combodo\\iTop\\Form\\Field\\TextAreaField':
case 'Combodo\\iTop\\Form\\Field\\SelectField':
case 'Combodo\\iTop\\Form\\Field\\HiddenField':
$oOutput->AddJs(
<<<EOF
$("#$sFieldId").off("change").on("change", function(){
$(this).closest(".form_handler").trigger("field_change", {
id: $(this).attr("id"),
name: $(this).attr("name"),
value: $(this).val()
});
});
EOF
);
break;
case 'Combodo\\iTop\\Form\\Field\\RadioField':
case 'Combodo\\iTop\\Form\\Field\\CheckboxField':
$oOutput->AddJs(
<<<EOF
$("#$sFieldId input").off("change").on("change", function(){
$(this).closest(".form_handler").trigger("field_change", {
id: $(this).closest("#$sFieldId").attr("id"),
name: $(this).attr("name"),
value: $(this).val()
});
});
EOF
);
break;
}
return $oOutput;
}
}

View File

@@ -0,0 +1,60 @@
<?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\Renderer;
use \Combodo\iTop\Form\Field\Field;
/**
* Description of FieldRenderer
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
*/
abstract class FieldRenderer
{
protected $oField;
protected $sEndpoint;
/**
* Default constructor
*
* @param \Combodo\iTop\Form\Field\Field $oField
*/
public function __construct(Field $oField)
{
$this->oField = $oField;
}
public function GetEndpoint()
{
return $this->sEndpoint;
}
public function SetEndpoint($sEndpoint)
{
$this->sEndpoint = $sEndpoint;
}
/**
* Renders a Field as a RenderingOutput
*
* @return \Combodo\iTop\Renderer\RenderingOutput
*/
abstract public function Render();
}

View File

@@ -0,0 +1,143 @@
<?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\Renderer;
use \Combodo\iTop\Form\Form;
/**
* Description of FormRenderer
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
*/
abstract class FormRenderer
{
protected $oForm;
protected $sEndpoint;
protected $aSupportedFields;
protected $sBaseLayout;
protected $aOutputs;
/**
* Default constructor
*
* @param \Combodo\iTop\Form\Form $oForm
*/
public function __construct(Form $oForm = null)
{
if ($oForm !== null)
{
$this->oForm = $oForm;
}
$this->sBaseLayout = '';
$this->InitOutputs();
}
public function GetForm()
{
return $this->oForm;
}
public function SetForm($oForm)
{
$this->oForm = $oForm;
return $this;
}
public function GetEndpoint()
{
return $this->sEndpoint;
}
public function SetEndpoint($sEndpoint)
{
$this->sEndpoint = $sEndpoint;
return $this;
}
public function GetBaseLayout()
{
return $this->sBaseLayout;
}
public function SetBaseLayout($sBaseLayout)
{
$this->sBaseLayout = $sBaseLayout;
return $this;
}
public function GetFieldRendererClass($oField)
{
if (array_key_exists(get_class($oField), $this->aSupportedFields))
{
return $this->aSupportedFields[get_class($oField)];
}
else
{
// TODO : We might want to throw an exception.
return null;
}
}
/**
* Returns the field identified by the id $sId in $this->oForm.
*
* @param string $sId
* @return Combodo\iTop\Renderer\FieldRenderer
*/
public function GetFieldRendererClassFromId($sId)
{
return $this->GetFieldRendererClass($this->oForm->GetField($sId));
}
/**
*
* @return array
*/
public function GetOutputs()
{
return $this->aOutputs;
}
/**
* Registers a Renderer class for the specified Field class.
*
* If the Field class is not fully qualified, the default "Combodo\iTop\Form\Field" will be prepend.
* If the Field class already had a registered Renderer, it is replaced.
*
* @param string $sFieldClass
* @param string $sRendererClass
*/
public function AddSupportedField($sFieldClass, $sRendererClass)
{
$sFieldClass = (strpos($sFieldClass, '\\') !== false) ? $sFieldClass : 'Combodo\\iTop\\Form\\Field\\' . $sFieldClass;
$this->aSupportedFields[$sFieldClass] = $sRendererClass;
return $this;
}
public function InitOutputs()
{
$this->aOutputs = array();
return $this;
}
abstract public function Render();
}

View File

@@ -0,0 +1,178 @@
<?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\Renderer;
/**
* Description of RenderingOutput
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
*/
class RenderingOutput
{
protected $sHtml;
protected $sJsInline;
protected $aJsFiles;
protected $sCssInline;
protected $aCssFiles;
public function __construct()
{
$this->sHtml = '';
$this->sJsInline = '';
$this->aJsFiles = array();
$this->sCssInline = '';
$this->aCssFiles = array();
}
/**
*
* @return string
*/
public function GetHtml()
{
return $this->sHtml;
}
/**
*
* @return string
*/
public function GetJs()
{
return $this->sJsInline;
}
/**
*
* @return array
*/
public function GetJsFiles()
{
return $this->aJsFiles;
}
/**
*
* @return string
*/
public function GetCss()
{
return $this->sCssInline;
}
/**
*
* @return array
*/
public function GetCssFiles()
{
return $this->aCssFiles;
}
/**
*
* @param string $sHtml
* @return \Combodo\iTop\Renderer\RenderingOutput
*/
public function AddHtml($sHtml)
{
$this->sHtml .= $sHtml;
return $this;
}
/**
*
* @param string $sJs
* @return \Combodo\iTop\Renderer\RenderingOutput
*/
public function AddJs($sJs)
{
$this->sJsInline .= $sJs . "\n";
return $this;
}
/**
*
* @param string $sFile
* @return \Combodo\iTop\Renderer\RenderingOutput
*/
public function AddJsFile($sFile)
{
if (!in_array($sFile, $this->aJsFiles))
{
$this->aJsFiles[] = $sFile;
}
return $this;
}
/**
*
* @param string $sFile
* @return \Combodo\iTop\Renderer\RenderingOutput
*/
public function RemoveJsFile($sFile)
{
if (in_array($sFile, $this->aJsFiles))
{
unset($this->aJsFiles[$sFile]);
}
return $this;
}
/**
*
* @param string $sCss
* @return \Combodo\iTop\Renderer\RenderingOutput
*/
public function AddCss($sCss)
{
$this->sCssInline .= $sCss . "\n";
return $this;
}
/**
*
* @param string $sFile
* @return \Combodo\iTop\Renderer\RenderingOutput
*/
public function AddCssFile($sFile)
{
if (!in_array($sFile, $this->aCssFiles))
{
$this->aCssFiles[] = $sFile;
}
return $this;
}
/**
*
* @param string $sFile
* @return \Combodo\iTop\Renderer\RenderingOutput
*/
public function RemoveCssFile($sFile)
{
if (in_array($sFile, $this->aCssFiles))
{
unset($this->aCssFiles[$sFile]);
}
return $this;
}
}