diff --git a/application/applicationextension.inc.php b/application/applicationextension.inc.php
index 022ef6684..ea265766e 100644
--- a/application/applicationextension.inc.php
+++ b/application/applicationextension.inc.php
@@ -18,11 +18,6 @@
* You should have received a copy of the GNU Affero General Public License
*/
-use Combodo\iTop\Application\UI\Base\iUIBlock;
-use Combodo\iTop\Application\WebPage\iTopWebPage;
-use Combodo\iTop\Application\WebPage\WebPage;
-use Symfony\Component\DependencyInjection\Container;
-
require_once(APPROOT.'application/newsroomprovider.class.inc.php');
/**
@@ -35,2281 +30,57 @@ require_once(APPROOT.'application/newsroomprovider.class.inc.php');
* @license http://opensource.org/licenses/AGPL-3.0
* @since 2.7.0
*/
+require_once(APPROOT.'application/applicationextension/backoffice/iApplicationUIExtension.php');
+require_once(APPROOT.'application/applicationextension/backoffice/iBackofficeDictEntriesExtension.php');
+require_once(APPROOT.'application/applicationextension/backoffice/iBackofficeDictEntriesPrefixesExtension.php');
+require_once(APPROOT.'application/applicationextension/backoffice/iBackofficeEarlyScriptExtension.php');
+require_once(APPROOT.'application/applicationextension/backoffice/iBackofficeInitScriptExtension.php');
+require_once(APPROOT.'application/applicationextension/backoffice/iBackofficeLinkedScriptsExtension.php');
+require_once(APPROOT.'application/applicationextension/backoffice/iBackofficeLinkedStylesheetsExtension.php');
+require_once(APPROOT.'application/applicationextension/backoffice/iBackofficeReadyScriptExtension.php');
+require_once(APPROOT.'application/applicationextension/backoffice/iBackofficeSassExtension.php');
+require_once(APPROOT.'application/applicationextension/backoffice/iBackofficeScriptExtension.php');
+require_once(APPROOT.'application/applicationextension/backoffice/iBackofficeStyleExtension.php');
+require_once(APPROOT.'application/applicationextension/backoffice/iFieldRendererMappingsExtension.php');
+require_once(APPROOT.'application/applicationextension/backoffice/iPageUIBlockExtension.php');
+require_once(APPROOT.'application/applicationextension/backoffice/iPopupMenuExtension.php');
+require_once(APPROOT.'application/applicationextension/backoffice/iPreferencesExtension.php');
+require_once(APPROOT.'application/applicationextension/backoffice/iWelcomePopupExtension.php');
+require_once(APPROOT.'application/applicationextension/backoffice/AbstractApplicationUIExtension.php');
+require_once(APPROOT.'application/applicationextension/backoffice/AbstractPageUIBlockExtension.php');
+require_once(APPROOT.'application/applicationextension/backoffice/AbstractPreferencesExtension.php');
+require_once(APPROOT.'application/applicationextension/backoffice/AbstractWelcomePopupExtension.php');
+require_once(APPROOT.'application/applicationextension/backoffice/ApplicationPopupMenuItem.php');
+require_once(APPROOT.'application/applicationextension/backoffice/JSButtonItem.php');
+require_once(APPROOT.'application/applicationextension/backoffice/JSPopupMenuItem.php');
+require_once(APPROOT.'application/applicationextension/backoffice/SeparatorPopupMenuItem.php');
+require_once(APPROOT.'application/applicationextension/backoffice/URLButtonItem.php');
+require_once(APPROOT.'application/applicationextension/backoffice/URLPopupMenuItem.php');
+
+//deprecated class and interface
+require_once(APPROOT.'application/applicationextension/backoffice/iApplicationObjectExtension.php');
+require_once(APPROOT.'application/applicationextension/backoffice/AbstractApplicationObjectExtension.php');
+
+
+
+require_once(APPROOT.'application/applicationextension/iBackupExtraFilesExtension.php');
+require_once(APPROOT.'application/applicationextension/iKPILoggerExtension.php');
+require_once(APPROOT.'application/applicationextension/iModuleExtension.php');
+
+require_once(APPROOT.'application/applicationextension/login/iLoginExtension.php');
+require_once(APPROOT.'application/applicationextension/login/iLoginFSMExtension.php');
+require_once(APPROOT.'application/applicationextension/login/iLoginUIExtension.php');
+require_once(APPROOT.'application/applicationextension/login/iLogoutExtension.php');
+require_once(APPROOT.'application/applicationextension/login/AbstractLoginFSMExtension.php');
+
+require_once(APPROOT.'application/applicationextension/portal/iPortalUIExtension.php');
+require_once(APPROOT.'application/applicationextension/portal/AbstractPortalUIExtension.php');
+
+require_once(APPROOT.'application/applicationextension/rest/iRestInputSanitizer.php');
+require_once(APPROOT.'application/applicationextension/rest/iRestServiceProvider.php');
+require_once(APPROOT.'application/applicationextension/rest/RestResult.php');
+require_once(APPROOT.'application/applicationextension/rest/RestUtils.php');
-/**
- * @api
- * @package LoginExtensibilityAPI
- * @since 2.7.0
- */
-interface iLoginExtension
-{
- /**
- * Return the list of supported login modes for this plugin
- *
- * @api
- * @return array of supported login modes
- */
- public function ListSupportedLoginModes();
-}
-/**
- * @api
- * @package LoginExtensibilityAPI
- * @since 2.7.0
- */
-interface iLoginFSMExtension extends iLoginExtension
-{
- /**
- * Execute action for this login state
- * If a page is displayed, the action must exit at this point
- * if LoginWebPage::LOGIN_FSM_RETURN_ERROR is returned $iErrorCode must be set
- * if LoginWebPage::LOGIN_FSM_RETURN_OK is returned then the login is OK and terminated
- * if LoginWebPage::LOGIN_FSM_CONTINUE is returned then the FSM will proceed to next plugin or state
- *
- * @api
- * @param string $sLoginState (see LoginWebPage::LOGIN_STATE_...)
- * @param int $iErrorCode (see LoginWebPage::EXIT_CODE_...)
- *
- * @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_CONTINUE
- */
- public function LoginAction($sLoginState, &$iErrorCode);
-}
-/**
- * Login finite state machine
- *
- * Execute the action corresponding to the current login state.
- *
- * * If a page is displayed, the action must exit at this point
- * * if LoginWebPage::LOGIN_FSM_RETURN_ERROR is returned $iErrorCode must be set
- * * if LoginWebPage::LOGIN_FSM_RETURN_OK is returned then the login is OK and terminated
- * * if LoginWebPage::LOGIN_FSM_CONTINUE is returned then the FSM will proceed to next plugin or to next state
- *
- * @api
- * @package LoginExtensibilityAPI
- * @since 2.7.0
- */
-abstract class AbstractLoginFSMExtension implements iLoginFSMExtension
-{
- /**
- * @inheritDoc
- */
- abstract public function ListSupportedLoginModes();
- /**
- * @inheritDoc
- */
- public function LoginAction($sLoginState, &$iErrorCode)
- {
- switch ($sLoginState) {
- case LoginWebPage::LOGIN_STATE_START:
- return $this->OnStart($iErrorCode);
-
- case LoginWebPage::LOGIN_STATE_MODE_DETECTION:
- return $this->OnModeDetection($iErrorCode);
-
- case LoginWebPage::LOGIN_STATE_READ_CREDENTIALS:
- return $this->OnReadCredentials($iErrorCode);
-
- case LoginWebPage::LOGIN_STATE_CHECK_CREDENTIALS:
- return $this->OnCheckCredentials($iErrorCode);
-
- case LoginWebPage::LOGIN_STATE_CREDENTIALS_OK:
- return $this->OnCredentialsOK($iErrorCode);
-
- case LoginWebPage::LOGIN_STATE_USER_OK:
- return $this->OnUsersOK($iErrorCode);
-
- case LoginWebPage::LOGIN_STATE_CONNECTED:
- return $this->OnConnected($iErrorCode);
-
- case LoginWebPage::LOGIN_STATE_ERROR:
- return $this->OnError($iErrorCode);
- }
-
- return LoginWebPage::LOGIN_FSM_CONTINUE;
- }
-
- /**
- * Initialization
- *
- * @api
- * @param int $iErrorCode (see LoginWebPage::EXIT_CODE_...)
- *
- * @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_CONTINUE
- */
- protected function OnStart(&$iErrorCode)
- {
- return LoginWebPage::LOGIN_FSM_CONTINUE;
- }
-
- /**
- * Detect login mode explicitly without respecting configured order (legacy mode)
- * In most case do nothing here
- *
- * @api
- * @param int $iErrorCode (see LoginWebPage::EXIT_CODE_...)
- *
- * @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_CONTINUE
- */
- protected function OnModeDetection(&$iErrorCode)
- {
- return LoginWebPage::LOGIN_FSM_CONTINUE;
- }
-
- /**
- * Obtain the credentials either if login mode is empty or set to yours.
- * This step can be called multiple times by the FSM:
- * for example:
- * 1 - display login form
- * 2 - read the values posted by the user (store that in session)
- *
- * @api
- * @param int $iErrorCode (see LoginWebPage::EXIT_CODE_...)
- *
- * @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_CONTINUE
- */
- protected function OnReadCredentials(&$iErrorCode)
- {
- return LoginWebPage::LOGIN_FSM_CONTINUE;
- }
-
- /**
- * Control the validity of the data from the session
- * Automatic user provisioning can be done here
- *
- * @api
- * @param int $iErrorCode (see LoginWebPage::EXIT_CODE_...)
- *
- * @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_CONTINUE
- */
- protected function OnCheckCredentials(&$iErrorCode)
- {
- return LoginWebPage::LOGIN_FSM_CONTINUE;
- }
-
- /**
- * @api
- * @param int $iErrorCode (see LoginWebPage::EXIT_CODE_...)
- *
- * @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_CONTINUE
- */
- protected function OnCredentialsOK(&$iErrorCode)
- {
- return LoginWebPage::LOGIN_FSM_CONTINUE;
- }
-
- /**
- * @api
- * @param int $iErrorCode (see LoginWebPage::EXIT_CODE_...)
- *
- * @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_CONTINUE
- */
- protected function OnUsersOK(&$iErrorCode)
- {
- return LoginWebPage::LOGIN_FSM_CONTINUE;
- }
-
- /**
- * @api
- * @param int $iErrorCode (see LoginWebPage::EXIT_CODE_...)
- *
- * @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_CONTINUE
- */
- protected function OnConnected(&$iErrorCode)
- {
- return LoginWebPage::LOGIN_FSM_CONTINUE;
- }
-
- /**
- * @api
- * @param int $iErrorCode (see LoginWebPage::EXIT_CODE_...)
- *
- * @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_CONTINUE
- */
- protected function OnError(&$iErrorCode)
- {
- return LoginWebPage::LOGIN_FSM_CONTINUE;
- }
-}
-
-/**
- * @api
- * @package LoginExtensibilityAPI
- * @since 2.7.0
- */
-interface iLogoutExtension extends iLoginExtension
-{
- /**
- * Execute all actions to log out properly
- * @api
- */
- public function LogoutAction();
-}
-
-/**
- * Login page extensibility
- *
- * @api
- * @package UIExtensibilityAPI
- * @since 2.7.0
- */
-interface iLoginUIExtension extends iLoginExtension
-{
- /**
- * @api
- * @return LoginTwigContext
- */
- public function GetTwigContext();
-}
-
-/**
- * @api
- * @package PreferencesExtensibilityAPI
- * @since 2.7.0
- */
-interface iPreferencesExtension
-{
- /**
- * @api
- * @param WebPage $oPage
- *
- */
- public function DisplayPreferences(WebPage $oPage);
-
- /**
- * @api
- * @param WebPage $oPage
- * @param string $sOperation
- *
- * @return bool true if the operation has been used
- */
- public function ApplyPreferences(WebPage $oPage, $sOperation);
-}
-
-/**
- * Extend this class instead of implementing iPreferencesExtension if you don't need to overload all methods
- *
- * @api
- * @package PreferencesExtensibilityAPI
- * @since 2.7.0
- */
-abstract class AbstractPreferencesExtension implements iPreferencesExtension
-{
- /**
- * @inheritDoc
- */
- public function DisplayPreferences(WebPage $oPage)
- {
- // Do nothing
- }
-
- /**
- * @inheritDoc
- */
- public function ApplyPreferences(WebPage $oPage, $sOperation)
- {
- // Do nothing
- }
-
-}
-
-/**
- * Implement this interface to change the behavior of the GUI for some objects.
- *
- * All methods are invoked by iTop for a given object. There are basically two usages:
- *
- * 1) To tweak the form of an object, you will have to implement a specific behavior within:
- *
- * * OnDisplayProperties (bEditMode = true)
- * * OnFormSubmit
- * * OnFormCancel
- *
- * 2) To tune the display of the object details, you can use:
- *
- * * OnDisplayProperties
- * * OnDisplayRelations
- * * GetIcon
- * * GetHilightClass
- *
- * Please note that some of the APIs can be called several times for a single page displayed.
- * Therefore it is not recommended to perform too many operations, such as querying the database.
- * A recommended pattern is to cache data by the mean of static members.
- *
- * @api
- * @package UIExtensibilityAPI
- */
-interface iApplicationUIExtension
-{
- /**
- * Invoked when an object is being displayed (wiew or edit)
- *
- * The method is called right after the main tab has been displayed.
- * You can add output to the page, either to change the display, or to add a form input
- *
- * Example:
- *
- * if ($bEditMode)
- * {
- * $oPage->p('Age of the captain: <input type="text" name="captain_age"/>');
- * }
- * else
- * {
- * $oPage->p('Age of the captain: '.$iCaptainAge);
- * }
- *
- *
- * @api
- * @param DBObject $oObject The object being displayed
- * @param WebPage $oPage The output context
- * @param boolean $bEditMode True if the edition form is being displayed
- *
- * @return void
- */
- public function OnDisplayProperties($oObject, WebPage $oPage, $bEditMode = false);
-
- /**
- * Invoked when an object is being displayed (wiew or edit)
- *
- * The method is called rigth after all the tabs have been displayed
- *
- * @api
- * @param DBObject $oObject The object being displayed
- * @param WebPage $oPage The output context
- * @param boolean $bEditMode True if the edition form is being displayed
- *
- * @return void
- */
- public function OnDisplayRelations($oObject, WebPage $oPage, $bEditMode = false);
-
- /**
- * Invoked when the end-user clicks on Modify from the object edition form
- *
- * The method is called after the changes from the standard form have been
- * taken into account, and before saving the changes into the database.
- *
- * @api
- * @param DBObject $oObject The object being edited
- * @param string $sFormPrefix Prefix given to the HTML form inputs
- *
- * @return void
- */
- public function OnFormSubmit($oObject, $sFormPrefix = '');
-
- /**
- * Invoked when the end-user clicks on Cancel from the object edition form
- *
- * Implement here any cleanup. This is necessary when you have injected some
- * javascript into the edition form, and if that code requires to store temporary data
- * (this is the case when a file must be uploaded).
- *
- * @api
- * @param string $sTempId Unique temporary identifier made of session_id and transaction_id. It identifies the object in a unique way.
- *
- * @return void
- */
- public function OnFormCancel($sTempId);
-
- /**
- * Not yet called by the framework!
- *
- * Sorry, the verb has been reserved. You must implement it, but it is not called as of now.
- *
- * @api
- * @param DBObject $oObject The object being displayed
- *
- * @return string[] desc
- */
- public function EnumUsedAttributes($oObject); // Not yet implemented
-
- /**
- * Not yet called by the framework!
- *
- * Sorry, the verb has been reserved. You must implement it, but it is not called as of now.
- *
- * @api
- * @param DBObject $oObject The object being displayed
- *
- * @return string Path of the icon, relative to the modules directory.
- */
- public function GetIcon($oObject); // Not yet implemented
-
- /**
- * Invoked when the object is displayed alone or within a list
- *
- * Returns a value influencing the appearance of the object depending on its
- * state.
- *
- * Possible values are:
- *
- * * HILIGHT_CLASS_CRITICAL
- * * HILIGHT_CLASS_WARNING
- * * HILIGHT_CLASS_OK
- * * HILIGHT_CLASS_NONE
- *
- * @api
- * @param DBObject $oObject The object being displayed
- *
- * @return integer The value representing the mood of the object
- */
- public function GetHilightClass($oObject);
-
- /**
- * Called when building the Actions menu for a single object or a list of objects
- *
- * Use this to add items to the Actions menu. You will have to specify a label and an URL.
- *
- * Example:
- *
- * $oObject = $oSet->fetch();
- * if ($oObject instanceof Sheep)
- * {
- * return array('View in my app' => 'http://myserver/view_sheeps?id='.$oObject->Get('name'));
- * }
- * else
- * {
- * return array();
- * }
- *
- *
- * See also iPopupMenuExtension for greater flexibility
- *
- * @api
- * @param DBObjectSet $oSet A set of persistent objects (DBObject)
- *
- * @return array
- */
- public function EnumAllowedActions(DBObjectSet $oSet);
-}
-
-/**
- * Extend this class instead of implementing iApplicationUIExtension if you don't need to overload
- *
- * @api
- * @package UIExtensibilityAPI
- * @since 2.7.0
- */
-abstract class AbstractApplicationUIExtension implements iApplicationUIExtension
-{
- /**
- * @inheritDoc
- */
- public function OnDisplayProperties($oObject, WebPage $oPage, $bEditMode = false)
- {
- }
-
- /**
- * @inheritDoc
- */
- public function OnDisplayRelations($oObject, WebPage $oPage, $bEditMode = false)
- {
- }
-
- /**
- * @inheritDoc
- */
- public function OnFormSubmit($oObject, $sFormPrefix = '')
- {
- }
-
- /**
- * @inheritDoc
- */
- public function OnFormCancel($sTempId)
- {
- }
-
- /**
- * @inheritDoc
- */
- public function EnumUsedAttributes($oObject)
- {
- return array();
- }
-
- /**
- * @inheritDoc
- */
- public function GetIcon($oObject)
- {
- return '';
- }
-
- /**
- * @inheritDoc
- */
- public function GetHilightClass($oObject)
- {
- return HILIGHT_CLASS_NONE;
- }
-
- /**
- * @inheritDoc
- */
- public function EnumAllowedActions(DBObjectSet $oSet)
- {
- return array();
- }
-
-}
-
-/**
- * Implement this interface to perform specific operations when objects are manipulated
- *
- * Note that those methods will be called when objects are manipulated, either in a programmatic way
- * or through the GUI.
- *
- * @api
- * @deprecated 3.1.0 N°4756 use the new event service instead, see {@see DBObject::FireEvent()} method. More details on each method PHPDoc.
- * @package ORMExtensibilityAPI
- */
-interface iApplicationObjectExtension
-{
- /**
- * Invoked to determine whether an object has been modified in memory
- *
- * The GUI calls this verb to determine the message that will be displayed to the end-user.
- * Anyhow, this API can be called in other contexts such as the CSV import tool.
- *
- * If the extension returns false, then the framework will perform the usual evaluation.
- * Otherwise, the answer is definitively "yes, the object has changed".
- *
- * @api
- * @deprecated 3.1.0 N°4756 No alternative available, this API was unstable and is abandoned
- * @param \cmdbAbstractObject $oObject The target object
- *
- * @return boolean True if something has changed for the target object
- */
- public function OnIsModified($oObject);
-
- /**
- * Invoked to determine whether an object can be written to the database
- *
- * The GUI calls this verb and reports any issue.
- * Anyhow, this API can be called in other contexts such as the CSV import tool.
- *
- * @api
- * @deprecated 3.1.0 N°4756 Use EVENT_DB_CHECK_TO_WRITE event instead
- * @param \cmdbAbstractObject $oObject The target object
- *
- * @return string[] A list of errors message. An error message is made of one line and it can be displayed to the end-user.
- */
- public function OnCheckToWrite($oObject);
-
- /**
- * Invoked to determine wether an object can be deleted from the database
- *
- * The GUI calls this verb and stops the deletion process if any issue is reported.
- *
- * Please not that it is not possible to cascade deletion by this mean: only stopper issues can be handled.
- *
- * @api
- * @deprecated 3.1.0 N°4756 Use EVENT_DB_CHECK_TO_DELETE event instead
- * @param \cmdbAbstractObject $oObject The target object
- *
- * @return string[] A list of errors message. An error message is made of one line and it can be displayed to the end-user.
- */
- public function OnCheckToDelete($oObject);
-
- /**
- * Invoked when an object is updated into the database. The method is called right after the object has been written to the
- * database.
- *
- * Useful methods you can call on $oObject :
- *
- * * {@see DBObject::ListPreviousValuesForUpdatedAttributes()} : list of changed attributes and their values before the change
- * * {@see DBObject::Get()} : for a given attribute the new value that was persisted
- *
- * @api
- * @deprecated 3.1.0 N°4756 Use EVENT_DB_AFTER_WRITE event instead
- * @param \cmdbAbstractObject $oObject The target object
- * @param CMDBChange|null $oChange A change context. Since 2.0 it is fine to ignore it, as the framework does maintain this information
- * once for all the changes made within the current page
- *
- * @return void
- *
- * @since 2.7.0 N°2293 can access object changes by calling {@see DBObject::ListPreviousValuesForUpdatedAttributes()} on $oObject
- */
- public function OnDBUpdate($oObject, $oChange = null);
-
- /**
- * Invoked when an object is created into the database
- *
- * The method is called right after the object has been written to the database.
- *
- * @api
- * @deprecated 3.1.0 N°4756 Use EVENT_DB_AFTER_WRITE event instead
- * @param \cmdbAbstractObject $oObject The target object
- * @param CMDBChange|null $oChange A change context. Since 2.0 it is fine to ignore it, as the framework does maintain this information
- * once for all the changes made within the current page
- *
- * @return void
- */
- public function OnDBInsert($oObject, $oChange = null);
-
- /**
- * Invoked when an object is deleted from the database
- *
- * The method is called right before the object will be deleted from the database.
- *
- * @api
- * @deprecated 3.1.0 N°4756 Use EVENT_DB_AFTER_DELETE event instead
- * @param \cmdbAbstractObject $oObject The target object
- * @param CMDBChange|null $oChange A change context. Since 2.0 it is fine to ignore it, as the framework does maintain this information
- * once for all the changes made within the current page
- *
- * @return void
- */
- public function OnDBDelete($oObject, $oChange = null);
-}
-
-/**
- * Extend this class instead of iApplicationObjectExtension if you don't need to overload all methods
- *
- * @api
- * @deprecated 3.1.0 N°4756 use the new event service instead, see {@see DBObject::FireEvent()} method
- * @package ORMExtensibilityAPI
- * @since 2.7.0
- */
-abstract class AbstractApplicationObjectExtension implements iApplicationObjectExtension
-{
- /**
- * @inheritDoc
- */
- public function OnIsModified($oObject)
- {
- return false;
- }
-
- /**
- * @inheritDoc
- */
- public function OnCheckToWrite($oObject)
- {
- return array();
- }
-
- /**
- * @inheritDoc
- */
- public function OnCheckToDelete($oObject)
- {
- return array();
- }
-
- /**
- * @inheritDoc
- */
- public function OnDBUpdate($oObject, $oChange = null)
- {
- }
-
- /**
- * @inheritDoc
- */
- public function OnDBInsert($oObject, $oChange = null)
- {
- }
-
- /**
- * @inheritDoc
- */
- public function OnDBDelete($oObject, $oChange = null)
- {
- }
-
-}
-
-/**
- * New extension to add menu items in the "popup" menus inside iTop. Provides a greater flexibility than
- * iApplicationUIExtension::EnumAllowedActions.
- *
- * To add some menus into iTop, declare a class that implements this interface, it will be called automatically
- * by the application, as long as the class definition is included somewhere in the code
- *
- * @api
- * @package UIExtensibilityAPI
- * @since 2.0
- */
-interface iPopupMenuExtension
-{
- /**
- * Insert an item into the Actions menu of a list
- *
- * $param is a DBObjectSet containing the list of objects
- * @api
- */
- const MENU_OBJLIST_ACTIONS = 1;
- /**
- * Insert an item into the Toolkit menu of a list
- *
- * $param is a DBObjectSet containing the list of objects
- * @api
- */
- const MENU_OBJLIST_TOOLKIT = 2;
- /**
- * Insert an item into the Actions menu on an object details page
- *
- * $param is a DBObject instance: the object currently displayed
- * @api
- */
- const MENU_OBJDETAILS_ACTIONS = 3;
- /**
- * Insert an item into the Dashboard menu
- *
- * The dashboad menu is shown on the top right corner when a dashboard
- * is being displayed.
- *
- * $param is a Dashboard instance: the dashboard currently displayed
- * @api
- */
- const MENU_DASHBOARD_ACTIONS = 4;
- /**
- * Insert an item into the User menu (upper right corner)
- *
- * $param is null
- * @api
- */
- const MENU_USER_ACTIONS = 5;
- /**
- * Insert an item into the Action menu on an object item in an objects list in the portal
- *
- * $param is an array('portal_id' => $sPortalId, 'object' => $oObject) containing the portal id and a DBObject instance (the object on
- * the current line)
- * @api
- */
- const PORTAL_OBJLISTITEM_ACTIONS = 7;
- /**
- * Insert an item into the Action menu on an object details page in the portal
- *
- * $param is an array('portal_id' => $sPortalId, 'object' => $oObject) containing the portal id and a DBObject instance (the object
- * currently displayed)
- * @api
- */
- const PORTAL_OBJDETAILS_ACTIONS = 8;
-
- /**
- * Insert an item into the Actions menu of a list in the portal
- * Note: This is not implemented yet !
- *
- * $param is an array('portal_id' => $sPortalId, 'object_set' => $oSet) containing DBObjectSet containing the list of objects
- *
- * @todo
- */
- const PORTAL_OBJLIST_ACTIONS = 6;
- /**
- * Insert an item into the user menu of the portal
- * Note: This is not implemented yet !
- *
- * $param is the portal id
- *
- * @todo
- */
- const PORTAL_USER_ACTIONS = 9;
- /**
- * Insert an item into the navigation menu of the portal
- * Note: This is not implemented yet !
- *
- * $param is the portal id
- *
- * @todo
- */
- const PORTAL_MENU_ACTIONS = 10;
-
- /**
- * Get the list of items to be added to a menu.
- *
- * This method is called by the framework for each menu.
- * The items will be inserted in the menu in the order of the returned array.
- *
- * @api
- * @param int $iMenuId The identifier of the type of menu, as listed by the constants MENU_xxx
- * @param mixed $param Depends on $iMenuId, see the constants defined above
- *
- * @return object[] An array of ApplicationPopupMenuItem or an empty array if no action is to be added to the menu
- */
- public static function EnumItems($iMenuId, $param);
-}
-
-/**
- * Base class for the various types of custom menus
- *
- * @api
- * @package UIExtensibilityAPI
- * @since 2.0
- */
-abstract class ApplicationPopupMenuItem
-{
- /** @ignore */
- protected $sUID;
- /** @ignore */
- protected $sLabel;
- /** @ignore */
- protected $sTooltip;
- /** @ignore */
- protected $sIconClass;
- /** @ignore */
- protected $aCssClasses;
-
- /**
- * Constructor
- *
- * @api
- * @param string $sUID The unique identifier of this menu in iTop... make sure you pass something unique enough
- * @param string $sLabel The display label of the menu (must be localized)
- */
- public function __construct($sUID, $sLabel)
- {
- $this->sUID = $sUID;
- $this->sLabel = $sLabel;
- $this->sTooltip = '';
- $this->sIconClass = '';
- $this->aCssClasses = array();
- }
-
- /**
- * Get the UID
- *
- * @return string The unique identifier
- * @ignore
- */
- public function GetUID()
- {
- return $this->sUID;
- }
-
- /**
- * Get the label
- *
- * @return string The label
- * @ignore
- */
- public function GetLabel()
- {
- return $this->sLabel;
- }
-
- /**
- * Get the CSS classes
- *
- * @return array
- * @ignore
- */
- public function GetCssClasses()
- {
- return $this->aCssClasses;
- }
-
- /**
- * @api
- * @param $aCssClasses
- */
- public function SetCssClasses($aCssClasses)
- {
- $this->aCssClasses = $aCssClasses;
- }
-
- /**
- * Adds a CSS class to the CSS classes that will be put on the menu item
- *
- * @api
- * @param $sCssClass
- */
- public function AddCssClass($sCssClass)
- {
- $this->aCssClasses[] = $sCssClass;
- }
-
-
- /**
- * @param $sTooltip
- *
- * @api
- * @since 3.0.0
- */
- public function SetTooltip($sTooltip)
- {
- $this->sTooltip = $sTooltip;
- }
-
- /**
- * @return string
- *
- * @api
- * @since 3.0.0
- */
- public function GetTooltip()
- {
- return $this->sTooltip;
- }
-
- /**
- * @param $sIconClass
- *
- * @api
- * @since 3.0.0
- */
- public function SetIconClass($sIconClass)
- {
- $this->sIconClass = $sIconClass;
- }
-
- /**
- * @return string
- *
- * @api
- * @since 3.0.0
- */
- public function GetIconClass()
- {
- return $this->sIconClass;
- }
-
- /**
- * Returns the components to create a popup menu item in HTML
- *
- * @return array A hash array: array('label' => , 'url' => , 'target' => , 'onclick' => )
- * @ignore
- */
- abstract public function GetMenuItem();
-
- /** @ignore */
- public function GetLinkedScripts()
- {
- return array();
- }
-}
-
-/**
- * Class for adding an item into a popup menu that browses to the given URL
- *
- * Note: This works only in the backoffice, {@see \URLButtonItem} for the end-user portal
- *
- * @api
- * @package UIExtensibilityAPI
- * @since 2.0
- */
-class URLPopupMenuItem extends ApplicationPopupMenuItem
-{
- /** @ignore */
- protected $sUrl;
- /** @ignore */
- protected $sTarget;
-
- /**
- * Constructor
- *
- * @api
- * @param string $sUID The unique identifier of this menu in iTop... make sure you pass something unique enough
- * @param string $sLabel The display label of the menu (must be localized)
- * @param string $sUrl If the menu is an hyperlink, provide the absolute hyperlink here
- * @param string $sTarget In case the menu is an hyperlink and a specific target is needed (_blank for example), pass it here
- */
- public function __construct($sUID, $sLabel, $sUrl, $sTarget = '_top')
- {
- parent::__construct($sUID, $sLabel);
- $this->sUrl = $sUrl;
- $this->sTarget = $sTarget;
- }
-
- /** @ignore */
- public function GetMenuItem()
- {
- return array('label' => $this->GetLabel(),
- 'url' => $this->GetUrl(),
- 'target' => $this-> GetTarget(),
- 'css_classes' => $this->aCssClasses,
- 'icon_class' => $this->sIconClass,
- 'tooltip' => $this->sTooltip
- );
- }
-
- /** @ignore */
- public function GetUrl()
- {
- return $this->sUrl;
- }
-
- /** @ignore */
- public function GetTarget()
- {
- return $this->sTarget;
- }
-}
-
-/**
- * Class for adding an item into a popup menu that triggers some Javascript code
- *
- * Note: This works only in the backoffice, {@see \JSButtonItem} for the end-user portal
- *
- * @api
- * @package UIExtensibilityAPI
- * @since 2.0
- */
-class JSPopupMenuItem extends ApplicationPopupMenuItem
-{
- /** @ignore */
- protected $sJsCode;
- /** @ignore */
- protected $sUrl;
- /** @ignore */
- protected $aIncludeJSFiles;
-
- /**
- * Class for adding an item that triggers some Javascript code
- *
- * @api
- * @param string $sUID The unique identifier of this menu in iTop... make sure you pass something unique enough
- * @param string $sLabel The display label of the menu (must be localized)
- * @param string $sJSCode In case the menu consists in executing some havascript code inside the page, pass it here. If supplied $sURL
- * ans $sTarget will be ignored
- * @param array $aIncludeJSFiles An array of file URLs to be included (once) to provide some JS libraries for the page.
- */
- public function __construct($sUID, $sLabel, $sJSCode, $aIncludeJSFiles = array())
- {
- parent::__construct($sUID, $sLabel);
- $this->sJsCode = $sJSCode;
- $this->sUrl = '#';
- $this->aIncludeJSFiles = $aIncludeJSFiles;
- }
-
- /** @ignore */
- public function GetMenuItem()
- {
- // Note: the semicolumn is a must here!
- return array(
- 'label' => $this->GetLabel(),
- 'onclick' => $this->GetJsCode().'; return false;',
- 'url' => $this->GetUrl(),
- 'css_classes' => $this->GetCssClasses(),
- 'icon_class' => $this->sIconClass,
- 'tooltip' => $this->sTooltip
- );
- }
-
- /** @ignore */
- public function GetLinkedScripts()
- {
- return $this->aIncludeJSFiles;
- }
-
- /** @ignore */
- public function GetJsCode()
- {
- return $this->sJsCode;
- }
-
- /** @ignore */
- public function GetUrl()
- {
- return $this->sUrl;
- }
-}
-
-/**
- * Class for adding a separator (horizontal line, not selectable) the output
- * will automatically reduce several consecutive separators to just one
- *
- * @api
- * @package UIExtensibilityAPI
- * @since 2.0
- */
-class SeparatorPopupMenuItem extends ApplicationPopupMenuItem
-{
- static $idx = 0;
-
- /**
- * Constructor
- * @api
- */
- public function __construct()
- {
- parent::__construct('_separator_'.(self::$idx++), '');
- }
-
- /** @ignore */
- public function GetMenuItem()
- {
- return array('label' => '
+ * $oObject = $oSet->fetch();
+ * if ($oObject instanceof Sheep)
+ * {
+ * return array('View in my app' => 'http://myserver/view_sheeps?id='.$oObject->Get('name'));
+ * }
+ * else
+ * {
+ * return array();
+ * }
+ *
+ *
+ * See also iPopupMenuExtension for greater flexibility
+ *
+ * @param DBObjectSet $oSet A set of persistent objects (DBObject)
+ *
+ * @return array
+ * @api
+ */
+ public function EnumAllowedActions(DBObjectSet $oSet);
+}
\ No newline at end of file
diff --git a/application/applicationextension/backoffice/iBackofficeDictEntriesExtension.php b/application/applicationextension/backoffice/iBackofficeDictEntriesExtension.php
new file mode 100644
index 000000000..ba188a09d
--- /dev/null
+++ b/application/applicationextension/backoffice/iBackofficeDictEntriesExtension.php
@@ -0,0 +1,19 @@
+ 'FQCN\FieldA', 'form_renderer' => 'Combodo\iTop\Renderer\Console\ConsoleFormRenderer', 'field_renderer' => 'FQCN\FieldRendererA'],
+ * ['field' => 'FQCN\FieldB', 'form_renderer' => 'Combodo\iTop\Renderer\Console\ConsoleFormRenderer', 'field_renderer' => 'FQCN\FieldRendererB'],
+ * ['field' => 'FQCN\FieldA', 'form_renderer' => 'Combodo\iTop\Renderer\Bootstrap\BsFormRenderer', 'field_renderer' => 'FQCN\FieldRendererA'],
+ * ['field' => 'FQCN\FieldB', 'form_renderer' => 'Combodo\iTop\Renderer\Bootstrap\BsFormRenderer', 'field_renderer' => 'FQCN\FieldRendererB'],
+ * ]
+ * ```
+ */
+ public static function RegisterSupportedFields(): array;
+}
\ No newline at end of file
diff --git a/application/applicationextension/backoffice/iPageUIBlockExtension.php b/application/applicationextension/backoffice/iPageUIBlockExtension.php
new file mode 100644
index 000000000..9b02f9278
--- /dev/null
+++ b/application/applicationextension/backoffice/iPageUIBlockExtension.php
@@ -0,0 +1,47 @@
+ $sPortalId, 'object' => $oObject) containing the portal id and a DBObject instance (the object on
+ * the current line)
+ * @api
+ */
+ const PORTAL_OBJLISTITEM_ACTIONS = 7;
+ /**
+ * Insert an item into the Action menu on an object details page in the portal
+ *
+ * $param is an array('portal_id' => $sPortalId, 'object' => $oObject) containing the portal id and a DBObject instance (the object
+ * currently displayed)
+ * @api
+ */
+ const PORTAL_OBJDETAILS_ACTIONS = 8;
+
+ /**
+ * Insert an item into the Actions menu of a list in the portal
+ * Note: This is not implemented yet !
+ *
+ * $param is an array('portal_id' => $sPortalId, 'object_set' => $oSet) containing DBObjectSet containing the list of objects
+ *
+ * @todo
+ */
+ const PORTAL_OBJLIST_ACTIONS = 6;
+ /**
+ * Insert an item into the user menu of the portal
+ * Note: This is not implemented yet !
+ *
+ * $param is the portal id
+ *
+ * @todo
+ */
+ const PORTAL_USER_ACTIONS = 9;
+ /**
+ * Insert an item into the navigation menu of the portal
+ * Note: This is not implemented yet !
+ *
+ * $param is the portal id
+ *
+ * @todo
+ */
+ const PORTAL_MENU_ACTIONS = 10;
+
+ /**
+ * Get the list of items to be added to a menu.
+ *
+ * This method is called by the framework for each menu.
+ * The items will be inserted in the menu in the order of the returned array.
+ *
+ * @param int $iMenuId The identifier of the type of menu, as listed by the constants MENU_xxx
+ * @param mixed $param Depends on $iMenuId, see the constants defined above
+ *
+ * @return object[] An array of ApplicationPopupMenuItem or an empty array if no action is to be added to the menu
+ * @api
+ */
+ public static function EnumItems($iMenuId, $param);
+}
\ No newline at end of file
diff --git a/application/applicationextension/backoffice/iPreferencesExtension.php b/application/applicationextension/backoffice/iPreferencesExtension.php
new file mode 100644
index 000000000..f166b0b34
--- /dev/null
+++ b/application/applicationextension/backoffice/iPreferencesExtension.php
@@ -0,0 +1,28 @@
+OnStart($iErrorCode);
+
+ case LoginWebPage::LOGIN_STATE_MODE_DETECTION:
+ return $this->OnModeDetection($iErrorCode);
+
+ case LoginWebPage::LOGIN_STATE_READ_CREDENTIALS:
+ return $this->OnReadCredentials($iErrorCode);
+
+ case LoginWebPage::LOGIN_STATE_CHECK_CREDENTIALS:
+ return $this->OnCheckCredentials($iErrorCode);
+
+ case LoginWebPage::LOGIN_STATE_CREDENTIALS_OK:
+ return $this->OnCredentialsOK($iErrorCode);
+
+ case LoginWebPage::LOGIN_STATE_USER_OK:
+ return $this->OnUsersOK($iErrorCode);
+
+ case LoginWebPage::LOGIN_STATE_CONNECTED:
+ return $this->OnConnected($iErrorCode);
+
+ case LoginWebPage::LOGIN_STATE_ERROR:
+ return $this->OnError($iErrorCode);
+ }
+
+ return LoginWebPage::LOGIN_FSM_CONTINUE;
+ }
+
+ /**
+ * Initialization
+ *
+ * @param int $iErrorCode (see LoginWebPage::EXIT_CODE_...)
+ *
+ * @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_CONTINUE
+ * @api
+ */
+ protected function OnStart(&$iErrorCode)
+ {
+ return LoginWebPage::LOGIN_FSM_CONTINUE;
+ }
+
+ /**
+ * Detect login mode explicitly without respecting configured order (legacy mode)
+ * In most case do nothing here
+ *
+ * @param int $iErrorCode (see LoginWebPage::EXIT_CODE_...)
+ *
+ * @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_CONTINUE
+ * @api
+ */
+ protected function OnModeDetection(&$iErrorCode)
+ {
+ return LoginWebPage::LOGIN_FSM_CONTINUE;
+ }
+
+ /**
+ * Obtain the credentials either if login mode is empty or set to yours.
+ * This step can be called multiple times by the FSM:
+ * for example:
+ * 1 - display login form
+ * 2 - read the values posted by the user (store that in session)
+ *
+ * @param int $iErrorCode (see LoginWebPage::EXIT_CODE_...)
+ *
+ * @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_CONTINUE
+ * @api
+ */
+ protected function OnReadCredentials(&$iErrorCode)
+ {
+ return LoginWebPage::LOGIN_FSM_CONTINUE;
+ }
+
+ /**
+ * Control the validity of the data from the session
+ * Automatic user provisioning can be done here
+ *
+ * @param int $iErrorCode (see LoginWebPage::EXIT_CODE_...)
+ *
+ * @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_CONTINUE
+ * @api
+ */
+ protected function OnCheckCredentials(&$iErrorCode)
+ {
+ return LoginWebPage::LOGIN_FSM_CONTINUE;
+ }
+
+ /**
+ * @param int $iErrorCode (see LoginWebPage::EXIT_CODE_...)
+ *
+ * @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_CONTINUE
+ * @api
+ */
+ protected function OnCredentialsOK(&$iErrorCode)
+ {
+ return LoginWebPage::LOGIN_FSM_CONTINUE;
+ }
+
+ /**
+ * @param int $iErrorCode (see LoginWebPage::EXIT_CODE_...)
+ *
+ * @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_CONTINUE
+ * @api
+ */
+ protected function OnUsersOK(&$iErrorCode)
+ {
+ return LoginWebPage::LOGIN_FSM_CONTINUE;
+ }
+
+ /**
+ * @param int $iErrorCode (see LoginWebPage::EXIT_CODE_...)
+ *
+ * @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_CONTINUE
+ * @api
+ */
+ protected function OnConnected(&$iErrorCode)
+ {
+ return LoginWebPage::LOGIN_FSM_CONTINUE;
+ }
+
+ /**
+ * @param int $iErrorCode (see LoginWebPage::EXIT_CODE_...)
+ *
+ * @return int LoginWebPage::LOGIN_FSM_RETURN_ERROR, LoginWebPage::LOGIN_FSM_RETURN_OK or LoginWebPage::LOGIN_FSM_CONTINUE
+ * @api
+ */
+ protected function OnError(&$iErrorCode)
+ {
+ return LoginWebPage::LOGIN_FSM_CONTINUE;
+ }
+}
\ No newline at end of file
diff --git a/application/applicationextension/login/iLoginExtension.php b/application/applicationextension/login/iLoginExtension.php
new file mode 100644
index 000000000..63c38f3c3
--- /dev/null
+++ b/application/applicationextension/login/iLoginExtension.php
@@ -0,0 +1,17 @@
+ tag
+ *
+ * @param \Symfony\Component\DependencyInjection\Container $oContainer
+ *
+ * @return string
+ * @api
+ */
+ public function GetBodyHTML(\Symfony\Component\DependencyInjection\Container $oContainer);
+
+ /**
+ * Returns raw HTML code to put at the end of the #main-wrapper element
+ *
+ * @param \Symfony\Component\DependencyInjection\Container $oContainer
+ *
+ * @return string
+ * @api
+ */
+ public function GetMainContentHTML(\Symfony\Component\DependencyInjection\Container $oContainer);
+
+ /**
+ * Returns raw HTML code to put at the end of the #topbar and #sidebar elements
+ *
+ * @param \Symfony\Component\DependencyInjection\Container $oContainer
+ *
+ * @return string
+ * @api
+ */
+ public function GetNavigationMenuHTML(\Symfony\Component\DependencyInjection\Container $oContainer);
+}
\ No newline at end of file
diff --git a/application/applicationextension/rest/RestResult.php b/application/applicationextension/rest/RestResult.php
new file mode 100644
index 000000000..e1e4c28d6
--- /dev/null
+++ b/application/applicationextension/rest/RestResult.php
@@ -0,0 +1,102 @@
+code = RestResult::OK;
+ }
+
+ /**
+ * Result code
+ * @var int
+ * @api
+ */
+ public $code;
+ /**
+ * Result message
+ * @var string
+ * @api
+ */
+ public $message;
+
+ /**
+ * Sanitize the content of this result to hide sensitive information
+ */
+ public function SanitizeContent()
+ {
+ // The default implementation does nothing
+ }
+}
\ No newline at end of file
diff --git a/application/applicationextension/rest/RestUtils.php b/application/applicationextension/rest/RestUtils.php
new file mode 100644
index 000000000..ee0bc72aa
--- /dev/null
+++ b/application/applicationextension/rest/RestUtils.php
@@ -0,0 +1,368 @@
+$sParamName)) {
+ return $oData->$sParamName;
+ } else {
+ throw new Exception("Missing parameter '$sParamName'");
+ }
+ }
+
+
+ /**
+ * Read an optional parameter from a Rest/Json structure.
+ *
+ * @param string $sParamName Name of the parameter to fetch from the input data
+ * @param mixed $default Default value if the parameter is not found in the input data
+ *
+ * @param StdClass $oData Structured input data.
+ *
+ * @return mixed
+ * @throws Exception
+ * @api
+ */
+ public static function GetOptionalParam($oData, $sParamName, $default)
+ {
+ if (isset($oData->$sParamName)) {
+ return $oData->$sParamName;
+ } else {
+ return $default;
+ }
+ }
+
+
+ /**
+ * Read a class from a Rest/Json structure.
+ *
+ * @param string $sParamName Name of the parameter to fetch from the input data
+ * @param StdClass $oData Structured input data. Must contain the entry defined by sParamName.
+ *
+ * @return string
+ * @throws Exception If the parameter is missing or the class is unknown
+ * @api
+ */
+ public static function GetClass($oData, $sParamName)
+ {
+ $sClass = self::GetMandatoryParam($oData, $sParamName);
+ if (!MetaModel::IsValidClass($sClass)) {
+ throw new Exception("$sParamName: '$sClass' is not a valid class'");
+ }
+
+ return $sClass;
+ }
+
+
+ /**
+ * Read a list of attribute codes from a Rest/Json structure.
+ *
+ * @param StdClass $oData Structured input data.
+ * @param string $sParamName Name of the parameter to fetch from the input data
+ *
+ * @param string $sClass Name of the class
+ *
+ * @return array of class => list of attributes (see RestResultWithObjects::AddObject that uses it)
+ * @throws Exception
+ * @api
+ */
+ public static function GetFieldList($sClass, $oData, $sParamName)
+ {
+ $sFields = self::GetOptionalParam($oData, $sParamName, '*');
+ $aShowFields = array();
+ if ($sFields == '*') {
+ foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) {
+ $aShowFields[$sClass][] = $sAttCode;
+ }
+ } elseif ($sFields == '*+') {
+ foreach (MetaModel::EnumChildClasses($sClass, ENUM_CHILD_CLASSES_ALL) as $sRefClass) {
+ foreach (MetaModel::ListAttributeDefs($sRefClass) as $sAttCode => $oAttDef) {
+ $aShowFields[$sRefClass][] = $sAttCode;
+ }
+ }
+ } else {
+ foreach (explode(',', $sFields) as $sAttCode) {
+ $sAttCode = trim($sAttCode);
+ if (($sAttCode != 'id') && (!MetaModel::IsValidAttCode($sClass, $sAttCode))) {
+ throw new Exception("$sParamName: invalid attribute code '$sAttCode'");
+ }
+ $aShowFields[$sClass][] = $sAttCode;
+ }
+ }
+
+ return $aShowFields;
+ }
+
+ /**
+ * Read and interpret object search criteria from a Rest/Json structure
+ *
+ * @param string $sClass Name of the class
+ * @param StdClass $oCriteria Hash of attribute code => value (can be a substructure or a scalar, depending on the nature of the
+ * attriute)
+ *
+ * @return object The object found
+ * @throws Exception If the input structure is not valid or it could not find exactly one object
+ * @api
+ */
+ protected static function FindObjectFromCriteria($sClass, $oCriteria)
+ {
+ $aCriteriaReport = array();
+ if (isset($oCriteria->finalclass)) {
+ if (!MetaModel::IsValidClass($oCriteria->finalclass)) {
+ throw new Exception("finalclass: Unknown class '" . $oCriteria->finalclass . "'");
+ }
+ if (!MetaModel::IsParentClass($sClass, $oCriteria->finalclass)) {
+ throw new Exception("finalclass: '" . $oCriteria->finalclass . "' is not a child class of '$sClass'");
+ }
+ $sClass = $oCriteria->finalclass;
+ }
+ $oSearch = new DBObjectSearch($sClass);
+ foreach ($oCriteria as $sAttCode => $value) {
+ $realValue = static::MakeValue($sClass, $sAttCode, $value);
+ $oSearch->AddCondition($sAttCode, $realValue, '=');
+ if (is_object($value) || is_array($value)) {
+ $value = json_encode($value);
+ }
+ $aCriteriaReport[] = "$sAttCode: $value ($realValue)";
+ }
+ $oSet = new DBObjectSet($oSearch);
+ $iCount = $oSet->Count();
+ if ($iCount == 0) {
+ throw new Exception("No item found with criteria: " . implode(', ', $aCriteriaReport));
+ } elseif ($iCount > 1) {
+ throw new Exception("Several items found ($iCount) with criteria: " . implode(', ', $aCriteriaReport));
+ }
+ $res = $oSet->Fetch();
+
+ return $res;
+ }
+
+
+ /**
+ * Find an object from a polymorph search specification (Rest/Json)
+ *
+ * @param mixed $key Either search criteria (substructure), or an object or an OQL string.
+ * @param bool $bAllowNullValue Allow the cases such as key = 0 or key = {null} and return null then
+ * @param string $sClass Name of the class
+ *
+ * @return DBObject The object found
+ * @throws Exception If the input structure is not valid or it could not find exactly one object
+ *
+ * @api
+ * @see DBObject::CheckChangedExtKeysValues() generic method to check that we can access the linked object isn't used in that use case because values can be literal, OQL, friendlyname
+ */
+ public static function FindObjectFromKey($sClass, $key, $bAllowNullValue = false)
+ {
+ if (is_object($key)) {
+ $res = static::FindObjectFromCriteria($sClass, $key);
+ } elseif (is_numeric($key)) {
+ if ($bAllowNullValue && ($key == 0)) {
+ $res = null;
+ } else {
+ $res = MetaModel::GetObject($sClass, $key, false);
+ if (is_null($res)) {
+ throw new Exception("Invalid object $sClass::$key");
+ }
+ }
+ } elseif (is_string($key)) {
+ // OQL
+ $oSearch = DBObjectSearch::FromOQL($key);
+ $oSet = new DBObjectSet($oSearch);
+ $iCount = $oSet->Count();
+ if ($iCount == 0) {
+ throw new Exception("No item found for query: $key");
+ } elseif ($iCount > 1) {
+ throw new Exception("Several items found ($iCount) for query: $key");
+ }
+ $res = $oSet->Fetch();
+ } else {
+ throw new Exception("Wrong format for key");
+ }
+
+ return $res;
+ }
+
+ /**
+ * Search objects from a polymorph search specification (Rest/Json)
+ *
+ * @param string $sClass Name of the class
+ * @param mixed $key Either search criteria (substructure), or an object or an OQL string.
+ * @param int $iLimit The limit of results to return
+ * @param int $iOffset The offset of results to return
+ *
+ * @return DBObjectSet The search result set
+ * @throws Exception If the input structure is not valid
+ * @api
+ */
+ public static function GetObjectSetFromKey($sClass, $key, $iLimit = 0, $iOffset = 0)
+ {
+ if (is_object($key)) {
+ if (isset($key->finalclass)) {
+ $sClass = $key->finalclass;
+ if (!MetaModel::IsValidClass($sClass)) {
+ throw new Exception("finalclass: Unknown class '$sClass'");
+ }
+ }
+
+ $oSearch = new DBObjectSearch($sClass);
+ foreach ($key as $sAttCode => $value) {
+ $realValue = static::MakeValue($sClass, $sAttCode, $value);
+ $oSearch->AddCondition($sAttCode, $realValue, '=');
+ }
+ } elseif (is_numeric($key)) {
+ $oSearch = new DBObjectSearch($sClass);
+ $oSearch->AddCondition('id', $key);
+ } elseif (is_string($key)) {
+ // OQL
+ try {
+ $oSearch = DBObjectSearch::FromOQL($key);
+ } catch (Exception $e) {
+ throw new CoreOqlException('Query failed to execute', [
+ 'query' => $key,
+ 'exception_class' => get_class($e),
+ 'exception_message' => $e->getMessage(),
+ ]);
+ }
+ } else {
+ throw new Exception("Wrong format for key");
+ }
+ $oObjectSet = new DBObjectSet($oSearch, array(), array(), null, $iLimit, $iOffset);
+
+ return $oObjectSet;
+ }
+
+ /**
+ * Interpret the Rest/Json value and get a valid attribute value
+ *
+ * @param string $sAttCode Attribute code
+ * @param mixed $value Depending on the type of attribute (a scalar, or search criteria, or list of related objects...)
+ * @param string $sClass Name of the class
+ *
+ * @return mixed The value that can be used with DBObject::Set()
+ * @throws Exception If the specification of the value is not valid.
+ * @api
+ */
+ public static function MakeValue($sClass, $sAttCode, $value)
+ {
+ try {
+ if (!MetaModel::IsValidAttCode($sClass, $sAttCode)) {
+ throw new Exception("Unknown attribute");
+ }
+ $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
+ if ($oAttDef instanceof AttributeExternalKey) {
+ $oExtKeyObject = static::FindObjectFromKey($oAttDef->GetTargetClass(), $value, true /* allow null */);
+ $value = ($oExtKeyObject != null) ? $oExtKeyObject->GetKey() : 0;
+ } elseif ($oAttDef instanceof AttributeLinkedSet) {
+ if (!is_array($value)) {
+ throw new Exception("A link set must be defined by an array of objects");
+ }
+ $sLnkClass = $oAttDef->GetLinkedClass();
+ $aLinks = array();
+ foreach ($value as $oValues) {
+ $oLnk = static::MakeObjectFromFields($sLnkClass, $oValues);
+ // Fix for N°1939
+ if (($oAttDef instanceof AttributeLinkedSetIndirect) && ($oLnk->Get($oAttDef->GetExtKeyToRemote()) == 0)) {
+ continue;
+ }
+ $aLinks[] = $oLnk;
+ }
+ $value = DBObjectSet::FromArray($sLnkClass, $aLinks);
+ } elseif ($oAttDef instanceof AttributeTagSet) {
+ if (!is_array($value)) {
+ throw new Exception("A tag set must be defined by an array of tag codes");
+ }
+ $value = $oAttDef->FromJSONToValue($value);
+ } else {
+ $value = $oAttDef->FromJSONToValue($value);
+ }
+ } catch (Exception $e) {
+ throw new Exception("$sAttCode: " . $e->getMessage(), $e->getCode());
+ }
+
+ return $value;
+ }
+
+ /**
+ * Interpret a Rest/Json structure that defines attribute values, and build an object
+ *
+ * @param array $aFields A hash of attribute code => value specification.
+ * @param string $sClass Name of the class
+ *
+ * @return DBObject The newly created object
+ * @throws Exception If the specification of the values is not valid
+ * @api
+ */
+ public static function MakeObjectFromFields($sClass, $aFields)
+ {
+ $oObject = MetaModel::NewObject($sClass);
+ foreach ($aFields as $sAttCode => $value) {
+ $realValue = static::MakeValue($sClass, $sAttCode, $value);
+ try {
+ $oObject->Set($sAttCode, $realValue);
+ } catch (Exception $e) {
+ throw new Exception("$sAttCode: " . $e->getMessage(), $e->getCode());
+ }
+ }
+
+ return $oObject;
+ }
+
+ /**
+ * Interpret a Rest/Json structure that defines attribute values, and update the given object
+ *
+ * @param array $aFields A hash of attribute code => value specification.
+ * @param DBObject $oObject The object being modified
+ *
+ * @return DBObject The object modified
+ * @throws Exception If the specification of the values is not valid
+ * @api
+ */
+ public static function UpdateObjectFromFields($oObject, $aFields)
+ {
+ $sClass = get_class($oObject);
+ foreach ($aFields as $sAttCode => $value) {
+ $realValue = static::MakeValue($sClass, $sAttCode, $value);
+ try {
+ $oObject->Set($sAttCode, $realValue);
+ } catch (Exception $e) {
+ throw new Exception("$sAttCode: " . $e->getMessage(), $e->getCode());
+ }
+ }
+
+ return $oObject;
+ }
+}
\ No newline at end of file
diff --git a/application/applicationextension/rest/iRestInputSanitizer.php b/application/applicationextension/rest/iRestInputSanitizer.php
new file mode 100644
index 000000000..4b7765df8
--- /dev/null
+++ b/application/applicationextension/rest/iRestInputSanitizer.php
@@ -0,0 +1,12 @@
+ verb, 'description' => description
+ * @api
+ */
+ public function ListOperations($sVersion);
+
+ /**
+ * Enumerate services delivered by this class
+ *
+ * @param string $sVersion The version (e.g. 1.0) supported by the services
+ * @param string $sVerb
+ * @param array $aParams
+ *
+ * @return RestResult The standardized result structure (at least a message)
+ * @api
+ */
+ public function ExecOperation($sVersion, $sVerb, $aParams);
+}
\ No newline at end of file