How to display a month-year dropdown in Symfony2

前端 未结 5 1195
生来不讨喜
生来不讨喜 2020-12-09 11:36

In my application, the user hsa to give a date by only selecting a month and a year in two dropdown lists. How can I achieve that?

Here is what I\'ve tried so far :

相关标签:
5条回答
  • 2020-12-09 12:08

    Very simple, datetime requires day!

    You need to output day, something like this:

            ->add(
                'ccExpirationDate',
                'date',
                array(
                    'format'          => 'MMM-yyyy',
                    'years'           => range(date('Y'), date('Y')+12),
                    'days'            => array(1),
                    'empty_value'     => array('year' => '----', 'month' => '----', 'day' => false)
                )
            )
    

    TWIG:

    {{ 
        form_widget(
            form.payment.ccExpirationDate.day, 
            { 
                'attr': { 'style': 'display:none' } }
            ) 
    }}
    
    0 讨论(0)
  • 2020-12-09 12:27

    Example for credit card expiration date:

    $builder->add('expirationDate', 'date', array(
     'label' => 'Expiration date',
     'widget' => 'choice',
     'empty_value' => array('year' => 'Year', 'month' => 'Month', 'day' => 'Day'),
     'format' => 'dd-MM-yyyy',
     'input' => 'string',
     'data' => date('Y-m-d'),
     'years' => range(date('Y'), date('Y') + 10),
    ));
    

    Then you must render this field manually.

    Your form's twig template:

    {{ form_row(form.expirationDate, {'date_pattern': '<span style="display: none;">{{ day }}</span> {{ month }} <span class="delim">&#47;</span> {{ year }}'}) }}
    

    Overriding date_pattern will hide day select. You will get month / year format.

    0 讨论(0)
  • 2020-12-09 12:27

    I working on a custom form type which would allow to solve such problem. The solution is based on what @oleg-andreyev proposed. The logic wrapped to a form type.

    Usage:

    <?php
    $builder->add('exp_date', 'payum_credit_card_expiration_date');
    

    The form type code:

    <?php
    namespace Payum\Bundle\PayumBundle\Form\Type;
    
    use Symfony\Component\Form\AbstractType;
    use Symfony\Component\Form\FormInterface;
    use Symfony\Component\Form\FormView;
    use Symfony\Component\OptionsResolver\OptionsResolverInterface;
    
    class CreditCardExpirationDateType extends AbstractType
    {
        public function finishView(FormView $view, FormInterface $form, array $options)
        {
            if ('choice' == $options['widget']) {
                if (empty($view['day']->vars['value'])) {
                    $view['day']->vars['value'] = $view['day']->vars['choices'][0]->value;
                }
    
                $style = 'display:none';
                if (false == empty($view['day']->vars['attr']['style'])) {
                    $style = $view['day']->vars['attr']['style'].'; '.$style;
                }
    
                $view['day']->vars['attr']['style'] = $style;
            }
        }
    
        public function setDefaultOptions(OptionsResolverInterface $resolver)
        {
            $resolver->replaceDefaults(array(
                'years' => range(date('Y'), date('Y') + 9)
            ));
        }
    
        public function getParent()
        {
            return 'date';
        }
    
        public function getName()
        {
            return 'payum_credit_card_expiration_date';
        }
    }
    

    You can copy\paste it or register payum bundle and use this type from (will be available there in next major release).

    0 讨论(0)
  • 2020-12-09 12:28

    I'm not using dropdown, but bootstrap-datetimepicker in single_text. For me to save month and year in separate fields in database would be difficult, because I'm ordering by this date. So I decided always to save the first day of the chosen month. I'm using DatetimepickerBundle, and my custom form type looks like that:

    class MonthPickerType extends AbstractType
    {
        public function configureOptions(OptionsResolver $resolver)
        {
            $resolver->setDefaults(array(
                'pickerOptions' => array(
                    'autoclose' => true,
                    'format' => 'mm/yyyy',
                    'startView' => 'year',
                    'minView' => 'year',
                )
            ));
        }
    
        public function getParent()
        {
            return 'collot_datetime';
        }
    
        public function getName()
        {
            return 'month_picker';
        }
    }
    

    And the result:

    0 讨论(0)
  • 2020-12-09 12:30

    @Oleg was pretty close to the correct answer. You have to use a view transformer to make sure that the DateTime gets a day.

    /* In your formType.php */
    
    $builder->add(
       $builder->create('date1', 'date', array(
           'format'      => 'MMMM-yyyyd', // you need to have 'y', 'M' and 'd' here
           'years'       => range(date('Y'), date('Y') - 30, -1)
       ))
       ->addViewTransformer(new IncompleteDateTransformer()));
    )
    

    Create a transformer:

    class IncompleteDateTransformer implements DataTransformerInterface
    {
    /**
     * Do nothing when transforming from norm -> view
     */
    public function transform($object)
    {
        return $object;
    }
    
    /**
     * If some components of the date is missing we'll add those. 
     * This reverse transform will work when month and/or day is missing
     *
     */
    public function reverseTransform($date)
    {
        if (!is_array($date)) {
            return $date;
        }
    
        if (empty($date['year'])) {
            return $date;
        }
    
        if (empty($date['day'])) {
            $date['day']=1;
        }
    
        if (empty($date['month'])) {
            $date['month']=1;
        }
    
        return $date;
    }
    } 
    

    Create a twig template where you use a custom form theme from the file itself:

    {# example.html.twig #}
    {% form_theme form _self %}
    
    {% block date_widget %}
    {% spaceless %}
        {% if widget == 'single_text' %}
            {{ block('field_widget') }}
        {% else %}
            <div {{ block('widget_container_attributes') }}>
                <div class="datetime_widget">
                    {{ date_pattern|replace({
                    '{{ year }}': form_widget(form.year),
                    '{{ month }}': form_widget(form.month),
                    '{{ day }}':  '',
                    })|raw }}
                </div>
            </div>
        {% endif %}
    {% endspaceless %}
    {% endblock date_widget %}
    
    <h2>Select a date</h2>
    {{ form(form) }}
    

    References:

    • Data transformers
    • Form customization
    • Choice type
    0 讨论(0)
提交回复
热议问题