Commit 7ec92dae authored by Ad Schellevis's avatar Ad Schellevis

Phalcon MVC work including first (not completed yet) demo form.

parent dec1e972
......@@ -29,6 +29,7 @@
namespace OPNsense\Base;
use Phalcon\Mvc\Controller;
use Phalcon\Translate\Adapter\NativeArray;
/**
* Class ControllerBase implements core controller for OPNsense framework
......@@ -36,11 +37,27 @@ use Phalcon\Mvc\Controller;
*/
class ControllerBase extends Controller
{
/**
* translate a text
* @param string $tag input text
* @return string
*/
public function getTranslator()
{
// TODO: implement language service
$messages = array();
return new \Phalcon\Translate\Adapter\NativeArray(array(
"content" => $messages
));
}
/**
* Default action. Set the standard layout.
*/
public function initialize()
{
// set base template
$this->view->setTemplateBefore('default');
}
......@@ -50,7 +67,7 @@ class ControllerBase extends Controller
public function beforeExecuteRoute($dispatcher)
{
// Execute before every found action
// TODO: implement default behavior
$this->view->setVar('lang', $this->getTranslator());
}
/**
......
......@@ -38,20 +38,56 @@ use \OPNsense\Core\Config;
*/
class PageController extends ControllerBase
{
/**
* update model with data from our request
* @param BaseModel &$mdlSample model to update
*/
private function updateModelWithPost(&$mdlSample)
{
// Access POST data and save parts to model
foreach ($this->request->getPost() as $key => $value) {
$refparts = explode("_", $key);
if (array_shift($refparts) == "sample") {
// this post item belongs to the Sample model (see prefix in view)
$node_found = $mdlSample->setNodeByReference(implode(".", $refparts), $value);
// new node in the post which is not on disc, create a new child node
// we need to create new nodes in memory for Array types
if ($node_found == null && strpos($key, 'childnodes_section_') !== false) {
// because all the array items are numbered in order, we know that any item not found
// must be a new one.
$mdlSample->childnodes->section->add();
$mdlSample->setNodeByReference(implode(".", $refparts), $value);
}
}
}
}
/**
* controller for sample index page, defaults to http://<host>/sample/page
*/
public function indexAction()
public function indexAction($error_msg = array())
{
// load model and send to view, this model is automatically filled with data from the config.xml
$mdlSample = new Sample();
$this->view->sample = $mdlSample;
// got forwarded with errors, load form data from post and update on our model
if ($this->request->isPost() == true && count($error_msg) >0) {
$this->updateModelWithPost($mdlSample);
}
// send error messages to view
$this->view->error_messages = $error_msg;
// set title and pick a template
$this->view->title = "test page";
$this->view->pick('OPNsense/Sample/page');
}
/**
* Example save action
* @throws \Phalcon\Validation\Exception
*/
public function saveAction()
{
// save action should be a post, redirect to index
......@@ -59,17 +95,49 @@ class PageController extends ControllerBase
// create model(s)
$mdlSample = new Sample();
// Access POST data and save parts to model
foreach ($this->request->getPost() as $key => $value) {
$refparts = explode("_", $key);
if (array_shift($refparts) == "sample") {
// this post item belongs to the Sample model (prefixed in view)
$mdlSample->setNodeByReference(implode(".", $refparts), $value);
// update model with request data
$this->updateModelWithPost($mdlSample);
if ($this->request->getPost("form_action") == "add") {
// implement addRow, append new model row and serialize to config
$mdlSample->childnodes->section->add();
$mdlSample->serializeToConfig();
} elseif ($this->request->getPost("form_action") == "save") {
// implement save, possible removing
if ($this->request->hasPost("delete")) {
// delete selected Rows, cannot combine with add because of the index numbering
foreach ($this->request->getPost("delete") as $node_ref => $option_key) {
$refparts = explode(".", $node_ref);
$delete_key = array_pop($refparts);
$parentNode = $mdlSample->getNodeByReference(implode(".", $refparts));
if ($parentNode != null) {
$parentNode->del($delete_key);
}
}
}
// save data to config
$validationOutput = $mdlSample->performValidation();
if ($validationOutput->count() > 0) {
// forward to index including errors
$error_msgs = array();
foreach ($validationOutput as $msg) {
$error_msgs[] = array("field" => $msg-> getField(), "msg" => $msg->getMessage());
}
// redirect to index
$this->dispatcher->forward(array(
"action" => "index",
"params" => array($error_msgs)
));
return false;
}
$mdlSample->serializeToConfig();
$cnf = Config::getInstance();
$cnf->save();
}
$mdlSample->serializeToConfig();
$cnf = Config::getInstance();
$cnf->save();
// redirect to index
$this->dispatcher->forward(array(
......@@ -84,28 +152,4 @@ class PageController extends ControllerBase
}
}
public function showAction($postId)
{
$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);
// $robot = new Sample\Sample();
// $robot->title = 'hoi';
//
// $this->view->title = $postId. "/". $this->persistent->name;
//
$this->view->pick('OPNsense/Sample/page.show');
// $this->flash->error("You don't have permission to access this area");
//
// // Forward flow to another action
// $this->dispatcher->forward(array(
// "controller" => "sample",
// "action" => "index"
// ));
}
}
......@@ -218,6 +218,15 @@ abstract class BaseModel
$this->internalData->$name = $value ;
}
/**
* forward to root node's getFlatNodes
* @return array all children
*/
public function getFlatNodes()
{
return $this->internalData->getFlatNodes();
}
/**
* validate full model using all fields and data in a single (1 deep) array
*/
......
......@@ -33,6 +33,10 @@ namespace OPNsense\Base\FieldTypes;
/**
* Class BaseField
* @package OPNsense\Base\FieldTypes
* @property-read string $__reference this tag absolute reference (node.subnode.subnode)
* @property-read string $__type this tag's class Name ( example TextField )
* @property-read string $__Ixx get tag by index/name even if the name is a number
* @property-read array $__items this node's children
*/
abstract class BaseField
{
......@@ -151,6 +155,11 @@ abstract class BaseField
return $result;
} elseif ($name == '__reference') {
return $this->internalReference;
} elseif ($name == '__type') {
return $this->getObjectType();
} elseif (strrpos($name, "__I") === 0) {
// direct index item assignment
return $this->__get(substr($name, 3));
} else {
// not found
return null;
......@@ -158,6 +167,7 @@ abstract class BaseField
}
/**
* reflect default setter to internal child nodes
* @param string $name property name
......@@ -307,4 +317,13 @@ abstract class BaseField
}
}
/**
* return object type as string
* @return string
*/
public function getObjectType()
{
$parts = explode("\\", get_class($this));
return $parts[count($parts)-1];
}
}
......@@ -9,14 +9,15 @@
<items>
<tag1 type="TextField">
<Mask>/^([A-Z,1-9]){0,10}$/</Mask>
<ValidationMessage>test</ValidationMessage>
</tag1>
<tagX>
<tag1 type="EmailField">
<Default>test1234</Default>
<ValidationMessage>you should input this!</ValidationMessage>
<ValidationMessage>you should input a valid email address</ValidationMessage>
</tag1>
<tag2>
<tagZ></tagZ>
<tagZ type="TextField"/>
</tag2>
</tagX>
<childnodes>
......
show template... {{title|default("??") }}
{% for item in items %}
{{ partial('layout_partials/std_input_field',item) }}
{% endfor %}
<br>
{% for section in data.childnodes.section.__items %}
{{ section.node1 }} <br>
{% endfor %}
<div>
<i>this is a sample page for the OPNsense mvc frontend framework</i>
<style type="text/css">
.tg {border-collapse:collapse;border-spacing:0;border-color:#aabcfe;}
.tg td{font-family:Arial, sans-serif;font-size:14px;padding:10px 5px;border-style:solid;border-width:0px;overflow:hidden;word-break:normal;border-color:#aabcfe;color:#669;background-color:#e8edff;border-top-width:1px;border-bottom-width:1px;}
.tg th{font-family:Arial, sans-serif;font-size:14px;font-weight:normal;padding:10px 5px;border-style:solid;border-width:0px;overflow:hidden;word-break:normal;border-color:#aabcfe;color:#039;background-color:#b9c9fe;border-top-width:1px;border-bottom-width:1px;}
.tg .tg-vn4c{background-color:#D2E4FC}
</style>
<div style="width:600px">
This a sample page for the OPNsense MVC framework. This page demonstrates how to create a model (OPNsense\Sample\Sample.xml) and bind this to data in our config.xml.
<br/><br/>
The index controller (controllers\OPNsense\Sample\PageController) binds some data to this form like the title ({{title|default("'no title set'") }}).
and the actual data from the Sample model, which is a combination of the data presented in the config.xml and the defaults set in the model xml.
<br/><br/>
When errors occur while saving this form, they will be shown below:
{% for error_message in error_messages %}
<i style="color:red"> {{ error_message['field'] }} : {{ error_message['msg'] }} </i> <br>
{% endfor %}
<br/><br/>
Edit the data
</div>
{{ sample.tag1 }}
<form action="save" method="post">
<input type="text" name="sample.{{sample.tag1.__reference}}" value="{{sample.tag1}}"><br>
<input type="text" name="sample.{{sample.tagX.tag1.__reference}}" value="{{sample.tagX.tag1}}"><br>
<form action="save" method="post">
<table class="tg">
<tr>
<td>{{ lang._('item') }} </td>
<td>{{ lang._('internal reference') }}</td>
<td>{{ lang._('input') }}</td>
</tr>
<tr>
<td>tag1 </td>
<td>{{sample.tag1.__reference}}</td>
<td>
{# for demonstration purposes, use a partial for this field #}
{{ partial("layout_partials/sample_input_field", ['field_type': 'text','field_content':sample.tag1,'field_name':sample.tag1.__reference,'field_name_prefix':'sample.']) }}
</td>
</tr>
<tr>
<td>tagX/tag1 </td>
<td>{{sample.tagX.tag1.__reference}}</td>
<td><input type="text" name="sample.{{sample.tagX.tag1.__reference}}" value="{{sample.tagX.tag1}}"><br><br></td>
</tr>
<tr> <td colspan=3>detail items within sample model</td> </tr>
{# traverse details #}
{% for section_item in sample.childnodes.section.__items %}
<tr> <td colspan=3>##ROW## delete node {{section_item.__reference}} <input type="checkbox" name="delete[{{section_item.__reference}}]" value="1"> </td> </tr>
<tr>
<td>childnodes/section/[]/node1</td>
<td>{{section_item.node1.__reference}}</td>
<td><input type="text" name="sample.{{section_item.node1.__reference}}" value="{{section_item.node1}}"></td>
</tr>
<tr>
<td>childnodes/section/[]/node2</td>
<td>{{section_item.node2.__reference}}</td>
<td><input type="text" name="sample.{{section_item.node2.__reference}}" value="{{section_item.node2}}"></td>
</tr>
{% endfor %}
<tr>
<td></td>
<td></td>
<td><input type="submit" value="add" name="form_action" ></td>
</tr>
<tr> <td colspan=3> </td> </tr>
<tr> <td colspan=3><input type="submit" value="save" name="form_action" > </td> </tr>
</table>
<input type="submit" value="Submit">
</form>
\ No newline at end of file
<input type="{{field_type}}" value="{{field_content}}" name="{{field_name_prefix}}{{field_name}}" >
<input type={{field_type}} value="{{field_content}}" name="{{field_name}}" >
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment