From bcf679570d2e285ffd0f87097a3abf341cccc3d8 Mon Sep 17 00:00:00 2001 From: Ad Schellevis Date: Sat, 12 May 2018 16:30:08 +0200 Subject: [PATCH] MVC, add support for application specific field types. Some field validations tend to be very application specific, in which case it would be easier to add specific field types then trying to expand the common field type set too much. This patch provides support for specific field types, as long as they are derived from OPNsense\Base\FieldTypes\BaseField in two forms, either a full path or a FieldTypes module within the current namespace using .\ --- .../app/models/OPNsense/Base/BaseModel.php | 29 +++++++++++++++---- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/src/opnsense/mvc/app/models/OPNsense/Base/BaseModel.php b/src/opnsense/mvc/app/models/OPNsense/Base/BaseModel.php index b0cded4d0..67ce12c62 100644 --- a/src/opnsense/mvc/app/models/OPNsense/Base/BaseModel.php +++ b/src/opnsense/mvc/app/models/OPNsense/Base/BaseModel.php @@ -111,15 +111,17 @@ abstract class BaseModel /** * fetch reflection class (cached by field type) * @param $classname classname to construct - * @return array - * @throws ModelException + * @return BaseField type class + * @throws ModelException when unable to parse field type + * @throws \ReflectionException when unable to create class */ private function getNewField($classname) { if (self::$internalCacheReflectionClasses === null) { self::$internalCacheReflectionClasses = array(); } - if (!isset(self::$internalCacheReflectionClasses[$classname])) { + $classname_idx = str_replace("\\", "_", $classname); + if (!isset(self::$internalCacheReflectionClasses[$classname_idx])) { $is_derived_from_basefield = false; if (class_exists($classname)) { $field_rfcls = new \ReflectionClass($classname); @@ -136,9 +138,9 @@ abstract class BaseModel // class found, but of wrong type. raise an exception. throw new ModelException("class ".$field_rfcls->name." of wrong type in model definition"); } - self::$internalCacheReflectionClasses[$classname] = $field_rfcls; + self::$internalCacheReflectionClasses[$classname_idx] = $field_rfcls; } - return self::$internalCacheReflectionClasses[$classname]; + return self::$internalCacheReflectionClasses[$classname_idx]; } /** @@ -165,7 +167,22 @@ abstract class BaseModel $xmlNodeType = $xmlNode->attributes()["type"]; if (!empty($xmlNodeType)) { // construct field type object - $field_rfcls = $this->getNewField("OPNsense\\Base\\FieldTypes\\".$xmlNodeType); + if (strpos($xmlNodeType, "\\") !== false) { + // application specific field type contains path separator + if (strpos($xmlNodeType, ".\\") === 0) { + // use current namespace (.\Class) + $namespace = explode("\\" , get_class($this)); + array_pop($namespace); + $namespace = implode("\\", $namespace); + $classname = str_replace(".\\",$namespace."\\FieldTypes\\", (string)$xmlNodeType); + } else { + $classname = (string)$xmlNodeType; + } + $field_rfcls = $this->getNewField($classname); + } else { + // standard field type + $field_rfcls = $this->getNewField("OPNsense\\Base\\FieldTypes\\".$xmlNodeType); + } } else { // no type defined, so this must be a standard container (without content) $field_rfcls = $this->getNewField('OPNsense\Base\FieldTypes\ContainerField');