In my current project I'm refactoring the code to get a DBAL. I have a class Entity
that is the base class for all classes that model a database table. So there are several classes that inherit from Entity
like Document
, Article
and so on.
abstract class Entity {
/** @var DatabaseRequest $dbReuest */
protected $dbRequest;
/** @var Login $login */
protected $login;
/* some methods like insert(), update(), JsonSerialize(), etc.
}
Since all these classes have the same constructor __construct( DatabaseRequest $dbRequest, Login $login )
and I don't want to throw around those two paramenters, I also made this:
class EntityFactory {
public function __construct( DatabaseRequest $dbRequest, Login $login )
{
$this->dbRequest = $dbRequest;
$this->login = $login;
}
public function makeEntity( string $class )
{
if ( $this->extendsEntity( $class ) ) {
$reflection = new \ReflectionClass( $class );
$construct = $reflection->getConstructor();
$params = $construct->getParameters();
return new $class( clone $this->dbRequest, clone $this->login );
}
throw new APIException( "Class $class does not extend " . Entity::class, JsonResponse::DEBUG );
}
}
You call the method like this: $factory->makeEntity( Document::class )
and this will give you an object of that class.
This way a change in in the Entity
constructor reduced the refactoring effort to a minimum. However, in class that extend Entity
I also defined some methods for the relationships between their tables. E.g.:
class DocumentAddressee extends Entity {
/* ... */
public static function createFromCustomer( Address $address )
{
$self = new DocumentAddressee( clone $address->dbRequest, clone $address->login );
/* transferring data from Address to $self */
return $self;
}
}
(According to verraes.net this is a legit use of static methods as named constructory ).
And methods like these happen quite some times (roughly 1-2 methods per foreign key in a table). Now I'd like to keep those methods, because I can easily access dependend data this way. But I'd also like to keep those constructors to the factory so I don't have to refactor all 100+ Entity-classes when the Entity construcor changes (this might happen if we'll decide to use a QueryBuilder in the future.
Is there already some kind of best practice to handle these methods? Should I propably handle those relationships within the factory or model those relationships in extra classes?
Best Answer
Ideally, you only use the factory to create these objects for consistency. So, in the factory you have something like:
You might want to add
initWithEntity()
toEntity
class, as basic implementation i.e.:And here's the
Initialisable
interface with updatedDocumentAdressee
.With
initWithEntity()
there's no need to open access toEntity
properties forEntityFactory
, so no need to use reflection there. To create aDocumentAdressee
object, you use:This should work for the problem in your question, where an Entity can have 1 to 1 relationship, e.g. the
DocumentAdressee
. For classes that have one to many relationship, you'd need to create something likeinitWithEntities()
and pass array ofEntity
s into that.As for best practice, there are ORMs that you can use or look at, e.g. Doctrine.
edit
I added
Initialisable
interface to allow check if the class being created needs to be initialised with an Entity.