Skip to content

Commit

Permalink
make sure ActionForm::populate() is not called before the ActionMappi…
Browse files Browse the repository at this point in the history
…ng is resolved

This could happen if the ActionForm was flashed to the HTTP session and
the session was started before the RequestProcessor finished preparing
the request.
  • Loading branch information
rosasurfer committed Apr 19, 2018
1 parent fff0d4a commit e26b19b
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 40 deletions.
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
},
"extra": {
"branch-alias": {
"dev-master": "0.6.x-dev"
"dev-master": "0.7.x-dev"
}
}
}
67 changes: 38 additions & 29 deletions src/ministruts/ActionForm.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,34 @@ abstract class ActionForm extends Object {
*/
public function __construct(Request $request) {
$this->request = $request;
}


/**
* Read a submitted dispatch action key.
*
* @var ActionMapping $mapping */
/**
* Read and store a submitted {@link DispatchAction} key.
*
* @param Request $request
*
* @example
*
* The framework expects the action key nested in an array. Include it in your HTML like this:
*
* <pre>
* &lt;img type="submit" name="submit[action]" value="..." src=... /&gt;
* </pre>
*/
public function initActionKey(Request $request) {
/** @var ActionMapping $mapping */
$mapping = $request->getAttribute(ACTION_MAPPING_KEY);
$actionClassName = $mapping->getActionClassName();

global $counter; is_int($counter) || $counter = 0;
header('X-Debug-'.(++$counter).': '.__METHOD__.'() $request->attribute(ACTION_MAPPING_KEY) => '.getType($mapping));

if (is_subclass_of($actionClassName, DispatchAction::class)) {
if (isSet($_REQUEST['submit']['action']))
$this->actionKey = $_REQUEST['submit']['action'];

if (is_subclass_of($mapping->getActionClassName(), DispatchAction::class)) {
//
// PHP silently converts dots "." and spaces " " in top-level parameter names to underscores.
//
// - Workaround for user-defined keys => wrap the key in a top-level array
Expand All @@ -49,18 +68,20 @@ public function __construct(Request $request) {
//
// - Workaround for browser-modified keys, i.e. <img type="submit"... => select the key value wisely:
// <img type="submit" name="submit[action]" ...>
// The browser will send "submit[action].x=1234" and PHP will ignore the ".x" part
//

/**
* The framework expects the dispatch action key nested in an array:
*/
if (isSet($_REQUEST['submit']['action']))
$this->actionKey = $_REQUEST['submit']['action']; // <img type="submit" name="submit[action]"...
// The browser will send "submit[action].x=123&submit[action].y=456" and PHP will discard the coordinates.
}
}

// read submitted parameters
$this->populate($request);

/**
* Return the dispatch action key (if the action is a {@link DispatchAction} and a key was submitted).
*
* @return string|null - action key or NULL if no action key was submitted
*
* @see java.struts.DispatchAction
*/
public function getActionKey() {
return $this->actionKey;
}


Expand All @@ -71,7 +92,7 @@ public function __construct(Request $request) {
*
* @return void
*/
abstract protected function populate(Request $request);
abstract public function populate(Request $request);


/**
Expand All @@ -82,18 +103,6 @@ abstract protected function populate(Request $request);
abstract public function validate();


/**
* Return the dispatch action key (if any).
*
* @return string|null - action key or NULL if no action key was submitted
*
* @see java.struts.DispatchAction
*/
public function getActionKey() {
return $this->actionKey;
}


/**
* Prevent serialization of transient properties. // access level encoding
* // ---------------------
Expand Down
22 changes: 12 additions & 10 deletions src/ministruts/RequestProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -327,22 +327,24 @@ protected function processActionFormCreate(Request $request, ActionMapping $mapp
/** @var ActionForm $form */
$form = null;

// bei gesetztem Session-Scope ActionForm zuerst in der Session suchen ...
// if the form has "session" scope we re-use an existing one from the session
if ($mapping->isSessionScope())
$form = $request->getSession()->getAttribute($className); // implicitely start a session
$form = $request->getSession()->getAttribute($className); // implicitely starts a session

// ... ansonsten neue Instanz erzeugen
if (!$form) {
/** @var ActionForm $form */
$form = new $className($request);
}
// otherwise create a new instance
/** @var ActionForm $form */
if (!$form) $form = new $className($request);

// populate the form
$form->initActionKey($request);
$form->populate($request);

// Instanz im Request ...
// store the ActionForm in the request
$request->setAttribute(ACTION_FORM_KEY, $form);

// ... und ggf. auch in der Session speichern
// if the form has "session" scope also store it in the session
if ($mapping->isSessionScope())
$request->getSession()->setAttribute($className, $form); // use started session
$request->getSession()->setAttribute($className, $form);

return $form;
}
Expand Down

0 comments on commit e26b19b

Please sign in to comment.