Symfony: Make a datetime form field really read-on

2019-08-09 00:43发布

问题:

I marked a datetime form field as read_only. Since this seams to have no effect I overruled the default twig template. This works fine.

{% block datetime_widget %}
    {% if read_only %}
        {{ value.date.year }}-{{ value.date.month }}-{{ value.date.day }} {{ value.time.hour }}:{{ value.time.minute }}
    {% else %}
        {{ parent() }}
    {% endif %}
{% endblock %}

This is the form type I'm using:

/**
 * @ORM\Entity
 */
abstract class BusinessClass
{

    /**
     * @ORM\Column(type="datetime")
     * @var \DateTime
     */
    private $created;

    /**
     * @return \DateTime
     */
    public function getCreated()
    {
        return $this->created;
    }

}

And this is how the datetime field is added to the form builder:

$formBuilder->add('created', 'datetime', array('read_only' => true));

However, symfony still tries to set the unchanged value back to my form type. Since it's read-only I only implemented a get method but not set method. That's why I get this error message:

InvalidPropertyException: Neither element "created" nor method "setCreated()" exists in class "Cinergy\ShopBundle\Tests\Functional\TestBundle\Entity\RecurringProduct"

    in /Users/ernst/Source/php/cinergy/shop/vendor/symfony/symfony/src/Symfony/Component/Form/Util/PropertyPath.php line 552
    at PropertyPath->writeProperty(object(RecurringProduct), 'created', null, false, null) in /Users/ernst/Source/php/cinergy/shop/vendor/symfony/symfony/src/Symfony/Component/Form/Util/PropertyPath.php line 318
    at PropertyPath->setValue(object(RecurringProduct), null) in /Users/ernst/Source/php/cinergy/shop/vendor/symfony/symfony/src/Symfony/Component/Form/Extension/Core/DataMapper/PropertyPathMapper.php line 74
    at PropertyPathMapper->mapFormsToData(array('created' => object(Form), 'duration' => object(Form), 'id' => object(Form), 'name' => object(Form), 'price' => object(Form), 'sku' => object(Form), 'updated' => object(Form), '__entity' => object(Form), '__id' => object(Form)), object(RecurringProduct)) in /Users/ernst/Source/php/cinergy/shop/vendor/symfony/symfony/src/Symfony/Component/Form/Form.php line 569
    at Form->bind(object(Request)) in /Users/ernst/Source/php/cinergy/shop/src/Cinergy/DaylightBundle/Controller/BrowserController.php line 123
    at BrowserController->updateAction(object(Request))
    at call_user_func_array(array(object(BrowserController), 'updateAction'), array(object(Request))) in /Users/ernst/Source/php/cinergy/shop/src/Cinergy/CommonBundle/EventListener/TransactionWrapper.php line 34
    at TransactionWrapper->wrappedExecution(object(Request))
    at call_user_func_array(array(object(TransactionWrapper), 'wrappedExecution'), array(object(Request))) in /Users/ernst/Source/php/cinergy/shop/app/bootstrap.php.cache line 1426
    at HttpKernel->handleRaw(object(Request), '1') in /Users/ernst/Source/php/cinergy/shop/app/bootstrap.php.cache line 1390
    at HttpKernel->handle(object(Request), '1', true) in /Users/ernst/Source/php/cinergy/shop/app/bootstrap.php.cache line 1566
    at HttpKernel->handle(object(Request), '1', true) in /Users/ernst/Source/php/cinergy/shop/app/bootstrap.php.cache line 617
    at Kernel->handle(object(Request)) in /Users/ernst/Source/php/cinergy/shop/web/app_dev.php line 28

Since this is part of my business logic I don't want to implement a setCreate method. It's also woth mentioning, that the very same thing works fine for text fields.

Any ideas about how I can stop symfony from setting the value if the read_only option is set?

回答1:

The short answer is: Use disabled instead of read_only.

After finding the relevant part in the docs I think that the rendering of datetime for read_only is not correct. Only setting read_only is changing nothing. According to the docs it should be rednered as read only HTML.



回答2:

Unfortunately, if a mapped field is set to be disabled it is then not persisted. Its value becomes null, which is probably not what the OP is looking for. An alternate solution is to do something like the following in your template:

{% if household.dateAdded is not null %}{{ household.dateAdded|date('m/d/Y') }}
<input type="hidden" name="household[dateAdded]" value="{{ household.dateAdded|date('m/d/Y') }}">
{% endif %}

where household is the form name, dateAdded is the mapped field name.