Как отобразить раскрывающийся список за месяц в Symfony2
В моем приложении пользователь hsa дает дату, только выбрав месяц и год в двух раскрывающихся списках. Как я могу это достичь?
Вот что я пробовал до сих пор:
В моей форме:
$builder->add('date1', 'date', array(
'widget' => 'choice',
'empty_value' => '',
'format' => 'MMMM-yyyy',
'input' => 'datetime',
'years' => range(date('Y'), date('Y') - 30, -1)
)
который фактически работает и отображает его точно так, как я хочу, но при проверке формы я получаю сообщение об ошибке:
This value is not valid
Снимок экрана желаемого результата:
![Screenshot]()
Ответы
Ответ 1
Пример срока действия кредитной карты:
$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),
));
Затем вы должны отобразить это поле вручную.
Шаблон формы вашей формы:
{{ form_row(form.expirationDate, {'date_pattern': '<span style="display: none;">{{ day }}</span> {{ month }} <span class="delim">/</span> {{ year }}'}) }}
Переопределение date_pattern
скроет выбор дня. Вы получите формат месяц/год.
Ответ 2
Очень просто, datetime требует дня!
Вам нужно вывести день, что-то вроде этого:
->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' } }
)
}}
Ответ 3
@Oleg был довольно близок к правильному ответу. Вы должны использовать трансформатор вида, чтобы удостовериться, что DateTime получает день.
/* 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()));
)
Создайте трансформатор:
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;
}
}
Создайте шаблон ветки, в котором вы используете пользовательскую тему формы из самого файла:
{# 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) }}
Ссылки:
Ответ 4
Я работаю над настраиваемым типом формы, который позволил бы решить такую проблему. Решение основано на том, что предложил @oleg-andreyev. Логика, привязанная к типу формы.
Использование:
<?php
$builder->add('exp_date', 'payum_credit_card_expiration_date');
Код типа формы:
<?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';
}
}
Вы можете скопировать\вставить его или зарегистрировать пакет платежей и использовать этот тип (будет доступен там в следующей крупной версии).
Ответ 5
Я не использую dropdown, но bootstrap-datetimepicker в single_text
. Мне экономить месяц и год в отдельных полях в базе данных было бы сложно, потому что я заказываю к этой дате. Поэтому я решил сохранить первый день выбранного месяца. Я использую DatetimepickerBundle, и мой пользовательский тип формы выглядит следующим образом:
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';
}
}
И результат:
![введите описание изображения здесь]()