Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix placeholders types #9

Merged
merged 12 commits into from
Nov 20, 2019
2 changes: 0 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
language: php

php:
- "7.0"
- "7.1"
- "7.2"
- "7.3"

Expand Down
22 changes: 22 additions & 0 deletions src/AbstractRouteHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,18 @@ abstract class AbstractRouteHandler

protected $fillable = [];

protected $attributeTypes = [
'STRING' => '([a-z0-9\-]+)',
'INTEGER' => '([0-9]+)',
'ARRAY' => '([a-z0-9]+)/(([a-z0-9\-]+/)+|([a-z0-9\-_]+)+)($)',
];

const PLACEHOLDER_TYPE_STRING = 'STRING';

const PLACEHOLDER_TYPE_INTEGER = 'INTEGER';

const PLACEHOLDER_TYPE_ARRAY = 'ARRAY';

public function route(string $method, string $pattern) : self
{
if (!is_null($this->matched)) {
Expand Down Expand Up @@ -94,6 +106,16 @@ public function __call(string $name , array $arguments = []) : self
return $this;
}

public function getPlaceholderRegExp(string $type) : string
{
return $this->attributeTypes[strtoupper($type)];
}

public function hasPlaceholderType(string $type) : bool
{
return array_key_exists(strtoupper($type), $this->attributeTypes);
}

protected function checkErrors() : void
{
if (isset($this->fillable['where']) && !preg_match('(\{\$[a-zA-Z]+\})', $this->fillable['pattern'])) {
Expand Down
4 changes: 4 additions & 0 deletions src/Mapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ public function match() : void
// @todo добавить проверку на существование плейсхолдера с выбросом исключения
if (!empty($this->fillable['where'])) {
foreach($this->fillable['where'] as $key => $condition) {
if ($this->hasPlaceholderType($condition)) {
$pattern = str_replace('{$' . $key . '}', $this->getPlaceholderRegExp($condition), $pattern);
continue;
}
$pattern = str_replace('{$' . $key . '}', $condition, $pattern);
}
}
Expand Down
119 changes: 99 additions & 20 deletions src/Resolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@ class Resolver

private $matched;

private $languages =[];
private $languages = [];

private $currentLanguage;

private const ATTRIBUTE_ARRAY_DELIMITER = '/';

public function __construct(Mapper $mapper)
{
$this->mapper = $mapper;
Expand Down Expand Up @@ -65,10 +67,14 @@ private function buildResult() : Result
$result->handler = $matched->handler;
$result->action = $matched->action;
$result->language = $this->currentLanguage;

if (!empty($matched->where)) {
$where = $this->prepareWhere($matched->where, $matched->pattern);
$result->attributes = $this->assignAttributes($where, $matched->pattern);
$attributesTypesMap = $this->prepareTypes($matched->where);
$rawAttributes = $this->assignAttributes($where, $matched->pattern);
$result->attributes = $this->typeСonversion($rawAttributes, $attributesTypesMap);
ifedko marked this conversation as resolved.
Show resolved Hide resolved
}

return $result;
}

Expand Down Expand Up @@ -99,16 +105,13 @@ private function prepareLanguage()

private function assignAttributes(array $where, string $pattern) : array
{
$attributes = [];
$rawAttributes = [];

$uri = $this->request->getUri();

while (key($where) !== null) {
$pattern = str_replace('{$' . key($where) . '}', ' ', $pattern);
next($where);
}

$segments = explode(' ', $pattern);

$patternWithoutPlaceholders = $this->clearPlaceholdersInPattern($where, $pattern);

$segments = explode(' ', trim($patternWithoutPlaceholders, ' '));

foreach ($where as $key => $value) {

Expand All @@ -118,32 +121,108 @@ private function assignAttributes(array $where, string $pattern) : array

$delimiter = substr($value, 0, 1) === '(' ? ')' : substr($value, 0, 1);

$withNeedless = substr($value, 0, -1) . preg_quote($segments[0]) . $delimiter;
$segmentPattern = $this->makePattern($segments, $delimiter, $value);

preg_match($segmentPattern, $uri, $matched);

preg_match($withNeedless, $uri, $matched);

$rawAttributes[$key] = substr($matched[0], 0, -(strlen(current($segments))));
if (empty($segments)) {
$rawAttributes[$key] = $matched[0];
} else {
$rawAttributes[$key] = substr($matched[0], 0, -(strlen(current($segments))));
}

$uri = substr($uri, strlen($rawAttributes[$key]));
}

foreach ($rawAttributes as $key => $value) {
$attributes[$key] = is_numeric($value) ? intval($value) : $value;
}

return $attributes;
return $rawAttributes;
}

private function clearPlaceholdersInPattern(array $where, string $pattern)
{
while (key($where) !== null) {
$pattern = str_replace('{$' . key($where) . '}', ' ', $pattern);
next($where);
}
return $pattern;
}

private function makePattern(array $segments, string $delimiter, string $whereValue) : string
{
if (isset($segments[0]) === false) {
return substr($whereValue, 0, -1) . $delimiter;
}
return substr($whereValue, 0, -1) . preg_quote($segments[0]) . $delimiter;
}

private function prepareWhere(array $where, string $pattern) : array
{
preg_match_all('(\{\$[a-z]+\})', $pattern, $matched, PREG_SET_ORDER);
preg_match_all('(\{\$[a-zA-Z]+\})', $pattern, $matched, PREG_SET_ORDER);

$sortedWhere = [];

foreach ($matched as $value) {

$placeHolder = substr($value[0], 2, -1);

if ($this->mapper->hasPlaceholderType($where[$placeHolder])) {
$sortedWhere[$placeHolder] = $this->mapper->getPlaceholderRegExp($where[$placeHolder]);
continue;
}

$sortedWhere[$placeHolder] = $where[$placeHolder];
}

return $sortedWhere;
}

private function prepareTypes(array $where) : array
{
$attributesTypesMap = [];

foreach ($where as $placeHolder => $value) {

if ($this->mapper->hasPlaceholderType($value) === false) {
continue;
}

if (strtoupper($value) === Mapper::PLACEHOLDER_TYPE_INTEGER) {
$attributesTypesMap[$placeHolder] = Mapper::PLACEHOLDER_TYPE_INTEGER;
continue;
}

if (strtoupper($value) === Mapper::PLACEHOLDER_TYPE_ARRAY) {
$attributesTypesMap[$placeHolder] = Mapper::PLACEHOLDER_TYPE_ARRAY;
}
}

return $attributesTypesMap;
}

private function typeСonversion(array $rawAttributes, array $attributesTypesMap) : array
{
$attributes = [];

if (empty($attributesTypesMap)) {
return $rawAttributes;
}

foreach ($rawAttributes as $placeHolder => $value) {

if (array_key_exists($placeHolder, $attributesTypesMap) === false) {
$attributes[$placeHolder] = $value;
continue;
}

if ($attributesTypesMap[$placeHolder] === Mapper::PLACEHOLDER_TYPE_INTEGER) {
$attributes[$placeHolder] = intval($value);
continue;
}

if ($attributesTypesMap[$placeHolder] === Mapper::PLACEHOLDER_TYPE_ARRAY) {
$attributes[$placeHolder] = explode(self::ATTRIBUTE_ARRAY_DELIMITER, $value);
}
}

return $attributes;
}
}
12 changes: 12 additions & 0 deletions tests/unit/AbstractRouteHandlerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,18 @@

class AbstractRouteHandlerTest extends TestCase
{
public function testGetPlaceholderRegExp() : void
{
$routeHandler = self::routeHandler();
$this->assertEquals('([0-9]+)', $routeHandler->getPlaceholderRegExp('integer'));
}
ifedko marked this conversation as resolved.
Show resolved Hide resolved

public function testHasPlaceholderType() : void
{
$routeHandler = self::routeHandler();
$this->assertIsBool($routeHandler->hasPlaceholderType('integer'));
ifedko marked this conversation as resolved.
Show resolved Hide resolved
}

public function testRoute(): void
{
$routeHandler = self::routeHandler();
Expand Down