Optimize mapper loops

This commit is contained in:
Dennis Eichhorn 2018-05-21 17:48:41 +02:00
parent aa89b83746
commit 71a13da619
5 changed files with 92 additions and 96 deletions

View File

@ -15,6 +15,7 @@ declare(strict_types=1);
namespace phpOMS\DataStorage\Database; namespace phpOMS\DataStorage\Database;
use phpOMS\DataStorage\Database\Connection\ConnectionAbstract; use phpOMS\DataStorage\Database\Connection\ConnectionAbstract;
use phpOMS\DataStorage\Database\Query\QueryType;
/** /**
* Database query builder. * Database query builder.
@ -48,7 +49,7 @@ abstract class BuilderAbstract
* @var int * @var int
* @since 1.0.0 * @since 1.0.0
*/ */
protected $type = null; protected $type = QueryType::EMPTY;
/** /**
* Prefix. * Prefix.

View File

@ -20,6 +20,7 @@ use phpOMS\DataStorage\DataMapperInterface;
use phpOMS\Message\RequestAbstract; use phpOMS\Message\RequestAbstract;
use phpOMS\DataStorage\Database\Exception\InvalidMapperException; use phpOMS\DataStorage\Database\Exception\InvalidMapperException;
use phpOMS\Util\ArrayUtils; use phpOMS\Util\ArrayUtils;
use phpOMS\DataStorage\Database\Query\QueryType;
/** /**
* Datamapper for databases. * Datamapper for databases.
@ -400,33 +401,29 @@ class DataMapperAbstract implements DataMapperInterface
$query = new Builder(self::$db); $query = new Builder(self::$db);
$query->prefix(self::$db->getPrefix())->into(static::$table); $query->prefix(self::$db->getPrefix())->into(static::$table);
$properties = $refClass->getProperties(); foreach (static::$columns as $key => $column) {
$propertyName = $column['internal'];
foreach ($properties as $property) {
$propertyName = $property->getName();
if (isset(static::$hasMany[$propertyName]) || isset(static::$hasOne[$propertyName])) { if (isset(static::$hasMany[$propertyName]) || isset(static::$hasOne[$propertyName])) {
continue; continue;
} }
$property = $refClass->getProperty($propertyName);
if (!($isPublic = $property->isPublic())) { if (!($isPublic = $property->isPublic())) {
$property->setAccessible(true); $property->setAccessible(true);
} }
foreach (static::$columns as $key => $column) { if (isset(static::$ownsOne[$propertyName])) {
if (isset(static::$ownsOne[$propertyName]) && $column['internal'] === $propertyName) {
$id = self::createOwnsOne($propertyName, $property->getValue($obj)); $id = self::createOwnsOne($propertyName, $property->getValue($obj));
$value = self::parseValue($column['type'], $id); $value = self::parseValue($column['type'], $id);
$query->insert($column['name'])->value($value, $column['type']); $query->insert($column['name'])->value($value, $column['type']);
break; } elseif (isset(static::$belongsTo[$propertyName])) {
} elseif (isset(static::$belongsTo[$propertyName]) && $column['internal'] === $propertyName) {
$id = self::createBelongsTo($propertyName, $property->getValue($obj)); $id = self::createBelongsTo($propertyName, $property->getValue($obj));
$value = self::parseValue($column['type'], $id); $value = self::parseValue($column['type'], $id);
$query->insert($column['name'])->value($value, $column['type']); $query->insert($column['name'])->value($value, $column['type']);
break; } elseif ($column['name'] !== static::$primaryField) {
} elseif ($column['internal'] === $propertyName && $column['type'] !== static::$primaryField) {
$tValue = $property->getValue($obj); $tValue = $property->getValue($obj);
if (stripos($column['internal'], '/') !== false) { if (stripos($column['internal'], '/') !== false) {
$path = explode($column['internal']); $path = explode($column['internal']);
@ -437,8 +434,6 @@ class DataMapperAbstract implements DataMapperInterface
$value = self::parseValue($column['type'], $tValue); $value = self::parseValue($column['type'], $tValue);
$query->insert($column['name'])->value($value, $column['type']); $query->insert($column['name'])->value($value, $column['type']);
break;
}
} }
if (!($isPublic)) { if (!($isPublic)) {
@ -446,8 +441,9 @@ class DataMapperAbstract implements DataMapperInterface
} }
} }
if (static::$table === 'exchange') { // if a table only has a single column = primary key column. This must be done otherwise the query is empty
var_dump($query->toSql()); if ($query->getType() === QueryType::EMPTY) {
$query->insert(static::$primaryField)->value(0, static::$columns[static::$primaryField]['type']);
} }
self::$db->con->prepare($query->toSql())->execute(); self::$db->con->prepare($query->toSql())->execute();
@ -470,7 +466,9 @@ class DataMapperAbstract implements DataMapperInterface
$query->prefix(self::$db->getPrefix())->into(static::$table); $query->prefix(self::$db->getPrefix())->into(static::$table);
foreach (static::$columns as $key => $column) { foreach (static::$columns as $key => $column) {
if (isset(static::$hasMany[$key]) || isset(static::$hasOne[$key])) { if (isset(static::$hasMany[$key])
|| isset(static::$hasOne[$key])
) {
continue; continue;
} }
@ -494,7 +492,7 @@ class DataMapperAbstract implements DataMapperInterface
$query->insert($column['name'])->value($value, $column['type']); $query->insert($column['name'])->value($value, $column['type']);
break; break;
} elseif ($column['internal'] === $path && $column['type'] !== static::$primaryField) { } elseif ($column['internal'] === $path) {
$value = self::parseValue($column['type'], $property); $value = self::parseValue($column['type'], $property);
$query->insert($column['name'])->value($value, $column['type']); $query->insert($column['name'])->value($value, $column['type']);
@ -1116,37 +1114,34 @@ class DataMapperAbstract implements DataMapperInterface
->update(static::$table) ->update(static::$table)
->where(static::$table . '.' . static::$primaryField, '=', $objId); ->where(static::$table . '.' . static::$primaryField, '=', $objId);
$properties = $refClass->getProperties(); foreach (static::$columns as $key => $column) {
$propertyName = $column['internal'];
foreach ($properties as $property) { if (isset(static::$hasMany[$propertyName])
$propertyName = $property->getName(); || isset(static::$hasOne[$propertyName])
|| $column['internal'] === static::$primaryField
if (isset(static::$hasMany[$propertyName]) || isset(static::$hasOne[$propertyName])) { ) {
continue; continue;
} }
$property = $refClass->getProperty($propertyName);
if (!($isPublic = $property->isPublic())) { if (!($isPublic = $property->isPublic())) {
$property->setAccessible(true); $property->setAccessible(true);
} }
// todo: the order of updating could be a problem. maybe looping through ownsOne and belongsTo first is better. if (isset(static::$ownsOne[$propertyName])) {
foreach (static::$columns as $key => $column) {
if (isset(static::$ownsOne[$propertyName]) && $column['internal'] === $propertyName) {
$id = self::updateOwnsOne($propertyName, $property->getValue($obj)); $id = self::updateOwnsOne($propertyName, $property->getValue($obj));
$value = self::parseValue($column['type'], $id); $value = self::parseValue($column['type'], $id);
// todo: should not be done if the id didn't change. but for now don't know if id changed // todo: should not be done if the id didn't change. but for now don't know if id changed
$query->set([static::$table . '.' . $column['name'] => $value], $column['type']); $query->set([static::$table . '.' . $column['name'] => $value], $column['type']);
break; } elseif (isset(static::$belongsTo[$propertyName])) {
} elseif (isset(static::$belongsTo[$propertyName]) && $column['internal'] === $propertyName) {
$id = self::updateBelongsTo($propertyName, $property->getValue($obj)); $id = self::updateBelongsTo($propertyName, $property->getValue($obj));
$value = self::parseValue($column['type'], $id); $value = self::parseValue($column['type'], $id);
// todo: should not be done if the id didn't change. but for now don't know if id changed // todo: should not be done if the id didn't change. but for now don't know if id changed
$query->set([static::$table . '.' . $column['name'] => $value], $column['type']); $query->set([static::$table . '.' . $column['name'] => $value], $column['type']);
break; } elseif ($column['name'] !== static::$primaryField) {
} elseif ($column['internal'] === $propertyName && $column['type'] !== static::$primaryField) {
$tValue = $property->getValue($obj); $tValue = $property->getValue($obj);
if (stripos($column['internal'], '/') !== false) { if (stripos($column['internal'], '/') !== false) {
$path = explode($column['internal']); $path = explode($column['internal']);
@ -1156,8 +1151,6 @@ class DataMapperAbstract implements DataMapperInterface
$value = self::parseValue($column['type'], $tValue); $value = self::parseValue($column['type'], $tValue);
$query->set([static::$table . '.' . $column['name'] => $value], $column['type']); $query->set([static::$table . '.' . $column['name'] => $value], $column['type']);
break;
}
} }
if (!($isPublic)) { if (!($isPublic)) {

View File

@ -32,4 +32,5 @@ abstract class QueryType extends Enum
public const DELETE = 3; public const DELETE = 3;
public const RANDOM = 4; public const RANDOM = 4;
public const RAW = 5; public const RAW = 5;
public const EMPTY = 6;
} }

View File

@ -19,7 +19,7 @@ class QueryTypeTest extends \PHPUnit\Framework\TestCase
{ {
public function testEnums() public function testEnums()
{ {
self::assertEquals(6, count(QueryType::getConstants())); self::assertEquals(7, count(QueryType::getConstants()));
self::assertEquals(QueryType::getConstants(), array_unique(QueryType::getConstants())); self::assertEquals(QueryType::getConstants(), array_unique(QueryType::getConstants()));
self::assertEquals(0, QueryType::SELECT); self::assertEquals(0, QueryType::SELECT);
@ -28,5 +28,6 @@ class QueryTypeTest extends \PHPUnit\Framework\TestCase
self::assertEquals(3, QueryType::DELETE); self::assertEquals(3, QueryType::DELETE);
self::assertEquals(4, QueryType::RANDOM); self::assertEquals(4, QueryType::RANDOM);
self::assertEquals(5, QueryType::RAW); self::assertEquals(5, QueryType::RAW);
self::assertEquals(6, QueryType::EMPTY);
} }
} }

View File

@ -35,7 +35,7 @@ class BaseModelMapper extends DataMapperAbstract
'test_base_null' => ['name' => 'test_base_null', 'type' => 'int', 'internal' => 'null'], 'test_base_null' => ['name' => 'test_base_null', 'type' => 'int', 'internal' => 'null'],
'test_base_float' => ['name' => 'test_base_float', 'type' => 'float', 'internal' => 'float'], 'test_base_float' => ['name' => 'test_base_float', 'type' => 'float', 'internal' => 'float'],
'test_base_json' => ['name' => 'test_base_json', 'type' => 'Json', 'internal' => 'json'], 'test_base_json' => ['name' => 'test_base_json', 'type' => 'Json', 'internal' => 'json'],
'test_base_jsonSerialize' => ['name' => 'test_base_jsonSerialize', 'type' => 'jsonSerializable', 'internal' => 'jsonSerialize'], 'test_base_json_serializable' => ['name' => 'test_base_json_serializable', 'type' => 'Json', 'internal' => 'jsonSerializable'],
'test_base_datetime' => ['name' => 'test_base_datetime', 'type' => 'DateTime', 'internal' => 'datetime'], 'test_base_datetime' => ['name' => 'test_base_datetime', 'type' => 'DateTime', 'internal' => 'datetime'],
'test_base_owns_one_self' => ['name' => 'test_base_owns_one_self', 'type' => 'int', 'internal' => 'ownsOneSelf'], 'test_base_owns_one_self' => ['name' => 'test_base_owns_one_self', 'type' => 'int', 'internal' => 'ownsOneSelf'],
'test_base_belongs_to_one' => ['name' => 'test_base_belongs_to_one', 'type' => 'int', 'internal' => 'belongsToOne'], 'test_base_belongs_to_one' => ['name' => 'test_base_belongs_to_one', 'type' => 'int', 'internal' => 'belongsToOne'],