As of Doctrine 2.5 we have the Embeddable
feature, that allow us to separate concerns by using a separated class (with its own behaviors) inside an entity. Something like this:
<?php
/** @Embeddable */
class DateTimeInterval
{
/** @Column(type="datetime") */
private $begin;
/** @Column(type="datetime") */
private $end;
/**
* @param DateTime $begin
* @param DateTime $end
*/
public function __construct(DateTime $begin, DateTime $end)
{
$this->begin = $begin;
$this->end = $end;
}
/**
* @return DateTime
*/
public function getStart()
{
return $this->start;
}
/**
* @return DateTime
*/
public function getEnd()
{
return $this->end;
}
/**
* @param DateTime $date
* @return boolean
*/
public function includes(DateTime $date)
{
return $date >= $this->start && $date <= $this->end;
}
}
/** @Entity */
class Event
{
// (...) other attributes
/**
* The period that the event occurs
*
* @Embedded(class = "DateTimeInterval")
*/
private $period;
/**
* @param DateTimeInterval $period
*/
public function __construct(DateTimeInterval $period /*[, (...)]*/)
{
$this->period = $period;
// (...)
}
}
Awesome, right?
Sometimes I want to have an optional attribute, that reuses the same Embeddable
. Something like:
<?php
/** @Entity */
class Event
{
// (...) other attributes
/**
* The period that the event occurs
*
* @Embedded(class = "DateTimeInterval")
*/
private $period;
/**
* The period that the talk submissions occurs (when the event have submissions)
*
* @Embedded(class = "DateTimeInterval")
*/
private $submissionsPeriod;
/**
* @param DateTimeInterval $period
*/
public function __construct(
DateTimeInterval $period,
DateTimeInterval $submissionsPeriod = null
/*[, (...)]*/
) {
$this->period = $period;
$this->submissionsPeriod = $submissionsPeriod;
// (...)
}
}
I know that we can have an optional association with a separated entity that have the attribute, but I believe that can be considered as a (small) over engineering.
It is "natural" to read and to know what's going on with the Event
object, but won't work because both $start
and $end
attributes are mandatory on the DateTimeInterval
. Nowadays, to have that desired behavior, we would have to create an extension of DateTimeInterval
with the nullable
option on the attributes annotations, but that will lead us to an empty instance of that extension class when both values were NULL
.
I believe that Doctrine could allow the nullable
option on Embedded
annotation, so when its true all attributes would be overridden (all nullable=true). When all values were NULL
Doctrine wouldn't create an empty instance, but just NULL
for the whole object.
After a small search, I saw that JPA allow the use of AttributeOverrides
annotation on Embedded
s so we can make the attributes nullable. That's an interesting approach too, and we would be able to change another things (not just nullable option). Like:
<?php
/** @Entity */
class Event
{
// (...) other attributes
/**
* The period that the event occurs
*
* @Embedded(class = "DateTimeInterval")
* @AttributeOverrides({
* @AttributeOverride(name="begin", column= @Column(type = "date")),
* @AttributeOverride(name="end", column= @Column(type = "date")),
* })
*/
private $period;
/**
* The period that the talk submissions occurs (when the event has submissions)
*
* @Embedded(class = "DateTimeInterval")
*/
private $submissionsPeriod;
/**
* @param DateTimeInterval $period
*/
public function __construct(
DateTimeInterval $period,
DateTimeInterval $submissionsPeriod = null
/*[, (...)]*/
) {
$this->period = $period;
$this->submissionsPeriod = $submissionsPeriod;
// (...)
}
}
With this feature we will have more flexibility when using Embeddables
and invert the control of the metadata.
@Icobucci Has there been any update on this topic of nullable embeddables? Anything we can do to help push it forward?