123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276 |
- <?php
- namespace Symfony\Component\Form;
- /*
- * This file is part of the Symfony framework.
- *
- * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
- *
- * This source file is subject to the MIT license that is bundled
- * with this source code in the file LICENSE.
- */
- use Symfony\Component\Form\ValueTransformer\ReversedTransformer;
- use Symfony\Component\Form\ValueTransformer\StringToDateTimeTransformer;
- use Symfony\Component\Form\ValueTransformer\TimestampToDateTimeTransformer;
- use Symfony\Component\Form\ValueTransformer\ValueTransformerChain;
- use Symfony\Component\Form\ValueTransformer\DateTimeToLocalizedStringTransformer;
- use Symfony\Component\Form\ValueTransformer\DateTimeToArrayTransformer;
- class DateField extends HybridField
- {
- const FULL = 'full';
- const LONG = 'long';
- const MEDIUM = 'medium';
- const SHORT = 'short';
- const DATETIME = 'datetime';
- const STRING = 'string';
- const TIMESTAMP = 'timestamp';
- const RAW = 'raw';
- const INPUT = 'input';
- const CHOICE = 'choice';
- protected static $formats = array(
- self::FULL,
- self::LONG,
- self::MEDIUM,
- self::SHORT,
- );
- protected static $intlFormats = array(
- self::FULL => \IntlDateFormatter::FULL,
- self::LONG => \IntlDateFormatter::LONG,
- self::MEDIUM => \IntlDateFormatter::MEDIUM,
- self::SHORT => \IntlDateFormatter::SHORT,
- );
- protected static $widgets = array(
- self::INPUT,
- self::CHOICE,
- );
- protected static $types = array(
- self::DATETIME,
- self::STRING,
- self::TIMESTAMP,
- self::RAW,
- );
- /**
- * The ICU formatter instance
- * @var \IntlDateFormatter
- */
- protected $formatter;
- /**
- * Configures the text field.
- *
- * Available options:
- *
- * * widget: How to render the field ("input" or "select"). Default: "input"
- * * years: An array of years for the year select tag (optional)
- * * months: An array of months for the month select tag (optional)
- * * days: An array of days for the day select tag (optional)
- * * format: See DateValueTransformer. Default: medium
- * * type: The type of the date ("date", "datetime" or "timestamp"). Default: "date"
- * * data_timezone: The timezone of the data
- * * user_timezone: The timezone of the user entering a new value
- * * pattern: The pattern for the select boxes when "widget" is "select".
- * You can use the placeholders "%year%", "%month%" and "%day%".
- * Default: locale dependent
- *
- * @param array $options Options for this field
- * @throws \InvalidArgumentException Thrown if you want to show a timestamp with the select widget.
- */
- protected function configure()
- {
- $this->addOption('years', range(date('Y') - 5, date('Y') + 5));
- $this->addOption('months', range(1, 12));
- $this->addOption('days', range(1, 31));
- $this->addOption('format', self::MEDIUM, self::$formats);
- $this->addOption('type', self::DATETIME, self::$types);
- $this->addOption('data_timezone', 'UTC');
- $this->addOption('user_timezone', 'UTC');
- $this->addOption('widget', self::CHOICE, self::$widgets);
- $this->addOption('pattern');
- $this->initFormatter();
- $transformers = array();
- if ($this->getOption('type') === self::STRING) {
- $transformers[] = new StringToDateTimeTransformer(array(
- 'input_timezone' => $this->getOption('data_timezone'),
- 'output_timezone' => $this->getOption('data_timezone'),
- 'format' => 'Y-m-d',
- ));
- } else if ($this->getOption('type') === self::TIMESTAMP) {
- $transformers[] = new TimestampToDateTimeTransformer(array(
- 'output_timezone' => $this->getOption('data_timezone'),
- 'input_timezone' => $this->getOption('data_timezone'),
- ));
- } else if ($this->getOption('type') === self::RAW) {
- $transformers[] = new ReversedTransformer(new DateTimeToArrayTransformer(array(
- 'input_timezone' => $this->getOption('data_timezone'),
- 'output_timezone' => $this->getOption('data_timezone'),
- 'fields' => array('year', 'month', 'day'),
- )));
- }
- if ($this->getOption('widget') === self::INPUT) {
- $transformers[] = new DateTimeToLocalizedStringTransformer(array(
- 'date_format' => $this->getOption('format'),
- 'time_format' => DateTimeToLocalizedStringTransformer::NONE,
- 'input_timezone' => $this->getOption('data_timezone'),
- 'output_timezone' => $this->getOption('user_timezone'),
- ));
- $this->setFieldMode(self::FIELD);
- } else {
- $transformers[] = new DateTimeToArrayTransformer(array(
- 'input_timezone' => $this->getOption('data_timezone'),
- 'output_timezone' => $this->getOption('user_timezone'),
- ));
- $this->setFieldMode(self::GROUP);
- $this->addChoiceFields();
- }
- if (count($transformers) > 0) {
- $this->setValueTransformer(new ValueTransformerChain($transformers));
- }
- }
- /**
- * Generates an array of choices for the given values
- *
- * If the values are shorter than $padLength characters, they are padded with
- * zeros on the left side.
- *
- * @param array $values The available choices
- * @param integer $padLength The length to pad the choices
- * @return array An array with the input values as keys and the
- * padded values as values
- */
- protected function generatePaddedChoices(array $values, $padLength)
- {
- $choices = array();
- foreach ($values as $value) {
- $choices[$value] = str_pad($value, $padLength, '0', STR_PAD_LEFT);
- }
- return $choices;
- }
- /**
- * Generates an array of localized month choices
- *
- * @param array $months The month numbers to generate
- * @return array The localized months respecting the configured
- * locale and date format
- */
- protected function generateMonthChoices(array $months)
- {
- $pattern = $this->formatter->getPattern();
- if (preg_match('/M+/', $pattern, $matches)) {
- $this->formatter->setPattern($matches[0]);
- $choices = array();
- foreach ($months as $month) {
- $choices[$month] = $this->formatter->format(gmmktime(0, 0, 0, $month));
- }
- $this->formatter->setPattern($pattern);
- } else {
- $choices = $this->generatePaddedChoices($months, 2);
- }
- return $choices;
- }
- /**
- * {@inheritDoc}
- */
- public function render(array $attributes = array())
- {
- if ($this->getOption('widget') === self::INPUT) {
- return $this->generator->tag('input', array_merge(array(
- 'id' => $this->getId(),
- 'name' => $this->getName(),
- 'value' => $this->getDisplayedData(),
- 'type' => 'text',
- ), $attributes));
- } else {
- // set order as specified in the pattern
- if ($this->getOption('pattern')) {
- $pattern = $this->getOption('pattern');
- }
- // set right order with respect to locale (e.g.: de_DE=dd.MM.yy; en_US=M/d/yy)
- // lookup various formats at http://userguide.icu-project.org/formatparse/datetime
- else if (preg_match('/^([yMd]+).+([yMd]+).+([yMd]+)$/', $this->formatter->getPattern())) {
- $pattern = preg_replace(array('/y+/', '/M+/', '/d+/'), array('%year%', '%month%', '%day%'), $this->formatter->getPattern());
- }
- // default fallback
- else {
- $pattern = '%year%-%month%-%day%';
- }
- return str_replace(array('%year%', '%month%', '%day%'), array(
- $this->get('year')->render($attributes),
- $this->get('month')->render($attributes),
- $this->get('day')->render($attributes),
- ), $pattern);
- }
- }
- /**
- * Sets the locale of this field.
- *
- * @see Localizable
- */
- public function setLocale($locale)
- {
- parent::setLocale($locale);
- $this->initFormatter();
- if ($this->getOption('widget') === self::CHOICE) {
- $this->addChoiceFields();
- }
- }
- /**
- * Initializes (or reinitializes) the formatter
- */
- protected function initFormatter()
- {
- $this->formatter = new \IntlDateFormatter(
- $this->locale,
- self::$intlFormats[$this->getOption('format')],
- \IntlDateFormatter::NONE
- );
- }
- /**
- * Adds (or replaces if already added) the fields used when widget=CHOICE
- */
- protected function addChoiceFields()
- {
- $this->add(new ChoiceField('year', array(
- 'choices' => $this->generatePaddedChoices($this->getOption('years'), 4),
- )));
- $this->add(new ChoiceField('month', array(
- 'choices' => $this->generateMonthChoices($this->getOption('months')),
- )));
- $this->add(new ChoiceField('day', array(
- 'choices' => $this->generatePaddedChoices($this->getOption('days'), 2),
- )));
- }
- }
|