Skip to content

Commit

Permalink
Additional commit for CO-1766
Browse files Browse the repository at this point in the history
  • Loading branch information
Benn Oshrin committed Aug 25, 2019
1 parent 3aa01b9 commit c724080
Show file tree
Hide file tree
Showing 5 changed files with 208 additions and 72 deletions.
139 changes: 87 additions & 52 deletions app/src/Controller/AppController.php
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,8 @@ public function beforeRender(\Cake\Event\Event $event) {
*/

protected function getPrimaryLink(bool $lookup=false) {
// Did we already figure this out?
if($this->cur_pl) {
// Did we already figure this out? (But only if $lookup)
if($lookup && isset($this->cur_pl['linkvalue'])) {
return $this->cur_pl;
}

Expand All @@ -171,28 +171,50 @@ protected function getPrimaryLink(bool $lookup=false) {

if($lookup) {
// Try to find a value
if($this->request->getQuery($this->cur_pl['linkattr'])) {
$this->cur_pl['linkvalue'] = $this->request->getQuery($this->cur_pl['linkattr']);
} elseif($this->request->getData($this->cur_pl['linkattr'])) {
$this->cur_pl['linkvalue'] = $this->request->getData($this->cur_pl['linkattr']);
} elseif($this->request->getData($modelName . "." . $this->cur_pl['linkattr'])) {
$this->cur_pl['linkvalue'] = $this->request->getData($modelName . "." . $this->cur_pl['linkattr']);
} else {
// Try to map via the requested ID, if known
$param = (int)$this->request->getParam('pass.0');

if(!empty($param)) {
$this->cur_pl['linkvalue'] = $this->$modelsName->calculateMatchgridId($param);

if($this->request->is('get')) {
// If this action allows unkeyed, asserted primary link IDs, check the query
// string (eg: 'add' or 'index' allow matchgrid_id to be passed in)
if($this->$modelsName->allowUnkeyedPrimaryLink($this->request->getParam('action'))
&& $this->request->getQuery($this->cur_pl['linkattr'])) {
$this->cur_pl['linkvalue'] = $this->request->getQuery($this->cur_pl['linkattr']);
} elseif($this->$modelsName->allowLookupPrimaryLink($this->request->getParam('action'))) {
// Try to map the requested object ID
$param = (int)$this->request->getParam('pass.0');

if(!empty($param)) {
$this->cur_pl['linkvalue'] = $this->$modelsName->calculatePrimaryLinkId($param);
}
}

if(!$this->cur_pl['linkvalue'] && !$this->$modelsName->allowEmptyPrimaryLink()) {
throw new \RuntimeException(__('match.er.primary_link', [ $this->cur_pl['linkattr'] ]));
} elseif($this->request->is('post') || $this->request->is('put')) {
// Look in the data for the primary link ID
if(!empty($this->request->getData($this->cur_pl['linkattr']))) {
$this->cur_pl['linkvalue'] = $this->request->getData($this->cur_pl['linkattr']);
} elseif(!empty($this->request->getData($modelName . "." . $this->cur_pl['linkattr']))) {
$this->cur_pl['linkvalue'] = $this->request->getData($modelName . "." . $this->cur_pl['linkattr']);
} elseif($this->$modelsName->allowLookupPrimaryLink($this->request->getParam('action'))) {
// Try to map the requested object ID (this is probably a delete, so no attribute in post body)
$param = (int)$this->request->getParam('pass.0');

if(!empty($param)) {
$this->cur_pl['linkvalue'] = $this->$modelsName->calculatePrimaryLinkId($param);
}
}
}

if(empty($this->cur_pl['linkvalue']) && !$this->$modelsName->allowEmptyPrimaryLink()) {
throw new \RuntimeException(__('match.er.primary_link', [ $this->cur_pl['linkattr'] ]));
}
}

if(!empty($this->cur_pl['linkvalue'])) {
$this->set('vv_primary_link_id', $this->cur_pl['linkvalue']);
// Look up the link value to find the related entity

$linkModelName = $this->$modelsName->getPrimaryLinkTableName();
$linkModel = TableRegistry::get($linkModelName);

$this->set('vv_primary_link_model', $linkModelName);
$this->set('vv_primary_link_obj', $linkModel->findById($this->cur_pl['linkvalue'])->firstOrFail());
}
}

Expand All @@ -213,58 +235,71 @@ protected function setMatchgrid() {

// $this->name = Models
$modelsName = $this->name;
// $modelName = Model
$modelName = \Cake\Utility\Inflector::singularize($this->name);

if(!method_exists($this->$modelsName, "requiresMatchgrid")
|| !$this->$modelsName->requiresMatchgrid()) {
// Nothing to do, matchgrid not required by this model/controller
return;
}

// Not all models have matchgrid as their primary link. This will trigger
// setting of the viewVar for breadcrumbs and anything else.
// Not all models have matchgrid as their primary link. This will also
// trigger setting of the viewVar for breadcrumbs and anything else.
// PrimaryLinkTrait
$link = $this->getPrimaryLink(true);

// Try to find the requested matchgrid
$mgid = null;

if($this->request->is('get')) {
// If this action allows unkeyed, asserted matchgrid IDs, check the query string
// (eg: 'add' or 'index' allow matchgrid_id to be passed in)
if($this->$modelsName->allowUnkeyedMatchgrid($this->request->getParam('action'))) {
$mgid = $this->request->getQuery('matchgrid_id');
}
}

if($this->request->is('post')) {
// Accept the matchgrid ID from the posted data
$mgid = $this->request->getData('matchgrid_id');
}

if(!$mgid) {
// Try to map the requested object ID
$param = (int)$this->request->getParam('pass.0');

if(!empty($param)) {
try {
$mgid = $this->$modelsName->calculateMatchgridId($param);
// If this action allows unkeyed, asserted primary link IDs, check the query
// string (eg: 'add' or 'index' allow matchgrid_id to be passed in), and
// possibly dereference it if the primary key is not matchgrid_id.
if($this->$modelsName->allowUnkeyedPrimaryLink($this->request->getParam('action'))) {
if($link['linkattr'] == 'matchgrid_id') {
// Simply accept the passed matchgrid ID
$mgid = $this->request->getQuery('matchgrid_id');
} else {
// We already have the primary link object in a viewvar

$plObj = $this->viewVars['vv_primary_link_obj'];

if(!empty($plObj->matchgrid_id)) {
$mgid = $plObj->matchgrid_id;
}
}
catch(Exception $e) {
// Ignore errors and keep trying
} elseif($this->$modelsName->allowLookupPrimaryLink($this->request->getParam('action'))) {
// Try to map the requested object ID
$param = (int)$this->request->getParam('pass.0');

if(!empty($param)) {
$mgid = $this->$modelsName->calculateMatchgridId($param);
}
}
}

if(!$mgid) {
// Use the primary link (if found) to calculate the matchgrid ID

if(!empty($link['linkvalue'])) {
$m = \Cake\Utility\Inflector::pluralize(
\Cake\Utility\Inflector::camelize(
substr($link['linkattr'], 0, strlen($link['linkattr'])-3)));
} elseif($this->request->is('post') || $this->request->is('put')) {
if($link['linkattr'] == 'matchgrid_id') {
// Simply accept the passed matchgrid ID
if(!empty($this->request->getData('matchgrid_id'))) {
$mgid = $this->request->getData('matchgrid_id');
} elseif(!empty($this->request->getData($modelName . ".matchgrid_id"))) {
$mgid = $this->request->getData($modelName . ".matchgrid_id");
} elseif($this->$modelsName->allowLookupPrimaryLink($this->request->getParam('action'))) {
// Try to map the requested object ID (this is probably a delete, so no attribute in post body)
$param = (int)$this->request->getParam('pass.0');

if(!empty($param)) {
$mgid = $this->$modelsName->calculateMatchgridId($param);
}
}
} else {
// We already have the primary link object in a viewvar

$linkModel = TableRegistry::get($m);
$mgid = $linkModel->calculateMatchgridId((int)$link['linkvalue']);
$plObj = $this->viewVars['vv_primary_link_obj'];

if(!empty($plObj->matchgrid_id)) {
$mgid = $plObj->matchgrid_id;
}
}
}

Expand Down
44 changes: 28 additions & 16 deletions app/src/Lib/Traits/MatchgridLinkTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,15 @@

namespace App\Lib\Traits;

use Cake\ORM\TableRegistry;

trait MatchgridLinkTrait {
// Does the associated model require a matchgrid ID?
private $requiresMatchgrid = false;

// If we normally require a matchgrid, can we proceed without one?
private $allowEmptyMatchgrid = false;

// Actions that can have an unkeyed (ie: self asserted) matchgrid ID
private $unkeyedActions = ['add', 'index'];

/**
* If the associated controller normally requires a Matchgrid ID, whether the
* Matchgrid ID can be empty.
Expand All @@ -50,18 +49,6 @@ trait MatchgridLinkTrait {
public function allowEmptyMatchgrid() {
return $this->allowEmptyMatchgrid;
}

/**
* Check to see whether the specified action is allowed to assert a matchgrid ID
* directly (ie: not via lookup of an associated record).
*
* @param string $action Action
* @return boolean true if permitted, false otherwise
*/

public function allowUnkeyedMatchgrid(string $action) {
return in_array($action, $this->unkeyedActions, true);
}

/**
* Calculate the Matchgrid ID associated with the requested object ID.
Expand All @@ -73,11 +60,36 @@ public function allowUnkeyedMatchgrid(string $action) {
*/

public function calculateMatchgridId(int $id) {
// First see if the object has a direct link to Matchgrid.
// Even if it doesn't, we'll still need the object's primary link.
// For now we assume we have a direct foreign key to Matchgrids.

$obj = $this->findById($id)->firstOrFail();

return $obj->matchgrid_id;
if(!empty($obj->matchgrid_id)) {
return $obj->matchgrid_id;
}

// This model probably has a primary key that isn't matchgrid.

if(method_exists($this, "getPrimaryLink")) {
$linkAttr = $this->getPrimaryLink();

if(!empty($obj->$linkAttr)) {
// Look up $linkAttr to get its Matchgrid. We currently assume only
// one level of nesting.

$linkTable = TableRegistry::get($this->getPrimaryLinkTableName());

return $linkTable->calculateMatchgridId($obj->$linkAttr);
}
}

if($this->requiresMatchgrid && !$this->allowEmptyMatchgrid) {
throw new \LogicException("MatchgridLinkTrait::calculateMatchgridId()");
}

return null;
}

/**
Expand Down
65 changes: 63 additions & 2 deletions app/src/Lib/Traits/PrimaryLinkTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,18 @@ trait PrimaryLinkTrait {
// Primary Link field (eg: model:matchgrid_id)
private $primaryLink = null;

// Primary Link table name (eg: Matchgrids)
private $primaryLinkTable = null;

// Allow empty primary link?
private $allowEmpty = false;

// Actions that can have an unkeyed (ie: self asserted) primary link ID
private $unkeyedActions = ['add', 'index'];

// Actions where the primary link can be obtained by looking up the record ID
private $lookupActions = ['delete', 'edit', 'view'];

/**
* Whether the primary link is permitted to be empty.
*
Expand All @@ -47,6 +56,32 @@ public function allowEmptyPrimaryLink() {
return $this->allowEmpty;
}

/**
* Check to see whether the specified action allows a record ID to be passed
* in the URL, which can be used to lookup a primary link.
*
* @since COmanage Match v1.0.0
* @param string $action Action
* @return boolean true if permitted, false otherwise
*/

public function allowLookupPrimaryLink(string $action) {
return in_array($action, $this->lookupActions, true);
}

/**
* Check to see whether the specified action is allowed to assert a primary link ID
* directly (ie: not via lookup of an associated record).
*
* @since COmanage Match v1.0.0
* @param string $action Action
* @return boolean true if permitted, false otherwise
*/

public function allowUnkeyedPrimaryLink(string $action) {
return in_array($action, $this->unkeyedActions, true);
}

/**
* Calculate the Primary Link ID associated with the requested object ID.
*
Expand All @@ -58,9 +93,8 @@ public function allowEmptyPrimaryLink() {

public function calculatePrimaryLinkId(int $id) {
$obj = $this->findById($id)->firstOrFail();
//select([$this->primaryLink]);

return $obj->${$this->primaryLink};
return $obj->{$this->primaryLink};
}

/**
Expand All @@ -87,6 +121,17 @@ public function getPrimaryLink() {
return $this->primaryLink;
}

/**
* Obtain the primary link's table name.
*
* @since COmanage Match v1.0.0
* @return string Primary link table name
*/

public function getPrimaryLinkTableName() {
return $this->primaryLinkTable;
}

/**
* Set whether the primary link is permitted to be empty.
*
Expand All @@ -98,6 +143,17 @@ public function setAllowEmptyPrimaryLink(bool $allowEmpty) {
$this->allowEmpty = $allowEmpty;
}

/**
* Set whether the primary link can be resolved via the object ID in the URL.
*
* @since COmanage Match v1.0.0
* @param boolean $allowEmpty true if the primary link can be resolved via the URL ID
*/

public function setAllowLookupPrimaryLink(array $actions) {
$this->lookupActions = array_merge($this->lookupActions, $actions);
}

/**
* Set the primary link attribute.
*
Expand All @@ -107,5 +163,10 @@ public function setAllowEmptyPrimaryLink(bool $allowEmpty) {

public function setPrimaryLink($field) {
$this->primaryLink = $field;

// Calculate the table name for future reference
if(preg_match('/^(.*?)_id$/', $field, $f)) {
$this->primaryLinkTable = \Cake\Utility\Inflector::camelize(\Cake\Utility\Inflector::pluralize($f[1]));
}
}
}
3 changes: 3 additions & 0 deletions app/src/Model/Table/MatchgridsTable.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
class MatchgridsTable extends Table {
use \App\Lib\Traits\AutoViewVarsTrait;
use \App\Lib\Traits\MatchgridLinkTrait;
use \App\Lib\Traits\PrimaryLinkTrait;

/**
* Perform Cake Model initialization.
Expand Down Expand Up @@ -90,6 +91,8 @@ public function initialize(array $config) {
'class' => 'StatusEnum'
]
]);

$this->setAllowLookupPrimaryLink(['manage', 'pending', 'reconcile']);
}

/**
Expand Down
Loading

0 comments on commit c724080

Please sign in to comment.