Skip to content

Commit

Permalink
add parameter transformers
Browse files Browse the repository at this point in the history
  • Loading branch information
juliangut committed Mar 4, 2018
1 parent 80659ff commit da6d856
Show file tree
Hide file tree
Showing 21 changed files with 658 additions and 7 deletions.
42 changes: 41 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,30 @@ Provided response types handlers:

You can create you're own response handlers to compose specifically formatted JSON (JSON-API, ...) or use another template engines (Plates, ...)

### Parameter transformation

Route parameters can be transformed before arriving to route callable. The most common use of this feature would be to transform ids from route into actual object/entity used in the callable

To achieve this you need to provide a `\Jgut\Slim\Routing\Transformer\ParameterTransformer` instance defined in the route itself. There is an abstract class `\Jgut\Slim\Routing\Transformer\AbstractTransformer` to easily implement parameters transformation

For example you would want to transform parameters into Doctrine entities

```php
class CustomTransformer extends AbstractTransformer
{
protected $entityManager;

public function __construct(EntityManager $entityManager) {
$this->entityManager = $entityManager;
}

protected function transformParameter(string $parameter, string $type)
{
return $this->entityManager->getRepository($type)->find($parameter);
}
}
```

### Routes

Routes can be defined in two basic ways: by setting them in definition files of various formats or directly defined in annotations on controller classes
Expand Down Expand Up @@ -231,6 +255,8 @@ class Section
* methods={"GET", "POST"},
* pattern="do/{action}",
* placeholders={"action": "[a-z0-9]+"},
* transformer="CustomTransformer",
* parameters={"action": "\My\Entity"},
* middleware={"routeMiddlewareName"},
* priority=-10
* )
Expand All @@ -246,6 +272,8 @@ class Section
* `xmlHttpRequest`, request should be AJAX, false by default
* `methods`, optional, list of accepted HTTP route methods. "ANY" is a special method that transforms to `[GET, POST, PUT, PATCH, DELETE]`, if ANY is used no other method is allowed in the list (defaults to GET)
* `placeholders`, optional, array of regex/alias for path placeholders
* `parameters`, optional, array of definitions of parameters, to be used in transformer
* `transformer`, optional, reference to a ParameterTransformer instance that will be extracted from the container
* `middleware`, optional, array of middleware to be added to the route
* `priority`, optional, integer for ordering route registration. The order is global among all loaded routes. Negative routes get loaded first (defaults to 0)

Expand All @@ -270,6 +298,8 @@ return [
'priority' => 0
'pattern' => 'route-pattern',
'placeholders' => ['route-placeholders'],
'parameters' => ['route-parameters'],
'transformer' => 'customTransformer',
'middleware' => ['route-middleware'],
'invokable' => 'callable',
],
Expand Down Expand Up @@ -308,6 +338,8 @@ return [
"priority": 0,
"pattern": "route-pattern",
"placeholders": ["route-placeholders"],
"parameters": ["route-parameters"],
"transformer": "customTransformer",
"middleware": ["route-middleware"],
"invokable": "callable"
},
Expand Down Expand Up @@ -349,10 +381,14 @@ return [
<placeholders>
<placeholder1>route-placeholder</placeholder1>
</placeholders>
<parameters>
<parameter1>route-parameter</parameter1>
</parameters>
<transformer>CustomTransformer</transformer>
<middleware>
<middleware1>route-middleware</middleware1>
</middleware>
<invokable>callable</invokable>,
<invokable>callable</invokable>
</route1>
<subgroup1 prefix="prefix" pattern="group-pattern">
<placeholders>
Expand Down Expand Up @@ -388,6 +424,8 @@ return [
priority: 0
pattern: route-pattern
placeholders: [route-placeholders]
parameters: [route-parameters]
transformer: CustomTransformer
middleware: [route-middleware]
invokable: callable
# Subgroup
Expand Down Expand Up @@ -420,6 +458,8 @@ Defines a route added to Slim
* `xmlHttpRequest`, request should be AJAX, false by default
* `methods`, optional, list of accepted HTTP route methods. "ANY" is a special method that transforms to `[GET, POST, PUT, PATCH, DELETE]`, if ANY is used no other method is allowed (defaults to GET)
* `placeholders`, optional, array of regex for path placeholders
* `parameters`, optional, array of definitions of parameters, to be used in transformer
* `transformer`, optional, reference to a ParameterTransformer instance that will be extracted from the container
* `middleware`, optional, array of middleware to be added to the route
* `priority`, optional, integer for ordering route registration. The order is global among all loaded routes. Negative routes get loaded first (defaults to 0)

Expand Down
35 changes: 33 additions & 2 deletions src/Mapping/Annotation/PathTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ trait PathTrait
*/
protected $placeholders = [];

/**
* Pattern parameters.
*
* @var array
*/
protected $parameters = [];

/**
* Get pattern path.
*
Expand All @@ -49,7 +56,7 @@ public function getPattern()
*
* @return static
*/
public function setPattern(string $pattern)
public function setPattern(string $pattern): self
{
$this->pattern = $pattern;

Expand All @@ -73,10 +80,34 @@ public function getPlaceholders(): array
*
* @return static
*/
public function setPlaceholders(array $placeholders)
public function setPlaceholders(array $placeholders): self
{
$this->placeholders = $placeholders;

return $this;
}

/**
* Get parameters.
*
* @return array
*/
public function getParameters(): array
{
return $this->parameters;
}

/**
* Set parameters.
*
* @param array $parameters
*
* @return static
*/
public function setParameters(array $parameters): self
{
$this->parameters = $parameters;

return $this;
}
}
31 changes: 31 additions & 0 deletions src/Mapping/Annotation/Route.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@ class Route extends AbstractAnnotation
*/
protected $name;

/**
* Parameters transformer.
*
* @var string
*/
protected $transformer;

/**
* Route methods.
*
Expand Down Expand Up @@ -89,6 +96,30 @@ public function setName(string $name): self
return $this;
}

/**
* Get parameters transformer.
*
* @return string|null
*/
public function getTransformer()
{
return $this->transformer;
}

/**
* Set parameters transformer.
*
* @param string $transformer
*
* @return static
*/
public function setTransformer(string $transformer): self
{
$this->transformer = $transformer;

return $this;
}

/**
* Get route methods.
*
Expand Down
31 changes: 31 additions & 0 deletions src/Mapping/Driver/AnnotationDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ protected function getGroupMetadata(GroupAnnotation $annotation): GroupMetadata
$group->setPrefix($annotation->getPrefix());
}

$group->setParameters($annotation->getParameters());

return $group;
}

Expand Down Expand Up @@ -220,6 +222,35 @@ protected function getRouteMetadata(
$route->setGroup($group);
}

if ($annotation->getTransformer() !== null) {
$route->setTransformer($annotation->getTransformer())
->setParameters($this->getRouteParameters($method, $annotation));
}

return $route;
}

/**
* Get route parameters.
*
* @param \ReflectionMethod $method
* @param RouteAnnotation $annotation
*
* @return array
*/
protected function getRouteParameters(
\ReflectionMethod $method,
RouteAnnotation $annotation
): array {
$parameters = [];
foreach ($method->getParameters() as $parameter) {
$type = $parameter->getType();

if ($type !== null) {
$parameters[$parameter->getName()] = (string) $type;
}
}

return \array_merge($parameters, $annotation->getParameters());
}
}
48 changes: 48 additions & 0 deletions src/Mapping/Driver/MappingTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ protected function getGroupMetadata(array $mapping, GroupMetadata $parentGroup =
{
$group = (new GroupMetadata())
->setPlaceholders($this->getPlaceholders($mapping))
->setParameters($this->getParameters($mapping))
->setMiddleware($this->getMiddleware($mapping));

$pattern = $this->getPattern($mapping);
Expand Down Expand Up @@ -120,6 +121,12 @@ protected function getRouteMetadata(array $mapping, GroupMetadata $group = null)
$route->setGroup($group);
}

$transformer = $this->getTransformer($mapping);
if ($transformer !== null) {
$route->setTransformer($transformer)
->setParameters($this->getParameters($mapping));
}

return $route;
}

Expand Down Expand Up @@ -192,6 +199,18 @@ protected function getMethods(array $mapping): array
return $methods;
}

/**
* Get parameter transformer.
*
* @param array $mapping
*
* @return string|null
*/
protected function getTransformer(array $mapping)
{
return $mapping['transformer'] ?? null;
}

/**
* Get XmlHttpRequest constraint.
*
Expand Down Expand Up @@ -230,6 +249,35 @@ protected function getPattern(array $mapping)
: null;
}

/**
* Get mapping parameters.
*
* @param array $mapping
*
* @throws DriverException
*
* @return string[]
*/
protected function getParameters(array $mapping): array
{
if (!\array_key_exists('parameters', $mapping)) {
return [];
}

$parameters = $mapping['parameters'];

\array_map(
function ($key) {
if (!\is_string($key)) {
throw new DriverException('Parameters keys must be all strings');
}
},
\array_keys($parameters)
);

return $parameters;
}

/**
* Get mapping placeholders.
*
Expand Down
31 changes: 31 additions & 0 deletions src/Mapping/Metadata/AbstractMetadata.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@ abstract class AbstractMetadata implements MetadataInterface
*/
protected $placeholders = [];

/**
* Pattern parameters.
*
* @var array
*/
protected $parameters = [];

/**
* Middleware list.
*
Expand Down Expand Up @@ -104,6 +111,30 @@ public function setPlaceholders(array $placeholders): self
return $this;
}

/**
* Get pattern parameters.
*
* @return array
*/
public function getParameters(): array
{
return $this->parameters;
}

/**
* Set pattern parameters.
*
* @param array $parameters
*
* @return static
*/
public function setParameters(array $parameters): self
{
$this->parameters = $parameters;

return $this;
}

/**
* Get middleware.
*
Expand Down
Loading

0 comments on commit da6d856

Please sign in to comment.