Skip to content

Commit

Permalink
MVC, keep track of model that created a field so our model relationfi…
Browse files Browse the repository at this point in the history
…eld can reuse the same object for choosing it's options, for #2255

(cherry picked from commit 117eb47)
  • Loading branch information
AdSchellevis authored and fichtner committed Apr 11, 2018
1 parent c0b1b02 commit e4d5daf
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 38 deletions.
1 change: 1 addition & 0 deletions src/opnsense/mvc/app/models/OPNsense/Base/BaseModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ private function parseXml(&$xml, &$config_data, &$internal_data)
$new_ref = $internal_data->__reference . "." . $tagName;
}
$fieldObject = $field_rfcls->newInstance($new_ref, $tagName);
$fieldObject->setParentModel($this);

// now add content to this model (recursive)
if ($fieldObject->isContainer() == false) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ public function add()
$this->__reference . "." . $nodeUUID,
$this->internalXMLTagName
);
$parentmodel = $this->getParentModel();
$container_node->setParentModel($parentmodel);

foreach ($new_record as $key => $node) {
// initialize field with new internal id and defined default value
Expand Down
24 changes: 24 additions & 0 deletions src/opnsense/mvc/app/models/OPNsense/Base/FieldTypes/BaseField.php
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,11 @@ abstract class BaseField
*/
private $internalFieldLoaded = false;

/**
* @var BaseModel|null keep record of the model which originally created this field
*/
private $internalParentModel = null;

/**
* generate a new UUID v4 number
* @return string uuid v4 number
Expand Down Expand Up @@ -145,6 +150,25 @@ protected function actionPostLoadingEvent()
return;
}

/**
* @param BaseModel $object to which this field is attached
*/
public function setParentModel(&$object)
{
if (empty($this->internalParentModel)){
// read only attribute, set from model
$this->internalParentModel = $object;
}
}

/**
* Retrieve the model to which this field is attached
* @return BaseModel parent model
*/
public function getParentModel()
{
return $this->internalParentModel;
}

/**
* trigger post loading event. (executed by BaseModel)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,30 +57,32 @@ class ModelRelationField extends BaseField
*/
private static $internalOptionList = array();

/**
* @var array|null model settings to use for validation
*/
private $mdlStructure = null;

/**
* @var boolean selected options from the same model
*/
private $internalOptionsFromThisModel = false;

/**
* @var string cache relations
*/
private $internalCacheKey = "";

/**
* Set model as reference list, use uuid's as key
* @param $mdlStructure nested array structure defining the usable datasources.
* load model option list
* @param $force force option load if we already seen this model before
*/
public function setModel($mdlStructure)
private function loadModelOptions($force=false)
{
// only handle array type input
if (!is_array($mdlStructure)) {
return;
}

// set internal key for this node based on sources and filter criteria
$this->internalCacheKey = md5(serialize($mdlStructure));

// only collect options once per source/filter combination, we use a static to save our unique option
// combinations over the running application.
if (!isset(self::$internalOptionList[$this->internalCacheKey])) {
if (!isset(self::$internalOptionList[$this->internalCacheKey]) || $force) {
self::$internalOptionList[$this->internalCacheKey] = array();
foreach ($mdlStructure as $modelData) {
foreach ($this->mdlStructure as $modelData) {
// only handle valid model sources
if (!isset($modelData['source']) || !isset($modelData['items']) || !isset($modelData['display'])) {
continue;
Expand All @@ -91,48 +93,72 @@ public function setModel($mdlStructure)
if (!class_exists($className)) {
continue;
}

$modelObj = new $className;
if (strcasecmp(get_class($this->getParentModel()), $className) === 0) {
// model options from the same model, use this model in stead of creating something new
$modelObj = $this->getParentModel();
$this->internalOptionsFromThisModel = true;
} else {
$modelObj = new $className;
}

$groupKey = isset($modelData['group']) ? $modelData['group'] : null;
$displayKey = $modelData['display'];
$groups = array();

foreach ($modelObj->getNodeByReference($modelData['items'])->__items as $node) {
if (!isset($node->getAttributes()['uuid']) || $node->$displayKey == null) {
continue;
}
$searchItems = $modelObj->getNodeByReference($modelData['items']);
if (!empty($searchItems)){
foreach ($modelObj->getNodeByReference($modelData['items'])->__items as $node) {
if (!isset($node->getAttributes()['uuid']) || $node->$displayKey == null) {
continue;
}

if (isset($modelData['filters'])) {
foreach ($modelData['filters'] as $filterKey => $filterValue) {
$fieldData = $node->$filterKey;
if (!preg_match($filterValue, $fieldData) && $fieldData != null) {
continue 2;
if (isset($modelData['filters'])) {
foreach ($modelData['filters'] as $filterKey => $filterValue) {
$fieldData = $node->$filterKey;
if (!preg_match($filterValue, $fieldData) && $fieldData != null) {
continue 2;
}
}
}
}

if (!empty($groupKey)) {
if ($node->$groupKey == null) {
continue;
}
$group = $node->$groupKey->__toString();
if (isset($groups[$group])) {
continue;
if (!empty($groupKey)) {
if ($node->$groupKey == null) {
continue;
}
$group = $node->$groupKey->__toString();
if (isset($groups[$group])) {
continue;
}
$groups[$group] = 1;
}
$groups[$group] = 1;
}

$uuid = $node->getAttributes()['uuid'];
self::$internalOptionList[$this->internalCacheKey][$uuid] =
$node->$displayKey->__toString();
$uuid = $node->getAttributes()['uuid'];
self::$internalOptionList[$this->internalCacheKey][$uuid] =
$node->$displayKey->__toString();
}
}

unset($modelObj);
}
}
}

/**
* Set model as reference list, use uuid's as key
* @param $mdlStructure nested array structure defining the usable datasources.
*/
public function setModel($mdlStructure)
{
// only handle array type input
if (!is_array($mdlStructure)) {
return;
} else {
$this->mdlStructure = $mdlStructure;
// set internal key for this node based on sources and filter criteria
$this->internalCacheKey = md5(serialize($mdlStructure));
}
$this->loadModelOptions();
}

/**
* select if multiple data nodes may be selected at once
* @param $value boolean value Y/N
Expand Down Expand Up @@ -182,6 +208,8 @@ public function getValidators()
{
$validators = parent::getValidators();
if ($this->internalValue != null) {
// if our options come from the same model, make sure to reload the options before validating them
$this->loadModelOptions($this->internalOptionsFromThisModel);
if ($this->internalMultiSelect) {
// field may contain more than one entries
$validators[] = new CsvListValidator(array(
Expand Down

0 comments on commit e4d5daf

Please sign in to comment.