Skip to content
This repository has been archived by the owner on Mar 2, 2021. It is now read-only.

Commit

Permalink
Merge pull request #23 from chrisandchris/feature/auto-camel-case
Browse files Browse the repository at this point in the history
added type caster
  • Loading branch information
chrisandchris authored Jul 28, 2017
2 parents 4e0a9d4 + 15ff6c0 commit 1ea2816
Show file tree
Hide file tree
Showing 16 changed files with 371 additions and 91 deletions.
9 changes: 9 additions & 0 deletions changelog/v2.3.0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Changelog for v2.3.0

This file is the changelog for changes from version 2.2.4 to 2.3.0

## Additions
* added typecast function to cast fields when mapping, using "field_name::int" when building query (currently only in MySQL!)

## Changes
* to support typecast, the ParserInterface was extended with `::getMappingInfo()`
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

namespace ChrisAndChris\Common\RowMapperBundle\Exceptions\Mapping;

/**
*
*
* @name UnknownCastTypeException
* @version 1.0.0
* @since 1.0.0
* @package RowMapperBundle
* @author ChrisAndChris
* @link https://github.com/chrisandchris
*/
class UnknownCastTypeException extends MappingException
{

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ services:
arguments: ['@common_rowmapper.pdoLayer', '@common_rowmapper.rowmapperfactory', '@common_rowmapper.errorHandler', '@common_rowmapper.querybuilderfactory', '@service_container', '@event_dispatcher']
common_rowmapper.pdolayer:
class: ChrisAndChris\Common\RowMapperBundle\Services\Pdo\PdoLayer
arguments: [%database_driver%, %database_host%, %database_port%, %database_name%, %database_user%, %database_password%]
arguments: ['%database_driver%', '%database_host%', '%database_port%', '%database_name%', '%database_user%', '%database_password%']
common_rowmapper.rowmapper:
class: ChrisAndChris\Common\RowMapperBundle\Services\Mapper\RowMapper
arguments: ['@event_dispatcher']
arguments: ['@event_dispatcher', '@common_rowmapper.type_caster']
common_rowmapper.type_caster:
class: ChrisAndChris\Common\RowMapperBundle\Services\Mapper\TypeCaster
common_rowmapper.rowmapperfactory:
class: ChrisAndChris\Common\RowMapperBundle\Services\Mapper\RowMapperFactory
arguments: ['@event_dispatcher']
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
class RowMapper
{

/** @var \ChrisAndChris\Common\RowMapperBundle\Services\Mapper\TypeCaster */
public $typeCaster;
/**
* @var EncryptionServiceInterface[]
*/
Expand All @@ -37,11 +39,16 @@ class RowMapper
/**
* RowMapper constructor.
*
* @param EventDispatcherInterface $eventDispatcher
* @param EventDispatcherInterface $eventDispatcher
* @param \ChrisAndChris\Common\RowMapperBundle\Services\Mapper\TypeCaster $typeCaster
*/
public function __construct(EventDispatcherInterface $eventDispatcher)
public function __construct(
EventDispatcherInterface $eventDispatcher,
TypeCaster $typeCaster
)
{
$this->eventDispatcher = $eventDispatcher;
$this->typeCaster = $typeCaster;
}

/**
Expand Down Expand Up @@ -75,21 +82,27 @@ public function mapSingleFromResult(\PDOStatement $statement, Entity $entity)
/**
* Maps a result from a statement into an entity
*
* @param \PDOStatement $statement the statement to map
* @param Entity $entity the entity to use
* @param int $limit max amount of rows to map
* @return Entity[] list of mapped rows
* @param \PDOStatement $statement the statement to map
* @param Entity $entity the entity to use
* @param int $limit max amount of rows to map
* @param array $mappingInfo the mapping info (typecast)
* @return \ChrisAndChris\Common\RowMapperBundle\Entity\Entity[] list of mapped rows
*/
public function mapFromResult(\PDOStatement $statement, Entity $entity = null, $limit = null)
public function mapFromResult(
\PDOStatement $statement,
Entity $entity = null,
$limit = null,
array $mappingInfo = []
)
{
$return = [];
$count = 0;
while (false !== ($row = $statement->fetch(\PDO::FETCH_ASSOC)) &&
(++$count <= $limit || $limit === null)) {
if ($entity === null) {
$return[] = $this->mapRow($row);
$return[] = $this->mapRow($row, null, $mappingInfo);
} else {
$return[] = $this->mapRow($row, clone $entity);
$return[] = $this->mapRow($row, clone $entity, $mappingInfo);
}
}

Expand All @@ -107,13 +120,17 @@ public function mapFromResult(\PDOStatement $statement, Entity $entity = null, $
* <li>a "set" string is added to the beginning</li>
* </ul>
*
* @param array $row the single row to map
* @param array $row the single row to map
* @param $entity Entity entity to map to
* @return Entity|array $entity the mapped entity
* @throws DatabaseException if there is no such property
* @throws InvalidOptionException if a EmptyEntity instance is given
* @param array $mappingInfo the mapping info (typecast)
* @return array|\ChrisAndChris\Common\RowMapperBundle\Entity\Entity $entity the mapped entity
* @throws \ChrisAndChris\Common\RowMapperBundle\Exceptions\InvalidOptionException if a EmptyEntity instance is given
*/
public function mapRow(array $row, Entity $entity = null)
public function mapRow(
array $row,
Entity $entity = null,
array $mappingInfo = []
)
{
if ($entity instanceof EmptyEntity) {
throw new InvalidOptionException(
Expand All @@ -123,7 +140,7 @@ public function mapRow(array $row, Entity $entity = null)
if (!isset($entity)) {
$entity = new EmptyEntity();
}
$this->populateFields($row, $entity);
$this->populateFields($row, $entity, $mappingInfo);

$entity = $this->checkForDecryption($entity);

Expand All @@ -133,13 +150,22 @@ public function mapRow(array $row, Entity $entity = null)
/**
* @param array $row
* @param Entity $entity
* @throws DatabaseException
* @throws InsufficientPopulationException if strict entity is not fully populated
* @param array $mappingInfo the mapping info (typecast)
* @throws \ChrisAndChris\Common\RowMapperBundle\Exceptions\Mapping\InsufficientPopulationException if strict entity is not fully populated
*/
private function populateFields(array $row, Entity $entity)
public function populateFields(
array $row,
Entity $entity,
array $mappingInfo
)
{
$entityFiller = function (Entity &$entity, $field, $value) {
$entityFiller =
function (Entity &$entity, $field, $value, $mappingInfo) {
$methodName = $this->buildMethodName($field);
if (isset($mappingInfo[$field]) && $value !== null) {
$value = $this->getTypeCaster()
->cast($mappingInfo[$field], $value);
}
if (method_exists($entity, $methodName)) {
$entity->$methodName($value);

Expand All @@ -159,7 +185,7 @@ private function populateFields(array $row, Entity $entity)

$count = 0;
foreach ($row as $field => $value) {
$count += $entityFiller($entity, $field, $value);
$count += $entityFiller($entity, $field, $value, $mappingInfo);
}

if ($entity instanceof PopulateEntity) {
Expand Down Expand Up @@ -269,4 +295,9 @@ public function mapToArray($statement, Entity $entity, \Closure $callable)

return $return;
}

private function getTypeCaster()
{
return $this->typeCaster;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ public function __construct(EventDispatcherInterface $eventDispatcher)
public function getMapper()
{
$mapper = new RowMapper(
$this->eventDispatcher
$this->eventDispatcher,
new TypeCaster()
);
/** @var NewMapperEvent $event */
$event = $this->eventDispatcher->dispatch('rowMapperBundle.createNewMapper', new NewMapperEvent());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?php

namespace ChrisAndChris\Common\RowMapperBundle\Services\Mapper;

use ChrisAndChris\Common\RowMapperBundle\Exceptions\Mapping\UnknownCastTypeException;

/**
* Casts arbitrary values to specified values
*
* @name TypeCaster
* @version 1.0.0
* @since 1.0.0
* @package RowMapperBundle
* @author ChrisAndChris
* @link https://github.com/chrisandchris
*/
class TypeCaster
{

/** @var array */
public $casts;

/**
* TypeCaster constructor.
*/
public function __construct()
{
$this->casts = [
'int' => [$this, 'castInt'],
'json' => [$this, 'castJson'],
];
}

public function cast($targetType, $value)
{
if (!isset($this->casts[$targetType])) {
throw new UnknownCastTypeException(sprintf(
'Cannot cast to unknown type %s',
$targetType
));
}

return call_user_func($this->casts[$targetType], $value);
}

/**
* @param $value
* @return int
*/
public function castInt($value)
{
return (int)$value;
}

public function castJson($value)
{
return json_decode($value, true);
}

public function castDate($value)
{
if ($value instanceof \DateTime) {
return $value;
}

return new \DateTime($value);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public function isOnlyOption(array $options, $optionName, array $allowAlways = [
}

/**
* Runs a query
* Runs a query and maps the result to $entity
*
* @param SqlQuery $query
* @param Entity $entity
Expand All @@ -89,7 +89,8 @@ public function run(SqlQuery $query, Entity $entity, \Closure $callAfter = null)
{
$stmt = $this->prepare($query);

return $this->handle($stmt, $entity, $callAfter);
return $this->handle($stmt, $entity, $callAfter,
$query->getMappingInfo());
}

/**
Expand Down Expand Up @@ -153,15 +154,24 @@ public function getDependencyProvider()
*
* @param PdoStatement $statement
* @param Entity $entity
* @param \Closure|null $callAfter a callable to call after the mapping is
* done
* @return bool|entity[]
* @param \Closure|null $callAfter callback to run after mapping is done
* @param array $mappingInfo the mapping info to use (typecast)
* @return bool|\ChrisAndChris\Common\RowMapperBundle\Entity\Entity[]
*/
private function handle(PdoStatement $statement, Entity $entity = null, \Closure $callAfter = null)
private function handle(
PdoStatement $statement,
Entity $entity = null,
\Closure $callAfter = null,
array $mappingInfo = []
)
{
return $this->handleGeneric(
$statement,
function (PdoStatement $statement) use ($entity, $callAfter) {
function (PdoStatement $statement) use (
$entity,
$callAfter,
$mappingInfo
) {
if ((int)$statement->errorCode() != 0 || $statement->errorInfo()[1] != null) {
return $this->handleError($statement);
}
Expand All @@ -170,7 +180,8 @@ function (PdoStatement $statement) use ($entity, $callAfter) {
}

$mapping = $this->getMapper()
->mapFromResult($statement, $entity);
->mapFromResult($statement, $entity, null,
$mappingInfo);

if ($callAfter instanceof \Closure) {
$callAfter($mapping);
Expand All @@ -182,12 +193,10 @@ function (PdoStatement $statement) use ($entity, $callAfter) {
}

/**
* Generic handle method
* Does low-level handling of the query
*
* @param PdoStatement $statement
* @param \Closure $mappingCallback a callback taking the
* statement as first and only
* argument
* @param \Closure $mappingCallback callback to map results
* @return mixed
* @throws NoSuchRowFoundException
*/
Expand Down Expand Up @@ -428,7 +437,8 @@ function (KeyValueEntity $entity) {
* Validates whether the given statement has a row count greater than zero
*
* @param SqlQuery $query
* @return bool whether there is at least one result row or notgit l
* @return bool whether there is at least one result row or not
* @deprecated use SqlQuery::requiresResult() instead and throw exception
*/
public function handleHasResult(SqlQuery $query)
{
Expand All @@ -442,6 +452,7 @@ public function handleHasResult(SqlQuery $query)
* @param bool $forceEqual if set to true, only a row count of one and
* only one returns true
* @return bool whether there is a row or not
* @deprecated use SqlQuery::requiresResult() instead and throw exception
*/
public function handleHas(SqlQuery $query, $forceEqual = true)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ public function equals()
* <br />
* database:table:field parses to database.table.field
*
* @param string $identifier path of field or field name
* @param string|array $identifier path of field or field name
* @return $this
*/
public function field($identifier)
Expand Down Expand Up @@ -909,7 +909,8 @@ public function getSqlQuery(ParserInterface $parser = null)
$query = new SqlQuery(
$parser->getSqlQuery(),
$parser->getParameters(),
$calcRowCapable
$calcRowCapable,
$parser->getMappingInfo()
);
}
$this->clear();
Expand Down
Loading

0 comments on commit 1ea2816

Please sign in to comment.