Skip to content

Commit

Permalink
Merge pull request #66 from lmc-eu/feature/update-dev-dependencies
Browse files Browse the repository at this point in the history
Update readme and fix codestyle
  • Loading branch information
MortalFlesh committed May 6, 2020
2 parents 1fafc8a + 199a0e7 commit cca5ad0
Show file tree
Hide file tree
Showing 27 changed files with 89 additions and 93 deletions.
52 changes: 23 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -400,19 +400,18 @@ Result:
```

## Functions in filters
With function you can handle all kinds of situations, which might be problematic with just a simple filters like `eq`, etc.

Let's see how to work with functions and what is required to do. We will show it right on the example.
With function you can handle all kinds of problems, which might be problematic with just a simple filters like `eq`, etc.

### Example for `fullName` function
Let's see how to work with functions and what is required to do. We will show it right on the example.

#### Expected api
```http request
GET http://host/endpoint?fullName=(Jon,Snow)
```
☝️ _this shows what we want to offer to our consumers. It's easy and explicit enough._
☝️ example above shows what we want to offer to our consumers. It's easy and explicit enough.

It may even hide some inner differences, for example with simple filters, database column must have same name as the field in the filter, but with function, we can change it.
It may even hide some inner differences, for example with simple filters, database column must have same name as field in filter, but with function, we can change it.

Let's say that in database we have something like:
```fs
Expand All @@ -432,15 +431,15 @@ $apiFilter->declareFunction(
'fullName',
[
new ParameterDefinition('firstName', 'eq', 'first_name'), // parameter name and field name are different, so we need to define it
'lastname`, // parameter name and field name are the same and we use the implicit `eq` filter, so it is defined simply
'lastname`, // parameter name and field name are the same and we use the implicit `eq` filter, so it is defined simply
]
);
```
Method `declareFunction` will create a function with filters based on parameters.
_There is also [registerFunction](#register-and-execute-function) method, which allows you to pass any function you want. This may be useful when you don't need filter functionality at all or have some custom logic/storage, etc._
Method `declareFunction` will create a function with filters based on parameters.
_There is also `registerFunction` method, which allows you to pass any function you want. This may be useful when you dont need filter functionality at all or have some custom storage, etc._

#### Parsing and applying filters
Now when request with `?fullName=(Jon,Snow)` comes, `ApiFilter` can parse it to:
Now when request with `?fullName=(Jon,Snow)` come, `ApiFilter` can parse it to:
```php
// in service/controller/...
$sql = 'SELECT * FROM person';
Expand Down Expand Up @@ -473,11 +472,7 @@ $filters = $apiFilter->parseFilters($request->query->all());
// ]

$appliedSql = $apiFilter->applyFilters($filters, $sql);
// SELECT *
// FROM person
// WHERE
// first_name = :firstName_function_parameter AND
// lastname = :lastname_function_parameter
// SELECT * FROM person WHERE first_name = :firstName_function_parameter AND lastname = :lastname_function_parameter

$preparedValues = $apiFilter->getPreparedValues($filters, $sql);
// [
Expand All @@ -493,36 +488,36 @@ All examples below results the same. We have that many options, so we can allow
### Explicit function call
GET http://host/endpoint?fullName=(Jon,Snow)
### Explicit function call with values
### Explicit function call with values
GET http://host/endpoint?function=fullName&firstName=Jon&lastname=Snow
### Implicit function call by values
GET http://host/endpoint?firstName=Jon&lastname=Snow
### Explicit function call by tuple
### Explicit function call by tuple
GET http://host/endpoint?(function,firstName,surname)=(fullName, Jon, Snow)
### Implicit function call by tuple
GET http://host/endpoint?(firstName,surname)=(Jon, Snow)
### Explicit function call by filter parameter
### Explicit function call by filter parameter
GET http://host/endpoint?filter[]=(fullName,Jon,Snow)
```

### Function Parameters Definition
To `declare` or `register` function, you have to define its parameters. There are many ways/needs to do it.

#### Defined as string
This is the easiest way to do it. You just define a parameter(s) name.

```php
$apiFilter->declareFunction('fullName', ['firstName', 'surname']);
```
This is the easiest way to do it. You just define a name.

It means:
- you want `eq` filter (_or `IN` for array_) and the column name and parameter name are the same
- the value for this parameter is mandatory

```php
$apiFilter->declareFunction('fullName', ['firstName', 'surname']);
```

#### Defined as array
This allows you to pass more options for a paramater.

Expand All @@ -533,25 +528,24 @@ $apiFilter->declareFunction('fullName', [['firstName'], ['surname']]);
```

##### More than one item
It means
- `firstName` parameter uses `eq` filter, has `first_name` column in storage and is mandatory
- `surname` parameter uses `eq` filter, has `lastname` column in storage and its value is `Snow` (_which will always be used and no value can override it_)
```php
$apiFilter->declareFunction('fullName', [
['firstName', 'eq', 'first_name'],
['surname', 'eq', 'lastname', 'Snow']
]);
```

It means
- `firstName` parameter uses `eq` filter, has `first_name` column in a storage and is mandatory
- `surname` parameter uses `eq` filter, has `lastname` column in a storage and its value is `Snow` (_which will always be used and no value can override it_)

#### Defined as object
This allows you to pass same options as with the array, but explicitly defined in the object. (_It even has some special constructor methods to simplify special needs._)
This allows you to pass same options as with the array, but explicitly defined object. (_It even has some special constructor methods to simplify creation_)
```php
$apiFilter->declareFunction('fullName', [
new ParameterDefinition('firstName', 'eq', 'first_name'),
new ParameterDefinition('surname', 'eq', 'lastname, new Value('Snow'))
]);
```
```

#### Combinations
All options can be combined to best suite the parameter.
Expand Down Expand Up @@ -585,7 +579,7 @@ $apiFilter->registerFunction(
function (\PDO $client, FunctionParameter $query): \PDOStatement {
return $client->query($query->getValue()->getValue());
}
)
);

// in service/controller/...
$statement = $apiFilter->executeFunction('sql', $queryParameters, $client); // \PDOStatement
Expand Down
21 changes: 11 additions & 10 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,15 @@
"doctrine/orm": "To allow applying filters directly to QueryBuilder"
},
"require-dev": {
"doctrine/orm": "^2.6",
"lmc/coding-standard": "^1.1",
"mockery/mockery": "^1.1",
"php-coveralls/php-coveralls": "^2.1",
"phpstan/phpstan-beberlei-assert": "^0.10.0",
"phpstan/phpstan-mockery": "^0.10.2",
"phpstan/phpstan-shim": "^0.10",
"phpunit/phpunit": "^7.0"
"doctrine/orm": "^2.7",
"lmc/coding-standard": "^2.0",
"mockery/mockery": "^1.3",
"php-coveralls/php-coveralls": "^2.2",
"phpstan/extension-installer": "^1.0",
"phpstan/phpstan": "^0.12.23",
"phpstan/phpstan-beberlei-assert": "^0.12.2",
"phpstan/phpstan-mockery": "^0.12.5",
"phpunit/phpunit": "^7.5"
},
"config": {
"sort-packages": true
Expand All @@ -46,7 +47,7 @@
"phpstan": "vendor/bin/phpstan analyze ./src ./tests -c phpstan.neon --ansi --level 7",
"tests": "vendor/bin/phpunit",
"tests-ci": "mkdir -p reports && php -dxdebug.coverage_enable=1 vendor/bin/phpunit -c phpunit.xml.dist",
"cs": "vendor/bin/ecs check -vv --ansi src/ tests/",
"fix": "vendor/bin/ecs check -vv --ansi --clear-cache --fix src/ tests/"
"cs": "vendor/bin/ecs check --ansi src/ tests/",
"fix": "vendor/bin/ecs check --ansi --clear-cache --fix src/ tests/"
}
}
2 changes: 1 addition & 1 deletion easy-coding-standard.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
imports:
- { resource: '%vendor_dir%/lmc/coding-standard/easy-coding-standard.yaml' }
- { resource: 'vendor/lmc/coding-standard/easy-coding-standard.yaml' }

parameters:
skip:
Expand Down
5 changes: 2 additions & 3 deletions phpstan.neon
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
includes:
- vendor/phpstan/phpstan-beberlei-assert/extension.neon
- vendor/phpstan/phpstan-mockery/extension.neon
parameters:
checkMissingIterableValueType: false
2 changes: 1 addition & 1 deletion src/ApiFilter.php
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ public function registerApplicator(ApplicatorInterface $applicator, int $priorit
* @param array $parameters names or definition of needed parameters (parameters will be passed to function in given order)
* @throws ApiFilterExceptionInterface
*/
public function declareFunction(string $functionName, array $parameters)
public function declareFunction(string $functionName, array $parameters): self
{
$parameters = $this->functionCreator->normalizeParameters($parameters);

Expand Down
3 changes: 2 additions & 1 deletion src/Assertion.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class Assertion extends BaseAssertion
* @param mixed $value
* @param string|callable|null $message
*/
public static function isTuple($value, $message = null, ?string $propertyPath = null)
public static function isTuple($value, $message = null, ?string $propertyPath = null): bool
{
if (self::isTupleValue($value)) {
return true;
Expand All @@ -30,6 +30,7 @@ public static function isTuple($value, $message = null, ?string $propertyPath =
throw static::createException($value, $message, 0, $propertyPath);
}

/** @param mixed $value */
private static function isTupleValue($value): bool
{
return $value instanceof ITuple || (is_string($value) && mb_substr($value, 0, 1) === '(');
Expand Down
3 changes: 3 additions & 0 deletions src/Exception/InvalidArgumentException.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ class InvalidArgumentException extends \InvalidArgumentException implements ApiF
/** @var array */
private $constraints;

/**
* @param mixed $value
*/
public function __construct(
string $message,
int $code = null,
Expand Down
2 changes: 1 addition & 1 deletion src/Exception/TupleException.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ class TupleException extends InvalidArgumentException implements TupleExceptionI
{
public static function forBaseTupleException(TupleExceptionInterface $e): self
{
return new static($e->getMessage(), $e->getCode(), null, null, [], $e);
return new self($e->getMessage(), $e->getCode(), null, null, [], $e);
}
}
2 changes: 1 addition & 1 deletion src/Exception/UnknownFilterException.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class UnknownFilterException extends InvalidArgumentException
{
public static function forFilterWithColumnAndValue(string $filter, string $column, Value $value): self
{
return new static(
return new self(
sprintf(
'Filter "%s" is not implemented. For column "%s" with value "%s".',
$filter,
Expand Down
2 changes: 1 addition & 1 deletion src/Exception/UnsupportedFilterException.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ class UnsupportedFilterException extends InvalidArgumentException
{
public static function forFilter(FilterInterface $filter): self
{
return new static(sprintf('Unsupported filter given "%s".', get_class($filter)));
return new self(sprintf('Unsupported filter given "%s".', get_class($filter)));
}
}
2 changes: 1 addition & 1 deletion src/Exception/UnsupportedFilterableException.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public static function forFilterable(Filterable $filterable): self
{
$filterableValue = $filterable->getValue();

return new static(
return new self(
sprintf(
'Unsupported filterable of type "%s".',
is_object($filterableValue)
Expand Down
7 changes: 5 additions & 2 deletions src/Filters/Filters.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

class Filters implements FiltersInterface
{
/** @var IList|FilterInterface[] */
/** @var IList<FilterInterface> */
private $filters;

/** @param FilterInterface[] $filters */
Expand All @@ -27,7 +27,10 @@ public static function from(array $filters): FiltersInterface
/** @param FilterInterface[] $filters */
public function __construct(array $filters = [])
{
$this->filters = ListCollection::fromT(FilterInterface::class, $filters);
/** @var IList<FilterInterface> $filterCollection */
$filterCollection = ListCollection::fromT(FilterInterface::class, $filters);

$this->filters = $filterCollection;
}

/**
Expand Down
12 changes: 6 additions & 6 deletions src/Service/FunctionCreator.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,8 @@ public function normalizeParameters(array $parameters): IMap
}

/**
* @see FunctionCreator::normalizeParameters()
*
* @param ParameterDefinition[]|IMap $normalizedParameters IMap<string, Parameter>
* @see FunctionCreator::normalizeParameters()
*/
public function getParameterNames(IMap $normalizedParameters): array
{
Expand All @@ -59,9 +58,8 @@ public function getParameterNames(IMap $normalizedParameters): array
}

/**
* @see FunctionCreator::normalizeParameters()
*
* @param ParameterDefinition[]|IMap $normalizedParameters IMap<string, Parameter>
* @see FunctionCreator::normalizeParameters()
*/
public function createByParameters(FilterApplicator $applicator, IMap $normalizedParameters): callable
{
Expand All @@ -75,6 +73,9 @@ public function createByParameters(FilterApplicator $applicator, IMap $normalize
};
}

/**
* @param mixed $parameter
*/
private function assertParameter($parameter): void
{
Assertion::true(
Expand Down Expand Up @@ -126,10 +127,9 @@ private function getParameterByDefinition(array $parameters, string $name): Func
}

/**
* @see FunctionCreator::normalizeParameters()
*
* @param ParameterDefinition[]|IMap $normalizedParameters IMap<string, Parameter>
* @return ParameterDefinition[]
* @see FunctionCreator::normalizeParameters()
*/
public function getParameterDefinitions(IMap $normalizedParameters): array
{
Expand Down
6 changes: 6 additions & 0 deletions src/Service/Parser/AbstractParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ public function __construct(FilterFactory $filterFactory)
$this->filterFactory = $filterFactory;
}

/**
* @param string|array $value
*/
protected function isTuple($value): bool
{
return is_string($value) && mb_substr($value, 0, 1) === '(';
Expand All @@ -40,6 +43,9 @@ protected function isColumnWithFilter(string $column): bool
return mb_strpos($column, '[') !== false || mb_strpos($column, ']') !== false;
}

/**
* @param mixed $value
*/
protected function createFilter(string $column, string $filter, $value): FilterInterface
{
return $this->filterFactory->createFilter($column, $filter, new Value($value));
Expand Down
3 changes: 3 additions & 0 deletions src/Service/Parser/FunctionParser/AbstractFunctionParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ final public function supports(string $rawColumn, $rawValue): bool
return $this->supportsParameters($this->assertQueryParameters(), $rawColumn, $rawValue);
}

/**
* @param string|array $rawValue Raw value from query parameters
*/
abstract protected function supportsParameters(array $queryParameters, string $rawColumn, $rawValue): bool;

private function assertQueryParameters(): array
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,11 @@

class ExplicitFunctionDefinitionParser extends AbstractFunctionParser
{
/**
* @param string|array $rawValue Raw value from query parameters
*/
protected function supportsParameters(array $queryParameters, string $rawColumn, $rawValue): bool
{
return !$this->isTuple($rawColumn) && $this->functions->isFunctionRegistered($rawColumn);
}

/**
* @param string|array $rawValue Raw value from query parameters
*/
protected function parseParameters(array $queryParameters, string $rawColumn, $rawValue): iterable
{
if (!$this->functions->isFunctionRegistered($rawColumn)) {
Expand All @@ -41,6 +35,9 @@ protected function parseParameters(array $queryParameters, string $rawColumn, $r
}
}

/**
* @param string|array $rawValue Raw value from query parameters
*/
protected function assertSingleStringValue($rawValue): void
{
Assertion::false(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,6 @@ protected function supportsParameters(array $queryParameters, string $rawColumn,
return array_key_exists(Column::FILTER, $queryParameters);
}

/**
* @param string|array $rawValue Raw value from query parameters
*/
protected function parseParameters(array $queryParameters, string $rawColumn, $rawValue): iterable
{
if ($this->isColumnParsed(Column::FILTER)) {
Expand Down
Loading

0 comments on commit cca5ad0

Please sign in to comment.