Skip to content
Snippets Groups Projects
Commit b37c65cf authored by Jan-Hendrik Willms's avatar Jan-Hendrik Willms
Browse files

restructure usage of magic sorm methods in studip controller that allows...

restructure usage of magic sorm methods in studip controller that allows extensions points for plugins
parent 0a0277be
No related branches found
No related tags found
No related merge requests found
Pipeline #8860 passed
...@@ -22,6 +22,7 @@ abstract class StudipController extends Trails_Controller ...@@ -22,6 +22,7 @@ abstract class StudipController extends Trails_Controller
protected $with_session = false; //do we need to have a session for this controller protected $with_session = false; //do we need to have a session for this controller
protected $allow_nobody = true; //should 'nobody' allowed for this controller or redirected to login? protected $allow_nobody = true; //should 'nobody' allowed for this controller or redirected to login?
protected $_autobind = false; protected $_autobind = false;
protected $reflection_cache = [];
/** /**
* @return false|void * @return false|void
...@@ -165,85 +166,12 @@ abstract class StudipController extends Trails_Controller ...@@ -165,85 +166,12 @@ abstract class StudipController extends Trails_Controller
*/ */
public function validate_args(&$args, $types = null) public function validate_args(&$args, $types = null)
{ {
$class_infos = []; if (!is_array($types)) {
$types = (array) $types;
if ($types === null) {
$types = array_fill(0, count($args), 'option');
}
if ($this->has_action($this->current_action)) {
$reflection = new ReflectionMethod($this, $this->current_action . '_action');
$parameters = $reflection->getParameters();
foreach ($parameters as $i => $parameter) {
$class_type = $parameter->getType();
if (!$class_type
|| !class_exists($class_type->getName())
|| !is_a($class_type->getName(), SimpleORMap::class, true))
{
continue;
}
$types[$i] = 'sorm';
$class_infos[$i] = [
'model' => $class_type->getName(),
'var' => $parameter->getName(),
'optional' => $parameter->isOptional(),
];
if ($parameter->isOptional() && !isset($args[$i])) {
$args[$i] = $parameter->getDefaultValue();
}
}
} }
foreach ($args as $i => &$arg) { foreach ($args as $i => &$arg) {
$type = $types[$i] ?: 'option'; $arg = $this->convertArgumentFromURL($arg, $i, $types[$i] ?? $this->getTypeForActionParameter($i));
switch ($type) {
case 'int':
$arg = (int) $arg;
break;
case 'float':
$arg = (float) strtr($arg, ',', '.');
break;
case 'option':
if (preg_match('/[^\\w,-]/', $arg)) {
throw new Trails_Exception(400);
}
break;
case 'sorm':
$info = $class_infos[$i];
$id = null;
if ($arg != -1) {
$id = $arg;
}
if (mb_strpos($id, SimpleORMap::ID_SEPARATOR) !== false) {
$id = explode(SimpleORMap::ID_SEPARATOR, $id);
}
$reflection = new ReflectionClass($info['model']);
$sorm = $reflection->newInstance($id);
if (!$info['optional'] && $sorm->isNew()) {
throw new Trails_Exception(
404,
"Parameter {$info['var']} could not be resolved with value {$arg}"
);
}
$arg = $sorm;
if ($this->_autobind) {
$this->{$info['var']} = $arg;
}
break;
default:
throw new Trails_Exception(500, 'Unknown type "' . $type . '"');
}
} }
reset($args); reset($args);
...@@ -289,7 +217,7 @@ abstract class StudipController extends Trails_Controller ...@@ -289,7 +217,7 @@ abstract class StudipController extends Trails_Controller
// Extract fragment (if any) // Extract fragment (if any)
if (strpos($to, '#') !== false) { if (strpos($to, '#') !== false) {
list($args[0], $fragment) = explode('#', $to); [$args[0], $fragment] = explode('#', $to);
} }
// Extract parameters (if any) // Extract parameters (if any)
...@@ -299,12 +227,10 @@ abstract class StudipController extends Trails_Controller ...@@ -299,12 +227,10 @@ abstract class StudipController extends Trails_Controller
} }
// Map any sorm objects to their ids // Map any sorm objects to their ids
$args = array_map(function ($arg) { $args = array_map(
if (is_object($arg) && $arg instanceof SimpleORMap) { [$this, 'convertArgumentForURL'],
return $arg->isNew() ? -1 : $arg->id; $args
} );
return $arg;
}, $args);
$url = parent::url_for(...$args); $url = parent::url_for(...$args);
...@@ -810,4 +736,146 @@ abstract class StudipController extends Trails_Controller ...@@ -810,4 +736,146 @@ abstract class StudipController extends Trails_Controller
return $body_id; return $body_id;
} }
/**
* Converts an argument passed to url_for()/link_for() for usage in an url.
*
* @param mixed $argument
* @return mixed
*/
protected function convertArgumentForURL($argument)
{
if (is_object($argument) && $argument instanceof SimpleORMap) {
return $argument->isNew() ? -1 : $argument->id;
}
return $argument;
}
/**
* @param mixed $argument
* @param int $index
* @param string $type
*
* @return mixed
*/
protected function convertArgumentFromURL($argument, int $index, string $type)
{
if ($type === 'int') {
return (int) $argument;
}
if ($type === 'float') {
return (float) strtr($argument, ',', '.');
}
if ($type === 'sorm') {
$parameter = $this->getReflectedParameter($index);
if ($parameter->isOptional() && !isset($argument)) {
return $parameter->getDefaultValue();
}
$sorm = $this->loadSORMParameter($parameter->getType()->getName(), $argument);
if ($sorm->isNew() && !$parameter->isOptional()) {
throw new Trails_Exception(
404,
"Parameter {$parameter->getName()} could not be resolved with value {$argument}"
);
}
if ($this->_autobind) {
$this->{$parameter->getName()} = $sorm;
}
return $sorm;
}
if ($type !== 'option') {
throw new Trails_Exception(500, 'Unknown type "' . $type . '"');
}
if (preg_match('/[^\\w,-]/', $argument)) {
throw new Trails_Exception(400);
}
return $argument;
}
/**
* @param int $index
*
* @return ReflectionMethod
* @throws ReflectionException
*/
protected function getTypeForActionParameter(int $index, string $action = null): string
{
$parameter = $this->getReflectedParameter($index, $action);
if (!$parameter) {
return 'option';
}
$type = $parameter->getType();
if (!$type) {
return 'option';
}
$type_name = $type->getName();
if (in_array($type_name, ['int', 'float'])) {
return $type_name;
}
if (class_exists($type_name) && is_a($type_name, SimpleORMap::class, true)) {
return 'sorm';
}
return 'option';
}
/**
* @param int $index
* @param string|null $action
*
* @return ReflectionParameter|null
* @throws ReflectionException
*/
protected function getReflectedParameter(int $index, string $action = null): ?ReflectionParameter
{
if ($action === null) {
$action = $this->current_action;
}
if (!$this->has_action($action)) {
return null;
}
if (!isset($this->reflection_cache[$action])) {
$reflection = new ReflectionMethod(
$this,
"{$action}_action"
);
$this->reflection_cache[$action] = $reflection->getParameters();
}
return $this->reflection_cache[$action][$index] ?? null;
}
/**
* @param string $class_name
* @param mixed $argument
*
* @return SimpleORMap
* @throws ReflectionException
*/
protected function loadSORMParameter(string $class_name, $argument): SimpleORMap
{
$id = $argument != -1 ? $argument : null;
if (mb_strpos($id, SimpleORMap::ID_SEPARATOR) !== false) {
$id = explode(SimpleORMap::ID_SEPARATOR, $id);
}
$reflection = new ReflectionClass($class_name);
return $reflection->newInstance($id);
}
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment