Source of file AdminFormgenerator.php
Size: 29,125 Bytes - Last Modified: 2016-05-18T03:08:27+02:00
buildproject/core/module_system/admin/AdminFormgenerator.php
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868 | <?php /*"****************************************************************************************************** * (c) 2007-2016 by Kajona, www.kajona.de * * Published under the GNU LGPL v2.1, see /system/licence_lgpl.txt * *-------------------------------------------------------------------------------------------------------* * $Id$ * ********************************************************************************************************/ namespace Kajona\System\Admin; use Kajona\System\Admin\Formentries\FormentryBase; use Kajona\System\Admin\Formentries\FormentryDivider; use Kajona\System\Admin\Formentries\FormentryHeadline; use Kajona\System\Admin\Formentries\FormentryHidden; use Kajona\System\Admin\Formentries\FormentryPlaintext; use Kajona\System\System\Carrier; use Kajona\System\System\Exception; use Kajona\System\System\Lang; use Kajona\System\System\Model; use Kajona\System\System\ModelInterface; use Kajona\System\System\Reflection; use Kajona\System\System\ReflectionEnum; use Kajona\System\System\Resourceloader; use Kajona\System\System\UserUser; use Kajona\System\System\ValidatorInterface; use Kajona\System\System\Validators\ObjectvalidatorBase; use Kajona\System\System\Validators\SystemidValidator; /** * The admin-form generator is used to create, validate and manage forms for the backend. * Those forms are created as automatically as possible, so the setup of the field-types, validators * and more is done by reflection and code-inspection. Therefore, especially the annotations on the extending * \Kajona\System\System\Model-objects are analyzed. * * There are three ways of adding entries to the current form, each representing a different level of * automation. * 1. generateFieldsFromObject(), everything is rendered automatically * 2. addDynamicField(), adds a single field based on its name * 3. addField(), pass a field to add it explicitly * * @author sidler@mulchprod.de * @since 4.0 * @module module_formgenerator */ class AdminFormgenerator { const STR_METHOD_POST = "POST"; const STR_METHOD_GET = "GET"; const STR_TYPE_ANNOTATION = "@fieldType"; const STR_VALIDATOR_ANNOTATION = "@fieldValidator"; const STR_MANDATORY_ANNOTATION = "@fieldMandatory"; const STR_LABEL_ANNOTATION = "@fieldLabel"; const STR_HIDDEN_ANNOTATION = "@fieldHidden"; const STR_READONLY_ANNOTATION = "@fieldReadonly"; const STR_OBJECTVALIDATOR_ANNOTATION = "@objectValidator"; const BIT_BUTTON_SAVE = 2; const BIT_BUTTON_CLOSE = 4; const BIT_BUTTON_CANCEL = 8; const BIT_BUTTON_SUBMIT = 16; const BIT_BUTTON_DELETE = 32; const BIT_BUTTON_RESET = 64; const BIT_BUTTON_CONTINUE = 128; const BIT_BUTTON_BACK = 256; const FORM_ENCTYPE_MULTIPART = "multipart/form-data"; const FORM_ENCTYPE_TEXTPLAIN = "text/plain"; /** * The list of form-entries * * @var FormentryBase[]|FormentryInterface[] */ private $arrFields = array(); /** * The internal name of the form. Used to generate the field-identifiers and more. * * @var string */ private $strFormname = ""; /** * The source-object to be rendered by the form * * @var Model */ private $objSourceobject = null; private $arrValidationErrors = array(); private $arrHiddenElements = array(); private $strHiddenGroupTitle = "additional fields"; private $bitHiddenElementsVisible = false; private $strFormEncoding = ""; private $strOnSubmit = ""; private $strMethod = "POST"; private $objLang; /** * Creates a new instance of the form-generator. * * @param string $strFormname * @param Model $objSourceobject */ public function __construct($strFormname, $objSourceobject) { $this->strFormname = $strFormname; $this->objSourceobject = $objSourceobject; $this->strOnSubmit = "$(this).on('submit', function() { return false; }); $(window).off('unload'); KAJONA.admin.forms.animateSubmit(this); return true;"; $this->objLang = Lang::getInstance(); } /** * Stores the values saved with the params-array back to the currently associated object. * Afterwards, the object may be persisted. * * @return void */ public function updateSourceObject() { foreach ($this->arrFields as $objOneField) { if ($objOneField->getObjSourceObject() != null) { $objOneField->setValueToObject(); } } } /** * Returns an array of required fields. * * @return string[] where string[fielName] = type */ public function getRequiredFields() { $arrReturn = array(); foreach ($this->arrFields as $objOneField) { if ($objOneField->getBitMandatory()) { $arrReturn[$objOneField->getStrEntryName()] = get_class($objOneField->getObjValidator()); } } return $arrReturn; } /** * Validates the current form. * * @throws Exception * @return bool */ public function validateForm() { $objLang = Carrier::getInstance()->getObjLang(); //1. Validate fields foreach ($this->arrFields as $objOneField) { $bitFieldIsEmpty = (!is_array($objOneField->getStrValue()) && trim($objOneField->getStrValue()) === "") || is_null($objOneField->getStrValue()) || (is_array($objOneField->getStrValue()) && count($objOneField->getStrValue()) == 0); //if it is an array with no entries //mandatory field if ($objOneField->getBitMandatory()) { //if field is mandatory and empty -> validation error if ($bitFieldIsEmpty) { $this->addValidationError($objOneField->getStrEntryName(), $objLang->getLang("commons_validator_field_empty", "system", array($objOneField->getStrLabel()))); } } //if field is not empty -> validate if (!$bitFieldIsEmpty) { if (!$objOneField->validateValue()) { $this->addValidationError($objOneField->getStrEntryName(), $objOneField->getStrValidationErrorMsg()); } } } //2. Validate complete object if ($this->getObjSourceobject() != null) { $objReflection = new Reflection($this->getObjSourceobject()); $arrObjectValidator = $objReflection->getAnnotationValuesFromClass(self::STR_OBJECTVALIDATOR_ANNOTATION); if (count($arrObjectValidator) == 1) { $strObjectValidator = $arrObjectValidator[0]; if (!class_exists($strObjectValidator)) { throw new Exception("object validator ".$strObjectValidator." not existing", Exception::$level_ERROR); } /** @var ObjectvalidatorBase $objValidator */ $objValidator = new $strObjectValidator(); //Keep the reference of the current object $objSourceObjectTemp = $this->getObjSourceobject(); //Create a new instance of the source object and set it as source object in the formgenerator //Each existing field will also reference the new created source object $strClassName = get_class($this->objSourceobject); $this->objSourceobject = new $strClassName($this->objSourceobject->getStrSystemid()); foreach ($this->arrFields as $objOneField) { if ($objOneField->getObjSourceObject() != null) { $objOneField->setObjSourceObject($this->objSourceobject); } } //if we are in new-mode, we should fix the prev-id to the lateron matching one if (($this->getField("mode") != null && $this->getField("mode")->getStrValue() == "new") || Carrier::getInstance()->getParam("mode") == "new") { $this->objSourceobject->setStrPrevId(Carrier::getInstance()->getParam("systemid")); } //Update the new source object values from the fields and validate the object $this->updateSourceObject(); $objValidator->validateObject($this->getObjSourceobject()); foreach ($objValidator->getArrValidationMessages() as $strKey => $arrMessages) { if (!is_array($arrMessages)) { throw new Exception("method validateObject must return an array of format array(\"<messageKey>\" => array())", Exception::$level_ERROR); } foreach ($arrMessages as $strMessage) { $this->addValidationError($strKey, $strMessage); } } //Set back kept reference to the formgenerator and all it's fields $this->objSourceobject = $objSourceObjectTemp; foreach ($this->arrFields as $objOneField) { if ($objOneField->getObjSourceObject() != null) { $objOneField->setObjSourceObject($objSourceObjectTemp); } } } } return count($this->arrValidationErrors) == 0; } /** * @param string $strTargetURI If you pass null, no form-tags will be rendered. * @param int $intButtonConfig a list of buttons to attach to the end of the form. if you need more then the obligatory save-button, * pass them combined by a bitwise or, e.g. AdminFormgenerator::BIT_BUTTON_SAVE | AdminFormgenerator::$BIT_BUTTON_CANCEL * * @throws Exception * @return string */ public function renderForm($strTargetURI, $intButtonConfig = 2) { $strReturn = ""; //add a hidden systemid-field if ($this->objSourceobject != null && $this->objSourceobject instanceof Model) { $objField = new FormentryHidden($this->strFormname, "systemid"); $objField->setStrEntryName("systemid")->setStrValue($this->objSourceobject->getSystemid())->setObjValidator(new SystemidValidator()); $this->addField($objField); } $strGeneratedFormname = $this->strFormname; if($strGeneratedFormname == null) { $strGeneratedFormname = "form".generateSystemid(); } $objToolkit = Carrier::getInstance()->getObjToolkit("admin"); if ($strTargetURI !== null) { $strReturn .= $objToolkit->formHeader($strTargetURI, $strGeneratedFormname, $this->strFormEncoding, $this->strOnSubmit, $this->strMethod); } $strReturn .= $objToolkit->getValidationErrors($this); $strHidden = ""; foreach ($this->arrFields as $objOneField) { if (in_array($objOneField->getStrEntryName(), $this->arrHiddenElements)) { $strHidden .= $objOneField->renderField(); } else { $strReturn .= $objOneField->renderField(); } } if ($strHidden != "") { $strReturn .= $objToolkit->formOptionalElementsWrapper($strHidden, $this->strHiddenGroupTitle, $this->bitHiddenElementsVisible); } $strButtons = ""; if ($intButtonConfig & self::BIT_BUTTON_SUBMIT) { $strButtons .= $objToolkit->formInputSubmit(Lang::getInstance()->getLang("commons_submit", "system"), "submitbtn", "", "", true, false); } if ($intButtonConfig & self::BIT_BUTTON_SAVE) { $strButtons .= $objToolkit->formInputSubmit(Lang::getInstance()->getLang("commons_save", "system"), "submitbtn", "", "", true, false); } if ($intButtonConfig & self::BIT_BUTTON_CANCEL) { $strButtons .= $objToolkit->formInputSubmit(Lang::getInstance()->getLang("commons_cancel", "system"), "cancelbtn", "", "", true, false); } if ($intButtonConfig & self::BIT_BUTTON_CLOSE) { $strButtons .= $objToolkit->formInputSubmit(Lang::getInstance()->getLang("commons_close", "system"), "closebtn", "", "", true, false); } if ($intButtonConfig & self::BIT_BUTTON_DELETE) { $strButtons .= $objToolkit->formInputSubmit(Lang::getInstance()->getLang("commons_delete", "system"), "deletebtn", "", "", true, false); } if ($intButtonConfig & self::BIT_BUTTON_RESET) { $strButtons .= $objToolkit->formInputSubmit(Lang::getInstance()->getLang("commons_reset", "system"), "reset", "", "cancelbutton", true, false); } if ($intButtonConfig & self::BIT_BUTTON_CONTINUE) { $strButtons .= $objToolkit->formInputSubmit(Lang::getInstance()->getLang("commons_continue", "system"), "continuebtn", "", "", true, false); } if ($intButtonConfig & self::BIT_BUTTON_BACK) { $strButtons .= $objToolkit->formInputSubmit(Lang::getInstance()->getLang("commons_back", "system"), "backbtn", "", "", true, false); } $strReturn .= $objToolkit->formInputButtonWrapper($strButtons); if ($strTargetURI !== null) { $strReturn .= $objToolkit->formClose(); } if (count($this->arrFields) > 0) { reset($this->arrFields); do { $objField = current($this->arrFields); if (!$objField instanceof FormentryHidden && !$objField instanceof FormentryPlaintext && !$objField instanceof FormentryHeadline && !$objField instanceof FormentryDivider ) { $strReturn .= $objToolkit->setBrowserFocus($objField->getStrEntryName()); break; } } while (next($this->arrFields) !== false); } //lock the record to avoid multiple edit-sessions - if in edit mode if ($this->objSourceobject != null && method_exists($this->objSourceobject, "getLockManager")) { $bitSkip = false; if ($this->getField("mode") != null && $this->getField("mode")->getStrValue() == "new") { $bitSkip = true; } if (!$bitSkip && !validateSystemid($this->objSourceobject->getSystemid())) { $bitSkip = true; } if (!$bitSkip) { if ($this->objSourceobject->getLockManager()->isAccessibleForCurrentUser()) { $this->objSourceobject->getLockManager()->lockRecord(); //register a new unlock-handler // KAJONA.admin.ajax.genericAjaxCall('system', 'unlockRecord', '".$this->objSourceobject->getSystemid()."'); $strReturn .= "<script type='text/javascript'> $(window).on('unload', function() { $.ajax({url: KAJONA_WEBPATH + '/xml.php?admin=1&module=system&action=unlockRecord&systemid=".$this->objSourceobject->getSystemid()."', async:false}) ; }); // $('#{$strGeneratedFormname}').on('submit', function() { $(window).off('unload'); return true;}); </script>"; } else { $objUser = new UserUser($this->objSourceobject->getLockManager()->getLockId()); throw new Exception("Current record is already locked by user '".$objUser->getStrDisplayName()."'.\nCannot be locked for the current user", Exception::$level_ERROR); } } } return $strReturn; } /** * This is the most dynamically way to build a form. * Using this method, the current object is analyzed regarding its * methods and annotation. As soon as a matching property is found, the field * is added to the current list of form-entries. * Therefore the internal method addDynamicField is used. * In order to identify a field as relevant, the getter has to be marked with a fieldType annotation. * * @return void */ public function generateFieldsFromObject() { //load all methods $objAnnotations = new Reflection($this->objSourceobject); $arrProperties = $objAnnotations->getPropertiesWithAnnotation("@fieldType"); foreach ($arrProperties as $strPropertyName => $strDataType) { $this->addDynamicField($strPropertyName); } return; } /** * Adds a new field to the current form. * Therefore, the current source-object is inspected regarding the passed propertyname. * So it is essential to provide the matching getters and setters in order to have all * set up dynamically. * * @param string $strPropertyName * * @return FormentryBase|FormentryInterface * @throws Exception */ public function addDynamicField($strPropertyName) { //try to get the matching getter $objReflection = new Reflection($this->objSourceobject); $strGetter = $objReflection->getGetter($strPropertyName); if ($strGetter === null) { throw new Exception("unable to find getter for property ".$strPropertyName."@".get_class($this->objSourceobject), Exception::$level_ERROR); } //load detailed properties $strType = $objReflection->getAnnotationValueForProperty($strPropertyName, self::STR_TYPE_ANNOTATION); $strValidator = $objReflection->getAnnotationValueForProperty($strPropertyName, self::STR_VALIDATOR_ANNOTATION); $strMandatory = $objReflection->getAnnotationValueForProperty($strPropertyName, self::STR_MANDATORY_ANNOTATION); $strLabel = $objReflection->getAnnotationValueForProperty($strPropertyName, self::STR_LABEL_ANNOTATION); $strHidden = $objReflection->getAnnotationValueForProperty($strPropertyName, self::STR_HIDDEN_ANNOTATION); $strReadonly = $objReflection->getAnnotationValueForProperty($strPropertyName, self::STR_READONLY_ANNOTATION); if ($strType === null) { $strType = "text"; } $strPropertyName = Lang::getInstance()->propertyWithoutPrefix($strPropertyName); $objField = $this->getFormEntryInstance($strType, $strPropertyName); if ($strLabel !== null) { $objField->updateLabel($strLabel); } $bitMandatory = false; if ($strMandatory !== null && $strMandatory !== "false") { $bitMandatory = true; } $objField->setBitMandatory($bitMandatory); $bitReadonly = false; if ($strReadonly !== null && $strReadonly !== "false") { $bitReadonly = true; } $objField->setBitReadonly($bitReadonly); if ($strValidator !== null) { $objField->setObjValidator($this->getValidatorInstance($strValidator)); } $this->addField($objField, $strPropertyName); if ($strHidden !== null) { $this->addFieldToHiddenGroup($objField); } return $objField; } /** * Set the position of a single field in the list of fields, so * the position inside the form. * The position is set human-readable, so the first element uses * the index 1. * * @param string $strField * @param int $intPos * * @throws Exception * @return void */ public function setFieldToPosition($strField, $intPos) { if (!isset($this->arrFields[$strField])) { throw new Exception("field ".$strField." not found in list ".implode(", ", array_keys($this->arrFields)), Exception::$level_ERROR); } $objField = $this->arrFields[$strField]; $arrNewOrder = array(); $intI = 1; foreach ($this->arrFields as $strKey => $objValue) { //skip the same field, is inserted somewhere else if ($strKey == $strField) { continue; } if ($intI == $intPos) { $arrNewOrder[$strField] = $objField; $objField = null; } $arrNewOrder[$strKey] = $objValue; $intI++; } if ($objField !== null) { $arrNewOrder[$strField] = $objField; } $this->arrFields = $arrNewOrder; } /** * Loads the field-entry identified by the passed name. * * @param string $strName * @param string $strPropertyname * * @return FormentryBase|FormentryInterface * @throws Exception */ private function getFormEntryInstance($strName, $strPropertyname) { //backslash given? //the V5 way: namespaces if(uniStrpos($strName, "\\") !== false) { $strClassname = $strName; } else { //backwards support for v4 $strClassname = "class_formentry_".$strName; $strPath = Resourceloader::getInstance()->getPathForFile("/admin/formentries/".$strClassname.".php"); if(!$strPath) { $strPath = Resourceloader::getInstance()->getPathForFile("/legacy/".$strClassname.".php"); if($strPath == null) { $strClassname = null; } } } if ($strClassname !== null) { return new $strClassname($this->strFormname, $strPropertyname, $this->objSourceobject); } else { throw new Exception("failed to load form-entry of type ".$strClassname, Exception::$level_ERROR); } } /** * Loads the validator identified by the passed name. * * @param string $strClassname * * @throws Exception * @return ValidatorInterface */ private function getValidatorInstance($strClassname) { if (class_exists($strClassname)) { return new $strClassname(); } if (uniStrpos($strClassname, "class_") === false) { $strClassname = "class_".$strClassname."_validator"; } if (Resourceloader::getInstance()->getPathForFile("/system/validators/".$strClassname.".php")) { return new $strClassname(); } else { throw new Exception("failed to load validator of type ".$strClassname, Exception::$level_ERROR); } } /** * Returns an language text. By default the formname is used as module name * * @param string $strText * * @param null $strModule * * @return string */ protected function getLang($strText, $strModule = null, array $arrParameters = array()) { return $this->objLang->getLang($strText, $strModule === null ? $this->strFormname : $strModule, $arrParameters); } /** * Returns an array of validation-errors * * @return array */ public function getArrValidationErrors() { return $this->arrValidationErrors; } /** * Returns an array of validation-errors. * Alias for getArrValidationErrors due to backwards compatibility. * * @return array * @see getArrValidationErrors */ public function getValidationErrors() { return $this->getArrValidationErrors(); } /** * Adds an additional, user-specific validation-error to the current list of errors. * * @param string $strEntry * @param string $strMessage * * @return void */ public function addValidationError($strEntry, $strMessage) { if (!array_key_exists($strEntry, $this->arrValidationErrors)) { $this->arrValidationErrors[$strEntry] = array(); } $this->arrValidationErrors[$strEntry][] = $strMessage; } /** * Removes a single validation error * * @param string $strEntry * * @return void */ public function removeValidationError($strEntry) { if (isset($this->arrValidationErrors[$strEntry])) { unset($this->arrValidationErrors[$strEntry]); } } /** * Clear all validation errors in the form */ public function removeAllValidationError() { $this->arrValidationErrors = array(); } /** * Adds a single field to the current form, the hard, manual way. * Use this method if you want to add custom fields to the current form. * * @param FormentryBase $objField * @param string $strKey * * @return FormentryBase|FormentryInterface */ public function addField(FormentryBase $objField, $strKey = "") { if ($strKey == "") { $strKey = $objField->getStrEntryName(); } $this->arrFields[$strKey] = $objField; return $objField; } /** * Returns a single entry form the fields, identified by its form-entry-name. * * @param string $strName * * @return FormentryBase|FormentryInterface */ public function getField($strName) { if (isset($this->arrFields[$strName])) { return $this->arrFields[$strName]; } else { return null; } } /** * Orders the fields by the given array. * The array must contain as values the keys of the form fields * * @param $arrFieldOrder * @return int * @throws Exception */ public function orderFields($arrFieldOrder) { $intPosition = 1; foreach($arrFieldOrder as $strFieldName) { if($this->getField($strFieldName) != null) { $this->setFieldToPosition($strFieldName, $intPosition); $intPosition++; } } return $intPosition; } /** * Removes a single entry form the fields, identified by its form-entry-name. * * @param string $strName * * @return $this */ public function removeField($strName) { unset($this->arrFields[$strName]); return $this; } /** * Sets the name of the group of hidden elements * * @param string $strHiddenGroupTitle * * @return $this */ public function setStrHiddenGroupTitle($strHiddenGroupTitle) { $this->strHiddenGroupTitle = $strHiddenGroupTitle; return $this; } /** * Moves a single field to the list of hidden elements * * @param FormentryBase $objField * * @return FormentryBase */ public function addFieldToHiddenGroup(FormentryBase $objField) { $this->arrHiddenElements[] = $objField->getStrEntryName(); if (!isset($this->arrFields[$objField->getStrEntryName()]) && !isset($this->arrFields[$objField->getStrSourceProperty()])) { $this->addField($objField); } return $objField; } /** * Makes the group of hidden elements visible or hides the content on page-load * * @param bool $bitHiddenElementsVisible * * @return void */ public function setBitHiddenElementsVisible($bitHiddenElementsVisible) { $this->bitHiddenElementsVisible = $bitHiddenElementsVisible; } /** * @return Model|ModelInterface */ public function getObjSourceobject() { return $this->objSourceobject; } /** * @param Model|ModelInterface $objSource */ protected function setObjSourceobject($objSource) { $this->objSourceobject = $objSource; } /** * @return FormentryBase[]|FormentryInterface[] */ public function getArrFields() { return $this->arrFields; } /** * Allows to inject an onsubmit handler * * @param string $strOnSubmit * * @return void */ public function setStrOnSubmit($strOnSubmit) { $this->strOnSubmit = $strOnSubmit; } /** * @return string */ public function getStrOnSubmit() { return $this->strOnSubmit; } /** * @param string $strFormEncoding * * @return void */ public function setStrFormEncoding($strFormEncoding) { $this->strFormEncoding = $strFormEncoding; } /** * @return string */ public function getStrFormEncoding() { return $this->strFormEncoding; } /** * @return string */ public function getStrFormname() { return $this->strFormname; } /** * @param string $strMethod * @throws Exception */ public function setStrMethod($strMethod) { if (in_array($strMethod, array(self::STR_METHOD_GET, self::STR_METHOD_POST))) { $this->strMethod = $strMethod; } else { throw new Exception("Invalid form method", Exception::$level_ERROR); } } /** * @return string */ public function getStrMethod() { return $this->strMethod; } } |