This commit is contained in:
Xes
2025-08-14 22:41:49 +02:00
parent 2de81ccc46
commit 8ce45119b6
39774 changed files with 4309466 additions and 0 deletions

View File

@@ -0,0 +1,87 @@
<?php
namespace Gedmo\Timestampable\Mapping\Driver;
use Gedmo\Mapping\Driver\AbstractAnnotationDriver;
use Gedmo\Exception\InvalidMappingException;
/**
* This is an annotation mapping driver for Timestampable
* behavioral extension. Used for extraction of extended
* metadata from Annotations specifically for Timestampable
* extension.
*
* @author Gediminas Morkevicius <gediminas.morkevicius@gmail.com>
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
class Annotation extends AbstractAnnotationDriver
{
/**
* Annotation field is timestampable
*/
const TIMESTAMPABLE = 'Gedmo\\Mapping\\Annotation\\Timestampable';
/**
* List of types which are valid for timestamp
*
* @var array
*/
protected $validTypes = array(
'date',
'date_immutable',
'time',
'time_immutable',
'datetime',
'datetime_immutable',
'datetimetz',
'datetimetz_immutable',
'timestamp',
'zenddate',
'vardatetime',
'integer',
);
/**
* {@inheritDoc}
*/
public function readExtendedMetadata($meta, array &$config)
{
$class = $this->getMetaReflectionClass($meta);
// property annotations
foreach ($class->getProperties() as $property) {
if ($meta->isMappedSuperclass && !$property->isPrivate() ||
$meta->isInheritedField($property->name) ||
isset($meta->associationMappings[$property->name]['inherited'])
) {
continue;
}
if ($timestampable = $this->reader->getPropertyAnnotation($property, self::TIMESTAMPABLE)) {
$field = $property->getName();
if (!$meta->hasField($field)) {
throw new InvalidMappingException("Unable to find timestampable [{$field}] as mapped property in entity - {$meta->name}");
}
if (!$this->isValidField($meta, $field)) {
throw new InvalidMappingException("Field - [{$field}] type is not valid and must be 'date', 'datetime' or 'time' in class - {$meta->name}");
}
if (!in_array($timestampable->on, array('update', 'create', 'change'))) {
throw new InvalidMappingException("Field - [{$field}] trigger 'on' is not one of [update, create, change] in class - {$meta->name}");
}
if ($timestampable->on == 'change') {
if (!isset($timestampable->field)) {
throw new InvalidMappingException("Missing parameters on property - {$field}, field must be set on [change] trigger in class - {$meta->name}");
}
if (is_array($timestampable->field) && isset($timestampable->value)) {
throw new InvalidMappingException("Timestampable extension does not support multiple value changeset detection yet.");
}
$field = array(
'field' => $field,
'trackedField' => $timestampable->field,
'value' => $timestampable->value,
);
}
// properties are unique and mapper checks that, no risk here
$config[$timestampable->on][] = $field;
}
}
}
}

View File

@@ -0,0 +1,106 @@
<?php
namespace Gedmo\Timestampable\Mapping\Driver;
use Gedmo\Mapping\Driver\Xml as BaseXml;
use Gedmo\Exception\InvalidMappingException;
/**
* This is a xml mapping driver for Timestampable
* behavioral extension. Used for extraction of extended
* metadata from xml specifically for Timestampable
* extension.
*
* @author Gediminas Morkevicius <gediminas.morkevicius@gmail.com>
* @author Miha Vrhovnik <miha.vrhovnik@gmail.com>
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
class Xml extends BaseXml
{
/**
* List of types which are valid for timestamp
*
* @var array
*/
private $validTypes = array(
'date',
'date_immutable',
'time',
'time_immutable',
'datetime',
'datetime_immutable',
'datetimetz',
'datetimetz_immutable',
'timestamp',
'zenddate',
'vardatetime',
'integer',
);
/**
* {@inheritDoc}
*/
public function readExtendedMetadata($meta, array &$config)
{
/**
* @var \SimpleXmlElement $mapping
*/
$mapping = $this->_getMapping($meta->name);
if (isset($mapping->field)) {
/**
* @var \SimpleXmlElement $fieldMapping
*/
foreach ($mapping->field as $fieldMapping) {
$fieldMappingDoctrine = $fieldMapping;
$fieldMapping = $fieldMapping->children(self::GEDMO_NAMESPACE_URI);
if (isset($fieldMapping->timestampable)) {
/**
* @var \SimpleXmlElement $data
*/
$data = $fieldMapping->timestampable;
$field = $this->_getAttribute($fieldMappingDoctrine, 'name');
if (!$this->isValidField($meta, $field)) {
throw new InvalidMappingException("Field - [{$field}] type is not valid and must be 'date', 'datetime' or 'time' in class - {$meta->name}");
}
if (!$this->_isAttributeSet($data, 'on') || !in_array($this->_getAttribute($data, 'on'), array('update', 'create', 'change'))) {
throw new InvalidMappingException("Field - [{$field}] trigger 'on' is not one of [update, create, change] in class - {$meta->name}");
}
if ($this->_getAttribute($data, 'on') == 'change') {
if (!$this->_isAttributeSet($data, 'field')) {
throw new InvalidMappingException("Missing parameters on property - {$field}, field must be set on [change] trigger in class - {$meta->name}");
}
$trackedFieldAttribute = $this->_getAttribute($data, 'field');
$valueAttribute = $this->_isAttributeSet($data, 'value') ? $this->_getAttribute($data, 'value' ) : null;
if (is_array($trackedFieldAttribute) && null !== $valueAttribute) {
throw new InvalidMappingException("Timestampable extension does not support multiple value changeset detection yet.");
}
$field = array(
'field' => $field,
'trackedField' => $trackedFieldAttribute,
'value' => $valueAttribute,
);
}
$config[$this->_getAttribute($data, 'on')][] = $field;
}
}
}
}
/**
* Checks if $field type is valid
*
* @param object $meta
* @param string $field
*
* @return boolean
*/
protected function isValidField($meta, $field)
{
$mapping = $meta->getFieldMapping($field);
return $mapping && in_array($mapping['type'], $this->validTypes);
}
}

View File

@@ -0,0 +1,107 @@
<?php
namespace Gedmo\Timestampable\Mapping\Driver;
use Gedmo\Mapping\Driver\File;
use Gedmo\Mapping\Driver;
use Gedmo\Exception\InvalidMappingException;
/**
* This is a yaml mapping driver for Timestampable
* behavioral extension. Used for extraction of extended
* metadata from yaml specifically for Timestampable
* extension.
*
* @author Gediminas Morkevicius <gediminas.morkevicius@gmail.com>
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
class Yaml extends File implements Driver
{
/**
* File extension
* @var string
*/
protected $_extension = '.dcm.yml';
/**
* List of types which are valid for timestamp
*
* @var array
*/
private $validTypes = array(
'date',
'date_immutable',
'time',
'time_immutable',
'datetime',
'datetime_immutable',
'datetimetz',
'datetimetz_immutable',
'timestamp',
'zenddate',
'vardatetime',
'integer',
);
/**
* {@inheritDoc}
*/
public function readExtendedMetadata($meta, array &$config)
{
$mapping = $this->_getMapping($meta->name);
if (isset($mapping['fields'])) {
foreach ($mapping['fields'] as $field => $fieldMapping) {
if (isset($fieldMapping['gedmo']['timestampable'])) {
$mappingProperty = $fieldMapping['gedmo']['timestampable'];
if (!$this->isValidField($meta, $field)) {
throw new InvalidMappingException("Field - [{$field}] type is not valid and must be 'date', 'datetime' or 'time' in class - {$meta->name}");
}
if (!isset($mappingProperty['on']) || !in_array($mappingProperty['on'], array('update', 'create', 'change'))) {
throw new InvalidMappingException("Field - [{$field}] trigger 'on' is not one of [update, create, change] in class - {$meta->name}");
}
if ($mappingProperty['on'] == 'change') {
if (!isset($mappingProperty['field'])) {
throw new InvalidMappingException("Missing parameters on property - {$field}, field must be set on [change] trigger in class - {$meta->name}");
}
$trackedFieldAttribute = $mappingProperty['field'];
$valueAttribute = isset($mappingProperty['value']) ? $mappingProperty['value'] : null;
if (is_array($trackedFieldAttribute) && null !== $valueAttribute) {
throw new InvalidMappingException("Timestampable extension does not support multiple value changeset detection yet.");
}
$field = array(
'field' => $field,
'trackedField' => $trackedFieldAttribute,
'value' => $valueAttribute,
);
}
$config[$mappingProperty['on']][] = $field;
}
}
}
}
/**
* {@inheritDoc}
*/
protected function _loadMappingFile($file)
{
return \Symfony\Component\Yaml\Yaml::parse(file_get_contents($file));
}
/**
* Checks if $field type is valid
*
* @param object $meta
* @param string $field
*
* @return boolean
*/
protected function isValidField($meta, $field)
{
$mapping = $meta->getFieldMapping($field);
return $mapping && in_array($mapping['type'], $this->validTypes);
}
}

View File

@@ -0,0 +1,36 @@
<?php
namespace Gedmo\Timestampable\Mapping\Event\Adapter;
use Gedmo\Mapping\Event\Adapter\ODM as BaseAdapterODM;
use Gedmo\Timestampable\Mapping\Event\TimestampableAdapter;
/**
* Doctrine event adapter for ODM adapted
* for Timestampable behavior
*
* @author Gediminas Morkevicius <gediminas.morkevicius@gmail.com>
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
final class ODM extends BaseAdapterODM implements TimestampableAdapter
{
/**
* {@inheritDoc}
*/
public function getDateValue($meta, $field)
{
$mapping = $meta->getFieldMapping($field);
if (isset($mapping['type']) && $mapping['type'] === 'timestamp') {
return time();
}
if (isset($mapping['type']) && $mapping['type'] == 'zenddate') {
return new \Zend_Date();
}
if (isset($mapping['type']) && in_array($mapping['type'], array('date_immutable', 'time_immutable', 'datetime_immutable', 'datetimetz_immutable'), true)) {
return new \DateTimeImmutable();
}
return \DateTime::createFromFormat('U.u', number_format(microtime(true), 6, '.', ''))
->setTimeZone(new \DateTimeZone(date_default_timezone_get()));
}
}

View File

@@ -0,0 +1,36 @@
<?php
namespace Gedmo\Timestampable\Mapping\Event\Adapter;
use Gedmo\Mapping\Event\Adapter\ORM as BaseAdapterORM;
use Gedmo\Timestampable\Mapping\Event\TimestampableAdapter;
/**
* Doctrine event adapter for ORM adapted
* for Timestampable behavior
*
* @author Gediminas Morkevicius <gediminas.morkevicius@gmail.com>
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
final class ORM extends BaseAdapterORM implements TimestampableAdapter
{
/**
* {@inheritDoc}
*/
public function getDateValue($meta, $field)
{
$mapping = $meta->getFieldMapping($field);
if (isset($mapping['type']) && $mapping['type'] === 'integer') {
return time();
}
if (isset($mapping['type']) && $mapping['type'] == 'zenddate') {
return new \Zend_Date();
}
if (isset($mapping['type']) && in_array($mapping['type'], array('date_immutable', 'time_immutable', 'datetime_immutable', 'datetimetz_immutable'), true)) {
return new \DateTimeImmutable();
}
return \DateTime::createFromFormat('U.u', number_format(microtime(true), 6, '.', ''))
->setTimeZone(new \DateTimeZone(date_default_timezone_get()));
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace Gedmo\Timestampable\Mapping\Event;
use Gedmo\Mapping\Event\AdapterInterface;
/**
* Doctrine event adapter interface
* for Timestampable behavior
*
* @author Gediminas Morkevicius <gediminas.morkevicius@gmail.com>
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
interface TimestampableAdapter extends AdapterInterface
{
/**
* Get the date value
*
* @param object $meta
* @param string $field
*
* @return mixed
*/
public function getDateValue($meta, $field);
}

View File

@@ -0,0 +1,50 @@
<?php
namespace Gedmo\Timestampable;
/**
* This interface is not necessary but can be implemented for
* Entities which in some cases needs to be identified as
* Timestampable
*
* @author Gediminas Morkevicius <gediminas.morkevicius@gmail.com>
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
interface Timestampable
{
// timestampable expects annotations on properties
/**
* @gedmo:Timestampable(on="create")
* dates which should be updated on insert only
*/
/**
* @gedmo:Timestampable(on="update")
* dates which should be updated on update and insert
*/
/**
* @gedmo:Timestampable(on="change", field="field", value="value")
* dates which should be updated on changed "property"
* value and become equal to given "value"
*/
/**
* @gedmo:Timestampable(on="change", field="field")
* dates which should be updated on changed "property"
*/
/**
* @gedmo:Timestampable(on="change", fields={"field1", "field2"})
* dates which should be updated if at least one of the given fields changed
*/
/**
* example
*
* @gedmo:Timestampable(on="create")
* @Column(type="date")
* $created
*/
}

View File

@@ -0,0 +1,36 @@
<?php
namespace Gedmo\Timestampable;
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
use Gedmo\AbstractTrackingListener;
use Gedmo\Timestampable\Mapping\Event\TimestampableAdapter;
/**
* The Timestampable listener handles the update of
* dates on creation and update.
*
* @author Gediminas Morkevicius <gediminas.morkevicius@gmail.com>
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
class TimestampableListener extends AbstractTrackingListener
{
/**
* @param ClassMetadata $meta
* @param string $field
* @param TimestampableAdapter $eventAdapter
* @return mixed
*/
protected function getFieldValue($meta, $field, $eventAdapter)
{
return $eventAdapter->getDateValue($meta, $field);
}
/**
* {@inheritDoc}
*/
protected function getNamespace()
{
return __NAMESPACE__;
}
}

View File

@@ -0,0 +1,68 @@
<?php
namespace Gedmo\Timestampable\Traits;
/**
* Timestampable Trait, usable with PHP >= 5.4
*
* @author Gediminas Morkevicius <gediminas.morkevicius@gmail.com>
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
trait Timestampable
{
/**
* @var \DateTime
*/
protected $createdAt;
/**
* @var \DateTime
*/
protected $updatedAt;
/**
* Sets createdAt.
*
* @param \DateTime $createdAt
* @return $this
*/
public function setCreatedAt(\DateTime $createdAt)
{
$this->createdAt = $createdAt;
return $this;
}
/**
* Returns createdAt.
*
* @return \DateTime
*/
public function getCreatedAt()
{
return $this->createdAt;
}
/**
* Sets updatedAt.
*
* @param \DateTime $updatedAt
* @return $this
*/
public function setUpdatedAt(\DateTime $updatedAt)
{
$this->updatedAt = $updatedAt;
return $this;
}
/**
* Returns updatedAt.
*
* @return \DateTime
*/
public function getUpdatedAt()
{
return $this->updatedAt;
}
}

View File

@@ -0,0 +1,75 @@
<?php
namespace Gedmo\Timestampable\Traits;
use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
use Gedmo\Mapping\Annotation as Gedmo;
/**
* Timestampable Trait, usable with PHP >= 5.4
*
* @author Gediminas Morkevicius <gediminas.morkevicius@gmail.com>
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
trait TimestampableDocument
{
/**
* @var \DateTime
* @Gedmo\Timestampable(on="create")
* @ODM\Field(type="date")
*/
protected $createdAt;
/**
* @var \DateTime
* @Gedmo\Timestampable(on="update")
* @ODM\Field(type="date")
*/
protected $updatedAt;
/**
* Sets createdAt.
*
* @param \DateTime $createdAt
* @return $this
*/
public function setCreatedAt(\DateTime $createdAt)
{
$this->createdAt = $createdAt;
return $this;
}
/**
* Returns createdAt.
*
* @return \DateTime
*/
public function getCreatedAt()
{
return $this->createdAt;
}
/**
* Sets updatedAt.
*
* @param \DateTime $updatedAt
* @return $this
*/
public function setUpdatedAt(\DateTime $updatedAt)
{
$this->updatedAt = $updatedAt;
return $this;
}
/**
* Returns updatedAt.
*
* @return \Datetime
*/
public function getUpdatedAt()
{
return $this->updatedAt;
}
}

View File

@@ -0,0 +1,75 @@
<?php
namespace Gedmo\Timestampable\Traits;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
/**
* Timestampable Trait, usable with PHP >= 5.4
*
* @author Gediminas Morkevicius <gediminas.morkevicius@gmail.com>
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
trait TimestampableEntity
{
/**
* @var \DateTime
* @Gedmo\Timestampable(on="create")
* @ORM\Column(type="datetime")
*/
protected $createdAt;
/**
* @var \DateTime
* @Gedmo\Timestampable(on="update")
* @ORM\Column(type="datetime")
*/
protected $updatedAt;
/**
* Sets createdAt.
*
* @param \DateTime $createdAt
* @return $this
*/
public function setCreatedAt(\DateTime $createdAt)
{
$this->createdAt = $createdAt;
return $this;
}
/**
* Returns createdAt.
*
* @return \DateTime
*/
public function getCreatedAt()
{
return $this->createdAt;
}
/**
* Sets updatedAt.
*
* @param \DateTime $updatedAt
* @return $this
*/
public function setUpdatedAt(\DateTime $updatedAt)
{
$this->updatedAt = $updatedAt;
return $this;
}
/**
* Returns updatedAt.
*
* @return \DateTime
*/
public function getUpdatedAt()
{
return $this->updatedAt;
}
}