diff --git a/src/opnsense/mvc/app/controllers/OPNsense/Sample/PageController.php b/src/opnsense/mvc/app/controllers/OPNsense/Sample/PageController.php
index acf8da865..f191cd746 100644
--- a/src/opnsense/mvc/app/controllers/OPNsense/Sample/PageController.php
+++ b/src/opnsense/mvc/app/controllers/OPNsense/Sample/PageController.php
@@ -46,6 +46,7 @@ class PageController extends ControllerBase
$sample = new Sample();
$this->view->title = $sample->title;
$this->view->items = array(array('field_name' =>'test', 'field_content'=>'1234567','field_type'=>"text") );
+ $this->view->data = $sample ;
// Pass the $postId parameter to the view
//$this->view->setVar("postId", $postId);
diff --git a/src/opnsense/mvc/app/models/OPNsense/Base/BaseModel.php b/src/opnsense/mvc/app/models/OPNsense/Base/BaseModel.php
new file mode 100644
index 000000000..a9478dd71
--- /dev/null
+++ b/src/opnsense/mvc/app/models/OPNsense/Base/BaseModel.php
@@ -0,0 +1,215 @@
+children() as $xmlNode) {
+ $tagName = $xmlNode->getName();
+ // every item results in a Field type object, the first step is to determine which object to create
+ // based on the input model spec
+ $fieldObject = null ;
+ $classname = "OPNsense\\Base\\FieldTypes\\".$xmlNode->attributes()["type"];
+ if (class_exists($classname)) {
+ // construct field type object
+ $field_rfcls = new \ReflectionClass($classname);
+ if (!$field_rfcls->getParentClass()->name == 'OPNsense\Base\FieldTypes\BaseField') {
+ // class found, but of wrong type. raise an exception.
+ throw new ModelException("class ".$field_rfcls->name." of wrong type in model definition");
+ }
+ } else {
+ // no type defined, so this must be a standard container (without content)
+ $field_rfcls = new \ReflectionClass('OPNsense\Base\FieldTypes\ContainerField');
+ }
+
+ // generate full object name ( section.section.field syntax ) and create new Field
+ if ($internal_data->__reference == "") {
+ $new_ref = $tagName;
+ } else {
+ $new_ref = $internal_data->__reference . "." . $tagName;
+ }
+ $fieldObject = $field_rfcls->newInstance($new_ref);
+
+ // now add content to this model (recursive)
+ if ($fieldObject->isContainer() == false) {
+ $internal_data->addChildNode($tagName, $fieldObject);
+ if ($xmlNode->count() > 0) {
+ // if fieldtype contains properties, try to call the setters
+ foreach ($xmlNode->children() as $fieldMethod) {
+ $param_value = $fieldMethod->__toString() ;
+ $method_name = "set".$fieldMethod->getName();
+ if ($field_rfcls->hasMethod($method_name)) {
+ $fieldObject->$method_name($param_value);
+ }
+ }
+ }
+ if ($config_data != null && isset($config_data->$tagName)) {
+ // set field content from config (if available)
+ $fieldObject->setValue($config_data->$tagName->__toString());
+ }
+
+ } else {
+ // add new child node container, always try to pass config data
+ if ($config_data != null && isset($config_data->$tagName)) {
+ $config_section_data = $config_data->$tagName;
+ } else {
+ $config_section_data = null ;
+ }
+
+ if ($fieldObject instanceof ArrayField) {
+ // handle Array types, recurring items
+ if ($config_section_data != null) {
+ $counter = 0 ;
+ foreach ($config_section_data as $conf_section) {
+ $child_node = new ArrayField($fieldObject->__reference . "." . ($counter++));
+ $this->parseXml($xmlNode, $conf_section, $child_node);
+ $fieldObject->addChildNode(null, $child_node);
+ }
+ } else {
+ $child_node = new ArrayField($fieldObject->__reference . ".0");
+ $child_node->setInternalEmptyStatus(true);
+ $this->parseXml($xmlNode, $config_section_data, $child_node);
+ $fieldObject->addChildNode(null, $child_node);
+ }
+ } else {
+ $this->parseXml($xmlNode, $config_section_data, $fieldObject);
+ }
+
+ $internal_data->addChildNode($xmlNode->getName(), $fieldObject);
+ }
+
+ }
+
+ }
+
+ /**
+ * Construct new model type, using it's own xml template
+ * @throws ModelException if the model xml is not found or invalid
+ */
+ public function __construct()
+ {
+ // setup config handle to singleton config singleton
+ $this->internalConfigHandle = Config::getInstance();
+
+ // init new root node, all details are linked to this
+ $this->internalData = new FieldTypes\ContainerField();
+
+ // determine our caller's filename and try to find the model definition xml
+ // throw error on failure
+ $class_info = new \ReflectionClass($this);
+ $model_filename = substr($class_info->getFileName(), 0, strlen($class_info->getFileName())-3) . "xml" ;
+ if (!file_exists($model_filename)) {
+ throw new ModelException('model xml '.$model_filename.' missing') ;
+ }
+ $model_xml = simplexml_load_file($model_filename);
+ if ($model_xml === false) {
+ throw new ModelException('model xml '.$model_filename.' not valid') ;
+ }
+ if ($model_xml->getName() != "model") {
+ throw new ModelException('model xml '.$model_filename.' seems to be of wrong type') ;
+ }
+
+ // use an xpath expression to find the root of our model in the config.xml file
+ // if found, convert the data to a simple structure (or create an empty array)
+ $tmp_config_data = $this->internalConfigHandle->xpath($model_xml->mount);
+ if ($tmp_config_data->length > 0) {
+ $config_array = simplexml_import_dom($tmp_config_data->item(0)) ;
+ } else {
+ $config_array = array();
+ }
+
+ // We've loaded the model template, now let's parse it into this object
+ $this->parseXml($model_xml->items, $config_array, $this->internalData) ;
+
+ //print_r($this->internalData);
+
+ // call Model initializer
+ $this->init();
+ }
+
+ /**
+ * reflect getter to internalData (ContainerField)
+ * @param $name property name
+ * @return mixed
+ */
+ public function __get($name)
+ {
+ return $this->internalData->$name;
+ }
+
+ /**
+ * reflect setter to internalData (ContainerField)
+ * @param $name property name
+ * @param $value property value
+ */
+ public function __set($name, $value)
+ {
+ $this->internalData->$name = $value ;
+ }
+
+}
\ No newline at end of file
diff --git a/src/opnsense/mvc/app/models/OPNsense/Base/FieldTypes/ArrayField.php b/src/opnsense/mvc/app/models/OPNsense/Base/FieldTypes/ArrayField.php
new file mode 100644
index 000000000..67b3797f3
--- /dev/null
+++ b/src/opnsense/mvc/app/models/OPNsense/Base/FieldTypes/ArrayField.php
@@ -0,0 +1,72 @@
+internalChildnodes[] = $node;
+ } else {
+ $this->internalChildnodes[$name] = $node;
+ }
+ }
+
+ /**
+ * @return bool is empty array (only filled for template structure)
+ */
+ public function isEmpty()
+ {
+ return $this->internalEmptyStatus;
+ }
+
+ /**
+ * @param $status|bool set empty (status boolean)
+ */
+ public function setInternalEmptyStatus($status)
+ {
+ $this->internalEmptyStatus = $status ;
+ }
+}
\ No newline at end of file
diff --git a/src/opnsense/mvc/app/models/OPNsense/Base/FieldTypes/BaseField.php b/src/opnsense/mvc/app/models/OPNsense/Base/FieldTypes/BaseField.php
new file mode 100644
index 000000000..b7d79d817
--- /dev/null
+++ b/src/opnsense/mvc/app/models/OPNsense/Base/FieldTypes/BaseField.php
@@ -0,0 +1,149 @@
+internalIsContainer;
+ }
+
+ /**
+ * default constructor
+ * @param null|string $ref direct reference to this object
+ */
+ public function __construct($ref = null)
+ {
+ $this->internalReference = $ref;
+ }
+
+ /**
+ * @param $name property name
+ * @param $node content (must be of type BaseField)
+ */
+ public function addChildNode($name, $node)
+ {
+ $this->internalChildnodes[$name] = $node;
+ }
+
+ /**
+ * Reflect default getter to internal child nodes.
+ * Implements the special attribute __items to return all items and __reference to identify the field in this model.
+ * @param $name property name
+ * @return mixed
+ */
+ public function __get($name)
+ {
+ if (array_key_exists($name, $this->internalChildnodes)) {
+ return $this->internalChildnodes[$name];
+ } elseif ($name == '__items') {
+ return $this->internalChildnodes;
+ } elseif ($name == '__reference') {
+ return $this->internalReference;
+ } else {
+ // not found
+ return null;
+ }
+
+ }
+
+ /**
+ * reflect default setter to internal child nodes
+ * @param $name|string property name
+ * @param $value|string property value
+ */
+ public function __set($name, $value)
+ {
+ if (array_key_exists($name, $this->internalChildnodes)) {
+ $this->internalChildnodes[$name]->setValue($value);
+ }
+ }
+
+ public function __toString()
+ {
+ return $this->internalValue;
+ }
+
+ /**
+ * set Default field value
+ * @param $value default value
+ */
+ public function setDefault($value)
+ {
+ $this->internalValue = $value;
+ }
+
+ /**
+ * default setter
+ * @param $value set field value
+ */
+ public function setValue($value)
+ {
+ $this->internalValue = $value;
+ }
+
+ /**
+ * @return array child items
+ */
+ public function getChildren()
+ {
+ return $this->internalChildnodes;
+ }
+
+}
\ No newline at end of file
diff --git a/src/opnsense/mvc/app/models/OPNsense/Base/FieldTypes/ContainerField.php b/src/opnsense/mvc/app/models/OPNsense/Base/FieldTypes/ContainerField.php
new file mode 100644
index 000000000..c37819150
--- /dev/null
+++ b/src/opnsense/mvc/app/models/OPNsense/Base/FieldTypes/ContainerField.php
@@ -0,0 +1,37 @@
+internalMask = $value ;
+ }
+}
\ No newline at end of file
diff --git a/src/opnsense/mvc/app/models/OPNsense/Base/Model.php b/src/opnsense/mvc/app/models/OPNsense/Base/ModelException.php
similarity index 86%
rename from src/opnsense/mvc/app/models/OPNsense/Base/Model.php
rename to src/opnsense/mvc/app/models/OPNsense/Base/ModelException.php
index a7fcdaf09..576857b85 100644
--- a/src/opnsense/mvc/app/models/OPNsense/Base/Model.php
+++ b/src/opnsense/mvc/app/models/OPNsense/Base/ModelException.php
@@ -27,17 +27,16 @@
--------------------------------------------------------------------------------------
package : Frontend Model Base
- function: implements base model to bind config and definition to object
+ function: Basic Exception class for Model initialization
*/
-
namespace OPNsense\Base;
-abstract class BaseModel
+
+/**
+ * Class BaseModelException
+ * @package Base
+ */
+class ModelException extends \Exception
{
- public function __construct()
- {
- $class_info = new \ReflectionClass($this);
- $class_info->getFileName();
- }
-}
+}
\ No newline at end of file
diff --git a/src/opnsense/mvc/app/models/OPNsense/Sample/Sample.php b/src/opnsense/mvc/app/models/OPNsense/Sample/Sample.php
index 2f8b42e9f..029c10036 100644
--- a/src/opnsense/mvc/app/models/OPNsense/Sample/Sample.php
+++ b/src/opnsense/mvc/app/models/OPNsense/Sample/Sample.php
@@ -34,5 +34,10 @@ use OPNsense\Base\BaseModel;
class Sample extends BaseModel
{
- public $title = "123456";
+// protected function init()
+// {
+// print("\nxXx\n");
+// }
+
+
}
diff --git a/src/opnsense/mvc/app/models/OPNsense/Sample/Sample.xml b/src/opnsense/mvc/app/models/OPNsense/Sample/Sample.xml
new file mode 100644
index 000000000..bd079577b
--- /dev/null
+++ b/src/opnsense/mvc/app/models/OPNsense/Sample/Sample.xml
@@ -0,0 +1,29 @@
+
+ //test/sample
+
+ Sample model
+
+
+
+ [A-Z]
+
+
+
+ test1234
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/opnsense/mvc/app/views/OPNsense/Sample/page.show.volt b/src/opnsense/mvc/app/views/OPNsense/Sample/page.show.volt
index b74913c19..25ed60d13 100644
--- a/src/opnsense/mvc/app/views/OPNsense/Sample/page.show.volt
+++ b/src/opnsense/mvc/app/views/OPNsense/Sample/page.show.volt
@@ -4,3 +4,8 @@
{% for item in items %}
{{ partial('layout_partials/std_input_field',item) }}
{% endfor %}
+
+
+{% for section in data.childnodes.section.__items %}
+ {{ section.node1 }}
+{% endfor %}