herrera-io/doctrine-dateinterval
Adds DateInterval support to Doctrine DBAL and ORM. Provides a custom DBAL type (dateinterval) plus a DATE_INTERVAL DQL function so you can map and query PHP DateInterval values in entities and database fields.
Installation:
composer require herrera-io/doctrine-dateinterval=1.*
Register the DBAL Type (in a service provider or bootstrap file):
use Doctrine\DBAL\Types\Type;
use Herrera\Doctrine\DBAL\Types\DateIntervalType;
Type::addType(DateIntervalType::DATEINTERVAL, DateIntervalType::class);
Register the ORM Function (in Doctrine configuration):
$entityManager->getConfiguration()->addCustomDatetimeFunction(
'DATE_INTERVAL',
'Herrera\Doctrine\ORM\Query\AST\Functions\DateIntervalFunction'
);
Map the Doctrine Type (for database column types):
$entityManager->getConnection()
->getDatabasePlatform()
->registerDoctrineTypeMapping(
DateIntervalType::DATEINTERVAL,
DateIntervalType::DATEINTERVAL
);
Define a dateinterval column in an entity and query it:
/**
* @Entity()
* @Table(name="recurring_events")
*/
class RecurringEvent
{
/**
* @Column(type="dateinterval")
*/
private $recurrenceInterval;
// Getters/setters...
}
// Query example:
$events = $entityManager->createQuery(
'SELECT e FROM RecurringEvent e WHERE e.recurrenceInterval = DATE_INTERVAL("P1M")'
)->getResult();
type="dateinterval" in Doctrine annotations/attributes.Herrera\DateInterval\DateInterval (not PHP's native DateInterval) for type consistency.default: "P1D" in annotations or constructor logic.// Find events recurring less frequently than annually
$query = $entityManager->createQuery(
'SELECT e FROM RecurringEvent e WHERE e.recurrenceInterval < DATE_INTERVAL("P1Y")'
);
// Hypothetical: Add intervals (DB-dependent)
$query = $entityManager->createQuery(
'SELECT e FROM RecurringEvent e WHERE e.endDate > e.startDate + DATE_INTERVAL("P1M")'
);
INTERVAL type in PostgreSQL, INTERVAL in MySQL, or INTERVAL in SQLite)."P1Y") to DateInterval objects during migration.DateIntervalType from Symfony's form component to handle input/output conversion:
$builder->add('recurrenceInterval', DateIntervalType::class, [
'widget' => 'single_text',
'input' => 'string', // Accepts ISO 8601 format (e.g., "P1M")
]);
Database Compatibility:
INTERVAL type but may require INTERVAL syntax in raw SQL (not all operations are supported).INTERVAL operations.Query Limitations:
DATE_INTERVAL() is provided. Complex arithmetic (e.g., +, -) may require raw SQL or application-side logic.dateinterval in GROUP BY or aggregations (e.g., MAX, AVG)—results are unpredictable.Serialization:
if (!$interval instanceof Herrera\DateInterval\DateInterval) {
throw new \RuntimeException('Invalid DateInterval loaded from DB');
}
Archived Package:
gedmo/doctrine-extensions (if available) for long-term projects.DateInterval strings in the database (e.g., "P1X"). Use toSpec() to inspect values:
$interval->toSpec(); // Returns string representation (e.g., "P1Y2M3D")
Herrera\DateInterval\DateInterval is used consistently (not PHP's native DateInterval).Validation:
public function setRecurrenceInterval(DateInterval $interval) {
if (!preg_match('/^P(?!$)(\d+Y)?(\d+M)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?(\d+S)?)?$/', $interval->toSpec())) {
throw new \InvalidArgumentException('Invalid DateInterval format');
}
$this->recurrenceInterval = $interval;
}
Testing:
DateIntervalType in unit tests to avoid database dependencies:
$type = $this->getMockBuilder(DateIntervalType::class)
->disableOriginalConstructor()
->onlyMethods(['convertToDatabaseValue', 'convertToPHPValue'])
->getMock();
Performance:
dateinterval in ORDER BY or JOIN conditions—indexing is non-trivial.Alternatives:
years, months, days as separate columns) if dateinterval operations are complex.Symfony Configuration:
config/packages/doctrine.yaml for cleaner setup:
doctrine:
dbal:
types:
dateinterval: Herrera\Doctrine\DBAL\Types\DateIntervalType
orm:
dql:
datetime_functions:
DATE_INTERVAL: Herrera\Doctrine\ORM\Query\AST\Functions\DateIntervalFunction
How can I help you explore Laravel packages today?