Skip to content

Instantly share code, notes, and snippets.

@mgeoffray
Last active July 9, 2021 08:39
Show Gist options
  • Save mgeoffray/267e5de5094eeda7680c0f71692f631a to your computer and use it in GitHub Desktop.
Save mgeoffray/267e5de5094eeda7680c0f71692f631a to your computer and use it in GitHub Desktop.
Symfony Doctrine Entity Factory
<?php
declare(strict_types=1);
namespace App\Framework\ObjectManager\Factory\Doctrine;
use App\Exception\ClassNotFoundException;
use Throwable;
/**
* Class EntityFactory
*
* @package App\Framework\ObjectManager\Factory\Doctrine
* @author Mattheo Geoffray <mattheo.geoffray@gmail.com>
* @copyright 2011-present Mattheo Geoffray
* @license https://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
* @link https://mgeoffray.fr/
*/
class EntityFactory
{
/**
* Create model instance with data
* $data must be like
* [
* 'setter_1' => 'value_1',
* 'setter_2' => 'value_2',
* 'setter_3' => 'value_3',
* 'setter_4' => 'value_4',
* ]
*
* @param string|object $modelName
* @param mixed[] $data
*
* @return object
* @throws ClassNotFoundException
*/
public function create($modelName, array $data = []): object
{
if (is_object($modelName)) {
/** @var object $model */
$model = $modelName;
} else {
if (!class_exists($modelName)) {
throw new ClassNotFoundException(
sprintf('Model class "%s" not found for factory.', $modelName)
);
}
$model = new $modelName();
}
/**
* @var string $key
* @var mixed $value
*/
foreach ($data as $key => $value) {
$this->computeChanged($model, $key, $value);
$this->setDataUsingMethod($model, $key, $value);
}
return $model;
}
/**
* Set data on object
*
* @param object $model
* @param string $key
* @param mixed $value
*
* @return void
*/
public function setDataUsingMethod(object &$model, string $key, $value = null): void
{
/** @var string $method */
$method = 'set' . str_replace(' ', '', ucwords(str_replace('_', ' ', $key)));
if (!method_exists($model, $method)) {
return;
}
$model->{$method}($value);
}
/**
* Description getDataUsingMethod function
*
* @param object $model
* @param string $key
*
* @return mixed|null
*/
public function getDataUsingMethod(object $model, string $key)
{
/** @var string $methodGet */
$methodGet = 'get' . str_replace(' ', '', ucwords(str_replace('_', ' ', $key)));
/** @var string $methodIs */
$methodIs = lcfirst(str_replace(' ', '', ucwords(str_replace('_', ' ', $key))));
/** @var string $methodIs */
$methodIs2 = 'is' . str_replace(' ', '', ucwords(str_replace('_', ' ', $key)));
/** @var mixed $value */
$value = null;
/** @var string|null $method */
foreach ([$methodGet, $methodIs, $methodIs2] as $method) {
if (!method_exists($model, $method)) {
continue;
}
try {
$value = $model->{$method}();
} catch (Throwable $t) {
}
}
return $value;
}
/**
* Description hasDataChangedFor function
*
* @param object $model
* @param string $key
* @param mixed $origin
*
* @return bool
*/
public function hasDataChangedFor(object $model, string $key, $origin): bool
{
$oldValue = $this->getDataUsingMethod($model, $key);
return $this->convertValue($oldValue) != $this->convertValue($origin);
}
/**
* Description convertValue function
*
* @param mixed $origin
*
* @return mixed
*/
public function convertValue($origin)
{
if ($origin instanceof \DateTime) {
/** @var \DateTime $compareValueOld */
$value = clone $origin;
return $value->setTimezone(new \DateTimeZone('Europe/Paris'));
}
if (is_object($origin) && method_exists($origin, 'getId')) {
return $origin->getId();
}
if (empty($origin)) {
return null;
}
return $origin;
}
/**
* Description computeChanged function
*
* @param object $model
* @param string $key
* @param mixed $origin
*
* @return void
*/
public function computeChanged(object $model, string $key, $origin): void
{
if (!method_exists($model, 'addChanges')) {
return;
}
if (!$this->hasDataChangedFor($model, $key, $origin)) {
return;
}
$model->addChanges(
[
$key => [
'old' => $this->convertValue($this->getDataUsingMethod($model, $key)),
'new' => $this->convertValue($origin),
],
]
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment