Skip to content

Commit

Permalink
Merge pull request #5 from netiul/feature/extract-type-casting
Browse files Browse the repository at this point in the history
Extract type cast behaviour
  • Loading branch information
weierophinney authored Jan 7, 2021
2 parents 74736f9 + 97eb983 commit 02793df
Show file tree
Hide file tree
Showing 91 changed files with 1,867 additions and 758 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/.phpcs-cache
/.phpunit.result.cache
/clover.xml
/composer.lock
/coveralls-upload.json
/phpunit.xml
/vendor/
.phpunit.result.cache
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ All notable changes to this project will be documented in this file, in reverse

### Added

- [#5](https://github.com/laminas-api-tools/api-tools-doctrine-querybuilder/pull/5) adds the interface `Laminas\ApiTools\Doctrine\QueryBuilder\Filter\TypeCastInterface` and the default implementations `Laminas\ApiTools\Doctrine\QueryBuilder\Filter\ODM\TypeCaster` and `Laminas\ApiTools\Doctrine\QueryBuilder\ORM\TypeCaster`, extracted from logic originally present in the ORM and ODM `AbstractFilter` implementations. Users can supply their own implementation by aliasing the `Laminas\ApiTools\Doctrine\QueryBuilder\Filter\TypeCastInterface` service to their own implementation. This ability allows users to supply their own type casting rules for their projects.

- [#12](https://github.com/laminas-api-tools/api-tools-doctrine-querybuilder/pull/12) adds support for PHP 7.3, 7.4, and 8.0.

### Changed
Expand Down
43 changes: 43 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -442,3 +442,46 @@ Field:
```php
['type' => 'field', 'field' => 'fieldName', 'direction' => 'desc']
```

Custom MappingTypes
-------------------

In case you have [custom mapping types](https://www.doctrine-project.org/projects/doctrine-orm/en/latest/cookbook/custom-mapping-types.html)
configured, you can substitute the supplied `Laminas\ApiTools\Doctrine\QueryBuilder\Filter\TypeCastInterface`
implementation with your own implementation.

As an example, given a custom type caster implentation as follows:

```php
namespace My\Custom;

class TypeCaster implements \Laminas\ApiTools\Doctrine\QueryBuilder\Filter\TypeCastInterface
{
public function typeCastField($metadata, $field, $value, $format = null, $doNotTypecastDatetime = false)
{
// implement your type casting logic
}
}
```

You will then provide a factory for your implementation, and alias the package `TypeCastInterface` to it:

```php
// config/autoload/api-tools-doctrine-querybuilder-global.php

use Laminas\ApiTools\Doctrine\QueryBuilder\Filter\TypeCastInterface;
use Laminas\ServiceManager\Factory\InvokableFactory;
use My\Custom\TypeCaster;

return [
'service_manager => [
'aliases' => [
TypeCastInterface::class => TypeCaster::class,
],
'factories' => [
TypeCaster::class => InvokableFactory::class,
],
],
];
```

30 changes: 19 additions & 11 deletions config/module.config.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,37 @@

namespace Laminas\ApiTools\Doctrine\QueryBuilder;

use Laminas\ServiceManager\Factory\InvokableFactory;
use ZF\Doctrine\QueryBuilder\Filter\Service\ODMFilterManager;
use ZF\Doctrine\QueryBuilder\Filter\Service\ORMFilterManager;
use ZF\Doctrine\QueryBuilder\OrderBy\Service\ODMOrderByManager;
use ZF\Doctrine\QueryBuilder\OrderBy\Service\ORMOrderByManager;

return [
'service_manager' => [
'aliases' => [
'LaminasDoctrineQueryBuilderFilterManagerOrm' => Filter\Service\ORMFilterManager::class,
'LaminasDoctrineQueryBuilderFilterManagerOdm' => Filter\Service\ODMFilterManager::class,
'aliases' => [
'LaminasDoctrineQueryBuilderFilterManagerOrm' => Filter\Service\ORMFilterManager::class,
'LaminasDoctrineQueryBuilderFilterManagerOdm' => Filter\Service\ODMFilterManager::class,
'LaminasDoctrineQueryBuilderOrderByManagerOrm' => OrderBy\Service\ORMOrderByManager::class,
'LaminasDoctrineQueryBuilderOrderByManagerOdm' => OrderBy\Service\ODMOrderByManager::class,

// Legacy Zend Framework aliases
'ZfDoctrineQueryBuilderFilterManagerOrm' => 'LaminasDoctrineQueryBuilderFilterManagerOrm',
'ZfDoctrineQueryBuilderFilterManagerOdm' => 'LaminasDoctrineQueryBuilderFilterManagerOdm',
'ZfDoctrineQueryBuilderFilterManagerOrm' => 'LaminasDoctrineQueryBuilderFilterManagerOrm',
'ZfDoctrineQueryBuilderFilterManagerOdm' => 'LaminasDoctrineQueryBuilderFilterManagerOdm',
'ZfDoctrineQueryBuilderOrderByManagerOrm' => 'LaminasDoctrineQueryBuilderOrderByManagerOrm',
'ZfDoctrineQueryBuilderOrderByManagerOdm' => 'LaminasDoctrineQueryBuilderOrderByManagerOdm',
\ZF\Doctrine\QueryBuilder\Filter\Service\ORMFilterManager::class => Filter\Service\ORMFilterManager::class,
\ZF\Doctrine\QueryBuilder\Filter\Service\ODMFilterManager::class => Filter\Service\ODMFilterManager::class,
\ZF\Doctrine\QueryBuilder\OrderBy\Service\ORMOrderByManager::class => OrderBy\Service\ORMOrderByManager::class,
\ZF\Doctrine\QueryBuilder\OrderBy\Service\ODMOrderByManager::class => OrderBy\Service\ODMOrderByManager::class,
ORMFilterManager::class => Filter\Service\ORMFilterManager::class,
ODMFilterManager::class => Filter\Service\ODMFilterManager::class,
ORMOrderByManager::class => OrderBy\Service\ORMOrderByManager::class,
ODMOrderByManager::class => OrderBy\Service\ODMOrderByManager::class,
],
'factories' => [
Filter\Service\ORMFilterManager::class => Filter\Service\ORMFilterManagerFactory::class,
Filter\Service\ODMFilterManager::class => Filter\Service\ODMFilterManagerFactory::class,
Filter\Service\ORMFilterManager::class => Filter\Service\ORMFilterManagerFactory::class,
Filter\Service\ODMFilterManager::class => Filter\Service\ODMFilterManagerFactory::class,
OrderBy\Service\ORMOrderByManager::class => OrderBy\Service\ORMOrderByManagerFactory::class,
OrderBy\Service\ODMOrderByManager::class => OrderBy\Service\ODMOrderByManagerFactory::class,
Filter\ORM\TypeCaster::class => InvokableFactory::class,
Filter\ODM\TypeCaster::class => InvokableFactory::class,
],
],
];
10 changes: 0 additions & 10 deletions phpcs.xml

This file was deleted.

28 changes: 28 additions & 0 deletions phpcs.xml.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?xml version="1.0"?>
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="vendor/squizlabs/php_codesniffer/phpcs.xsd">

<arg name="basepath" value="."/>
<arg name="cache" value=".phpcs-cache"/>
<arg name="colors"/>
<arg name="extensions" value="php"/>
<arg name="parallel" value="80"/>

<!-- Show progress -->
<arg value="p"/>

<!-- Paths to check -->
<file>config</file>
<file>config/api-tools-doctrine-querybuilder.global.php.dist</file>
<file>src</file>
<file>test</file>

<!-- Include all rules from the Laminas Coding Standard -->
<rule ref="LaminasCodingStandard"/>

<rule ref="Generic.Files.LineLength">
<properties>
<property name="lineLimit" value="121"/>
</properties>
</rule>
</ruleset>
9 changes: 9 additions & 0 deletions src/Filter/FilterInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,16 @@

namespace Laminas\ApiTools\Doctrine\QueryBuilder\Filter;

use Doctrine\ODM\MongoDB\Query\Builder;
use Doctrine\ORM\QueryBuilder;

interface FilterInterface
{
/**
* @param QueryBuilder|Builder $queryBuilder
* @param object $metadata
* @param array $option
* @return void
*/
public function filter($queryBuilder, $metadata, $option);
}
103 changes: 43 additions & 60 deletions src/Filter/ODM/AbstractFilter.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,74 +8,57 @@

namespace Laminas\ApiTools\Doctrine\QueryBuilder\Filter\ODM;

use DateTime;
use Doctrine\ODM\MongoDB\Query\Builder;
use Laminas\ApiTools\Doctrine\QueryBuilder\Filter\FilterInterface;
use Laminas\ApiTools\Doctrine\QueryBuilder\Filter\TypeCastInterface;

abstract class AbstractFilter implements FilterInterface
{
/**
* @param Builder $queryBuilder
* @param object $metadata
* @param array $option
* @return void
*/
abstract public function filter($queryBuilder, $metadata, $option);

protected function typeCastField($metadata, $field, $value, $format = null, $doNotTypecastDatetime = false)
/** @var TypeCastInterface */
protected $typeCaster;

public function __construct(array $params = [])
{
if (! isset($metadata->fieldMappings[$field])) {
return $value;
}
$this->setTypeCaster($params['type_caster'] ?? new TypeCaster());
}

switch ($metadata->fieldMappings[$field]['type']) {
case 'int':
settype($value, 'integer');
break;
case 'boolean':
settype($value, 'boolean');
break;
case 'float':
settype($value, 'float');
break;
case 'string':
settype($value, 'string');
break;
case 'bin_data_custom':
break;
case 'bin_data_func':
break;
case 'bin_data_md5':
break;
case 'bin_data':
break;
case 'bin_data_uuid':
break;
case 'collection':
break;
case 'custom_id':
break;
case 'date':
if ($value && ! $doNotTypecastDatetime) {
if (! $format) {
$format = 'Y-m-d H:i:s';
}
$value = DateTime::createFromFormat($format, $value);
}
break;
case 'file':
break;
case 'hash':
break;
case 'id':
break;
case 'increment':
break;
case 'key':
break;
case 'object_id':
break;
case 'raw_type':
break;
case 'timestamp':
break;
default:
break;
}
/**
* @return $this
*/
public function setTypeCaster(TypeCastInterface $typeCaster)
{
$this->typeCaster = $typeCaster;
return $this;
}

/**
* @return TypeCastInterface
*/
protected function getTypeCaster()
{
return $this->typeCaster;
}

return $value;
/**
* @param object $metadata
* @param string|int|float $value
* @return mixed
*/
protected function typeCastField(
$metadata,
string $field,
$value,
?string $format = null,
bool $doNotTypecastDatetime = false
) {
return $this->getTypeCaster()->typeCastField($metadata, $field, $value, $format, $doNotTypecastDatetime);
}
}
5 changes: 4 additions & 1 deletion src/Filter/ODM/Between.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@

class Between extends AbstractFilter
{
/**
* {@inheritDoc}
*/
public function filter($queryBuilder, $metadata, $option)
{
$queryType = 'addAnd';
Expand All @@ -22,7 +25,7 @@ public function filter($queryBuilder, $metadata, $option)
}
}

$format = isset($option['format']) ? $option['format'] : null;
$format = $option['format'] ?? null;

$from = $this->typeCastField($metadata, $option['field'], $option['from'], $format);
$to = $this->typeCastField($metadata, $option['field'], $option['to'], $format);
Expand Down
5 changes: 4 additions & 1 deletion src/Filter/ODM/Equals.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@

class Equals extends AbstractFilter
{
/**
* {@inheritDoc}
*/
public function filter($queryBuilder, $metadata, $option)
{
$queryType = 'addAnd';
Expand All @@ -22,7 +25,7 @@ public function filter($queryBuilder, $metadata, $option)
}
}

$format = isset($option['format']) ? $option['format'] : null;
$format = $option['format'] ?? null;

$value = $this->typeCastField($metadata, $option['field'], $option['value'], $format);

Expand Down
5 changes: 4 additions & 1 deletion src/Filter/ODM/GreaterThan.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@

class GreaterThan extends AbstractFilter
{
/**
* {@inheritDoc}
*/
public function filter($queryBuilder, $metadata, $option)
{
$queryType = 'addAnd';
Expand All @@ -22,7 +25,7 @@ public function filter($queryBuilder, $metadata, $option)
}
}

$format = isset($option['format']) ? $option['format'] : null;
$format = $option['format'] ?? null;

$value = $this->typeCastField($metadata, $option['field'], $option['value'], $format);

Expand Down
5 changes: 4 additions & 1 deletion src/Filter/ODM/GreaterThanOrEquals.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@

class GreaterThanOrEquals extends AbstractFilter
{
/**
* {@inheritDoc}
*/
public function filter($queryBuilder, $metadata, $option)
{
$queryType = 'addAnd';
Expand All @@ -22,7 +25,7 @@ public function filter($queryBuilder, $metadata, $option)
}
}

$format = isset($option['format']) ? $option['format'] : null;
$format = $option['format'] ?? null;

$value = $this->typeCastField($metadata, $option['field'], $option['value'], $format);

Expand Down
7 changes: 5 additions & 2 deletions src/Filter/ODM/In.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@

class In extends AbstractFilter
{
/**
* {@inheritDoc}
*/
public function filter($queryBuilder, $metadata, $option)
{
$queryType = 'addAnd';
Expand All @@ -21,11 +24,11 @@ public function filter($queryBuilder, $metadata, $option)
}
}

$format = isset($option['format']) ? $option['format'] : null;
$format = $option['format'] ?? null;

$queryValues = [];
foreach ($option['values'] as $value) {
$queryValues[] = $this->typeCastField(
$queryValues[] = $this->typeCastField(
$metadata,
$option['field'],
$value,
Expand Down
3 changes: 3 additions & 0 deletions src/Filter/ODM/IsNotNull.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@

class IsNotNull extends AbstractFilter
{
/**
* {@inheritDoc}
*/
public function filter($queryBuilder, $metadata, $option)
{
$queryType = 'addAnd';
Expand Down
Loading

0 comments on commit 02793df

Please sign in to comment.