Commit 2e9c7fef authored by alexpott's avatar alexpott

Issue #2002102 by Berdir, fago, dixon_: Move TypedData primitive types to interfaces.

parent c56cb204
...@@ -85,17 +85,10 @@ public function getConstraints() { ...@@ -85,17 +85,10 @@ public function getConstraints() {
* Overrides \Drupal\Component\Plugin\Context\Context::getConstraints(). * Overrides \Drupal\Component\Plugin\Context\Context::getConstraints().
*/ */
public function validate() { public function validate() {
$validator = Validation::createValidatorBuilder() // If the context is typed data, defer to its validation.
->setTranslator(new DrupalTranslator()) if (!empty($this->contextDefinition['type'])) {
->getValidator(); return $this->getTypedContext()->validate();
// @todo We won't need to special case "entity" here once #1868004 lands.
if (!empty($this->contextDefinition['type']) && $this->contextDefinition['type'] == 'entity') {
$value = $this->getTypedContext();
}
else {
$value = $this->getContextValue();
} }
return $validator->validateValue($value, $this->getConstraints()); return parent::validate();
} }
} }
...@@ -7,6 +7,8 @@ ...@@ -7,6 +7,8 @@
namespace Drupal\Core\TypedData\Plugin\DataType; namespace Drupal\Core\TypedData\Plugin\DataType;
use Drupal\Core\TypedData\PrimitiveBase;
use Drupal\Core\TypedData\Type\BinaryInterface;
use Drupal\Core\TypedData\Annotation\DataType; use Drupal\Core\TypedData\Annotation\DataType;
use Drupal\Core\Annotation\Translation; use Drupal\Core\Annotation\Translation;
use Drupal\Core\TypedData\TypedData; use Drupal\Core\TypedData\TypedData;
...@@ -20,11 +22,10 @@ ...@@ -20,11 +22,10 @@
* *
* @DataType( * @DataType(
* id = "binary", * id = "binary",
* label = @Translation("Binary"), * label = @Translation("Binary")
* primitive_type = 8
* ) * )
*/ */
class Binary extends TypedData { class Binary extends PrimitiveBase implements BinaryInterface {
/** /**
* The file resource URI. * The file resource URI.
......
...@@ -9,7 +9,8 @@ ...@@ -9,7 +9,8 @@
use Drupal\Core\TypedData\Annotation\DataType; use Drupal\Core\TypedData\Annotation\DataType;
use Drupal\Core\Annotation\Translation; use Drupal\Core\Annotation\Translation;
use Drupal\Core\TypedData\TypedData; use Drupal\Core\TypedData\PrimitiveBase;
use Drupal\Core\TypedData\Type\BooleanInterface;
/** /**
* The boolean data type. * The boolean data type.
...@@ -19,16 +20,9 @@ ...@@ -19,16 +20,9 @@
* *
* @DataType( * @DataType(
* id = "boolean", * id = "boolean",
* label = @Translation("Boolean"), * label = @Translation("Boolean")
* primitive_type = 1
* ) * )
*/ */
class Boolean extends TypedData { class Boolean extends PrimitiveBase implements BooleanInterface {
/**
* The data value.
*
* @var boolean
*/
protected $value;
} }
<?php
/**
* @file
* Contains \Drupal\Core\TypedData\Plugin\DataType\Date.
*/
namespace Drupal\Core\TypedData\Plugin\DataType;
use Drupal\Core\TypedData\Annotation\DataType;
use Drupal\Core\Annotation\Translation;
use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\Core\TypedData\TypedData;
/**
* The date data type.
*
* The plain value of a date is an instance of the DrupalDateTime class. For
* setting the value any value supported by the __construct() of the
* DrupalDateTime class will work, including a DateTime object, a timestamp, a
* string date, or an array of date parts.
*
* @DataType(
* id = "date",
* label = @Translation("Date"),
* primitive_type = 5
* )
*/
class Date extends TypedData {
/**
* The data value.
*
* @var DateTime
*/
protected $value;
/**
* Overrides TypedData::setValue().
*/
public function setValue($value, $notify = TRUE) {
// Notify the parent of any changes to be made.
if ($notify && isset($this->parent)) {
$this->parent->onChange($this->name);
}
// Don't try to create a date from an empty value.
// It would default to the current time.
if (!isset($value)) {
$this->value = $value;
}
else {
$this->value = $value instanceOf DrupalDateTime ? $value : new DrupalDateTime($value);
}
}
}
<?php
/**
* @file
* Contains \Drupal\Core\TypedData\Plugin\DataType\DateTimeIso8601.
*/
namespace Drupal\Core\TypedData\Plugin\DataType;
use Drupal\Core\TypedData\Annotation\DataType;
use Drupal\Core\Annotation\Translation;
use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\Core\TypedData\Type\DateTimeInterface;
/**
* A data type for ISO 8601 date strings.
*
* The plain value of this data type is a date string in ISO 8601 format.
*
* @DataType(
* id = "datetime_iso8601",
* label = @Translation("Date")
* )
*/
class DateTimeIso8601 extends String implements DateTimeInterface {
/**
* {@inheritdoc}
*/
public function getDateTime() {
if ($this->value) {
return new DrupalDateTime($this->value);
}
}
/**
* {@inheritdoc}
*/
public function setDateTime(DrupalDateTime $dateTime) {
$this->value = $dateTime->format('c');
}
}
<?php
/**
* @file
* Contains \Drupal\Core\TypedData\Plugin\DataType\Duration.
*/
namespace Drupal\Core\TypedData\Plugin\DataType;
use Drupal\Core\TypedData\Annotation\DataType;
use Drupal\Core\Annotation\Translation;
use Drupal\Core\TypedData\TypedData;
use DateInterval;
/**
* The duration data type.
*
* The plain value of a duration is an instance of the DateInterval class. For
* setting the value an instance of the DateInterval class, a ISO8601 string as
* supported by DateInterval::__construct, or an integer in seconds may be
* passed.
*
* @DataType(
* id = "duration",
* label = @Translation("Duration"),
* primitive_type = 6
* )
*/
class Duration extends TypedData {
/**
* The data value.
*
* @var \DateInterval
*/
protected $value;
/**
* Overrides TypedData::setValue().
*/
public function setValue($value, $notify = TRUE) {
// Notify the parent of any changes to be made.
if ($notify && isset($this->parent)) {
$this->parent->onChange($this->name);
}
// Catch any exceptions thrown due to invalid values being passed.
try {
if ($value instanceof DateInterval || !isset($value)) {
$this->value = $value;
}
// Treat integer values as time spans in seconds, even if supplied as PHP
// string.
elseif ((string) (int) $value === (string) $value) {
$this->value = new DateInterval('PT' . $value . 'S');
}
elseif (is_string($value)) {
// @todo: Add support for negative intervals on top of the DateInterval
// constructor.
$this->value = new DateInterval($value);
}
else {
// Unknown value given.
$this->value = $value;
}
}
catch (\Exception $e) {
// An invalid value has been given. Setting any invalid value will let
// validation fail.
$this->value = $e;
}
}
/**
* Overrides TypedData::getString().
*/
public function getString() {
// Generate an ISO 8601 formatted string as supported by
// DateInterval::__construct() and setValue().
return (string) $this->getValue()->format('%rP%yY%mM%dDT%hH%mM%sS');
}
}
<?php
/**
* @file
* Contains \Drupal\Core\TypedData\Plugin\DataType\DurationIso8601.
*/
namespace Drupal\Core\TypedData\Plugin\DataType;
use Drupal\Core\TypedData\Annotation\DataType;
use Drupal\Core\Annotation\Translation;
use Drupal\Core\TypedData\Type\DurationInterface;
/**
* The duration ISO8601 data type.
*
* The plain value of this data type is a ISO8601 duration string.
*
* @DataType(
* id = "duration_iso8601",
* label = @Translation("Duration")
* )
*/
class DurationIso8601 extends String implements DurationInterface {
/**
* {@inheritdoc}
*/
public function getDuration() {
if ($this->value) {
// @todo: Add support for negative intervals on top of the DateInterval
// constructor.
return new \DateInterval($this->value);
}
}
/**
* {@inheritdoc}
*/
public function setDuration(\DateInterval $duration) {
// Generate an ISO 8601 formatted string as supported by
// DateInterval::__construct() and setValue().
$this->value = $duration->format('%rP%yY%mM%dDT%hH%mM%sS');
}
}
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
use Drupal\Core\TypedData\Annotation\DataType; use Drupal\Core\TypedData\Annotation\DataType;
use Drupal\Core\Annotation\Translation; use Drupal\Core\Annotation\Translation;
use Drupal\Core\TypedData\Type\StringInterface;
/** /**
* The Email data type. * The Email data type.
...@@ -18,10 +19,9 @@ ...@@ -18,10 +19,9 @@
* @DataType( * @DataType(
* id = "email", * id = "email",
* label = @Translation("Email"), * label = @Translation("Email"),
* primitive_type = 2,
* constraints = {"Email" = TRUE} * constraints = {"Email" = TRUE}
* ) * )
*/ */
class Email extends String { class Email extends String implements StringInterface {
} }
...@@ -9,7 +9,8 @@ ...@@ -9,7 +9,8 @@
use Drupal\Core\TypedData\Annotation\DataType; use Drupal\Core\TypedData\Annotation\DataType;
use Drupal\Core\Annotation\Translation; use Drupal\Core\Annotation\Translation;
use Drupal\Core\TypedData\TypedData; use Drupal\Core\TypedData\PrimitiveBase;
use Drupal\Core\TypedData\Type\FloatInterface;
/** /**
* The float data type. * The float data type.
...@@ -19,16 +20,9 @@ ...@@ -19,16 +20,9 @@
* *
* @DataType( * @DataType(
* id = "float", * id = "float",
* label = @Translation("Float"), * label = @Translation("Float")
* primitive_type = 4
* ) * )
*/ */
class Float extends TypedData { class Float extends PrimitiveBase implements FloatInterface {
/**
* The data value.
*
* @var float
*/
protected $value;
} }
...@@ -9,7 +9,8 @@ ...@@ -9,7 +9,8 @@
use Drupal\Core\TypedData\Annotation\DataType; use Drupal\Core\TypedData\Annotation\DataType;
use Drupal\Core\Annotation\Translation; use Drupal\Core\Annotation\Translation;
use Drupal\Core\TypedData\TypedData; use Drupal\Core\TypedData\PrimitiveBase;
use Drupal\Core\TypedData\Type\IntegerInterface;
/** /**
* The integer data type. * The integer data type.
...@@ -19,16 +20,9 @@ ...@@ -19,16 +20,9 @@
* *
* @DataType( * @DataType(
* id = "integer", * id = "integer",
* label = @Translation("Integer"), * label = @Translation("Integer")
* primitive_type = 3
* ) * )
*/ */
class Integer extends TypedData { class Integer extends PrimitiveBase implements IntegerInterface {
/**
* The data value.
*
* @var integer
*/
protected $value;
} }
...@@ -9,7 +9,8 @@ ...@@ -9,7 +9,8 @@
use Drupal\Core\TypedData\Annotation\DataType; use Drupal\Core\TypedData\Annotation\DataType;
use Drupal\Core\Annotation\Translation; use Drupal\Core\Annotation\Translation;
use Drupal\Core\TypedData\TypedData; use Drupal\Core\TypedData\PrimitiveBase;
use Drupal\Core\TypedData\Type\StringInterface;
/** /**
* The string data type. * The string data type.
...@@ -19,16 +20,9 @@ ...@@ -19,16 +20,9 @@
* *
* @DataType( * @DataType(
* id = "string", * id = "string",
* label = @Translation("String"), * label = @Translation("String")
* primitive_type = 2
* ) * )
*/ */
class String extends TypedData { class String extends PrimitiveBase implements StringInterface {
/**
* The data value.
*
* @var string
*/
protected $value;
} }
<?php
/**
* @file
* Contains \Drupal\Core\TypedData\Type\TimeSpan.
*/
namespace Drupal\Core\TypedData\Plugin\DataType;
use Drupal\Core\TypedData\Annotation\DataType;
use Drupal\Core\Annotation\Translation;
use Drupal\Core\TypedData\Type\DurationInterface;
/**
* The time span data type represents durations as number of seconds.
*
* The plain value is the (integer) number of seconds. Note that time spans only
* map correctly to durations as long as the number of seconds does not exceed
* a day (there is already a difference in applying a duration of a day or 24
* hours due to daylight savings). If that's an issue, consider using
* \Drupal\Core\TypedData\Type\DurationIso8601 instead.
*
* @DataType(
* id = "timespan",
* label = @Translation("Time span in seconds")
* )
*
* @see \Drupal\Core\TypedData\Type\DurationIso8601
*/
class TimeSpan extends Integer implements DurationInterface {
/**
* {@inheritdoc}
*/
public function getDuration() {
if ($this->value) {
// Keep the duration in seconds as there is generally no valid way to
// convert it to days, months or years.
return new \DateInterval('PT' . $this->value . 'S');
}
}
/**
* {@inheritdoc}
*/
public function setDuration(\DateInterval $duration) {
// Note that this applies the assumption of 12 month's a 30 days and
// each year having 365 days. There is no accurate conversion for time spans
// exceeding a day.
$this->value = ($duration->y * 365 * 24 * 60 * 60) +
($duration->m * 30 * 24 * 60 * 60) +
($duration->d * 24 * 60 * 60) +
($duration->h * 60 * 60) +
($duration->i * 60) +
$duration->s;
}
}
<?php
/**
* @file
* Contains \Drupal\Core\TypedData\Type\Timestamp.
*/
namespace Drupal\Core\TypedData\Plugin\DataType;
use Drupal\Core\TypedData\Annotation\DataType;
use Drupal\Core\Annotation\Translation;
use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\Core\TypedData\Type\DateTimeInterface;
/**
* The timestamp data type.
*
* @DataType(
* id = "timestamp",
* label = @Translation("String")
* )
*/
class Timestamp extends Integer implements DateTimeInterface {
/**
* The data value as a UNIX timestamp.
*
* @var integer
*/
protected $value;
/**
* {@inheritdoc}
*/
public function getDateTime() {
if ($this->value) {
return new DrupalDateTime($this->value);
}
}
/**
* {@inheritdoc}
*/
public function setDateTime(DrupalDateTime $dateTime) {
$this->value = $dateTime->getTimestamp();
}
}
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
use Drupal\Core\TypedData\Annotation\DataType; use Drupal\Core\TypedData\Annotation\DataType;
use Drupal\Core\Annotation\Translation; use Drupal\Core\Annotation\Translation;
use Drupal\Core\TypedData\PrimitiveBase;
use Drupal\Core\TypedData\Type\UriInterface;
use Drupal\Core\TypedData\TypedData; use Drupal\Core\TypedData\TypedData;
/** /**
...@@ -18,16 +20,9 @@ ...@@ -18,16 +20,9 @@
* *
* @DataType( * @DataType(
* id = "uri", * id = "uri",
* label = @Translation("URI"), * label = @Translation("URI")
* primitive_type = 7
* ) * )
*/ */
class Uri extends TypedData { class Uri extends PrimitiveBase implements UriInterface {
/**
* The data value.
*
* @var string
*/
protected $value;
} }
<?php
/**
* @file
* Contains \Drupal\Core\TypedData\Primitive.
*/
namespace Drupal\Core\TypedData;
/**
* Class that holds constants for all primitive data types.
*/
final class Primitive {
/**
* The BOOLEAN primitive data type.
*
* @see \Drupal\Core\TypedData\Plugin\DataType\Boolean
*/
const BOOLEAN = 1;
/**
* The STRING primitive data type.
*
* @see \Drupal\Core\TypedData\Plugin\DataType\String
*/
const STRING = 2;
/**
* The INTEGER primitive data type.
*
* @see \Drupal\Core\TypedData\Plugin\DataType\Integer
*/
const INTEGER = 3;
/**
* The FLOAT primitive data type.
*
* @see \Drupal\Core\TypedData\Plugin\DataType\Float
*/
const FLOAT = 4;
/**
* The DATE primitive data type.
*
* @see \Drupal\Core\TypedData\Plugin\DataType\Date
*/
const DATE = 5;
/**
* The DURATION primitive data type.
*
* @see \Drupal\Core\TypedData\Plugin\DataType\Duration
*/
const DURATION = 6;
/**
* The URI primitive data type.
*
* @see \Drupal\Core\TypedData\Plugin\DataType\Uri
*/
const URI = 7;
/**
* The BINARY primitive data type.
*
* @see \Drupal\Core\TypedData\Plugin\DataType\Binary
*/
const BINARY = 8;
}
<?php
/**
* @file
* Contains \Drupal\Core\TypedData\PrimitiveBase.
*/
namespace Drupal\Core\TypedData;
/**
* Base class for primitive data types.
*/
abstract class PrimitiveBase extends TypedData implements PrimitiveInterface {
/**
* The data value.
*
* @var mixed
*/
protected $value;
/**
* {@inheritdoc}
*/
public function getValue() {
return $this->value;
}
/**
* {@inheritdoc}
*/
public function setValue($value, $notify = TRUE) {
// Notify the parent of any changes to be made.
if ($notify && isset($this->parent)) {
$this->parent->onChange($this->name);
}
$this->value = $value;