If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.
With a Subscription, click any sentence in the script to jump to that part of the video!
Login SubscribeThanks to our data transformer - specifically the fact that it throws a TransformationFailedException
when a bad email is entered - our UserSelectTextType
has some built-in sanity validation!
But, the message we passed to the exception is not what's shown to the user. That's just internal. To control the message, well, we already know the answer! Add an invalid_message
option when we create the field.
Or... instead of configuring that option when we're adding the specific field, we can give this option a default value for our custom field type. Open UserSelectTextType
, go back to the Code -> Generate menu, or Command + N on a Mac, and this time, override configureOptions()
. Inside, add $resolver->setDefaults()
and give the invalid_message
option a different default: "User not found".
... lines 1 - 11 | |
class UserSelectTextType extends AbstractType | |
{ | |
... lines 14 - 30 | |
public function configureOptions(OptionsResolver $resolver) | |
{ | |
$resolver->setDefaults([ | |
'invalid_message' => 'Hmm, user not found!', | |
]); | |
} | |
} |
Try that out! Go back, refresh and... very nice!
And hey! We've seen this configureOptions()
method before inside our normal form classes! When you're building an entire form, configureOptions()
is used to set some options on your... whole form. There aren't very many common things to configure at that level.
But when you're creating a custom field type: configureOptions()
is used to set the options for that specific field. We've just changed the default value for the invalid_message
option. The cool thing is that this can still be overridden if we want: we could add an invalid_message
option to the author field and it would win!
I want to talk more about field options because they can unlock some serious possibilities. But first, there is a teenie, tiny bug with our data transformer. Clear out the author
text box and try to submit. Duh - disable HTML5 validation by adding the novalidate
attribute. Hit update!
Oh! Our sanity validation still fails: User not found. That's not quite what we want. Instead of failing, our data transformer should probably just return null
.
Go back to EmailToUserTransformer
. In reverseTransform()
, if $value
is empty, just return
. So, if the field is submitted empty, null
should be passed to setAuthor()
.
But, hmm... the problem now is that, while it's technically ok to call setAuthor()
with a null
argument, we want that field to be required!
Re-submit the form! Oof - an integrity constraint violation: it's trying to save to the database with null
set as the author_id
column. We purposely made this required in the database and this is a great example of... messing up! We forget to add an important piece of business validation: to make the author
required. No worries: open the Article
class, find the $author
field and, above it, add @Assert\NotNull()
. Give it a message: Please set an author
.
... lines 1 - 17 | |
class Article | |
{ | |
... lines 20 - 71 | |
/** | |
... lines 73 - 74 | |
* @Assert\NotNull(message="Please set an author") | |
*/ | |
private $author; | |
... lines 78 - 269 | |
} |
Try that again. Excellent! This is the behavior - and error - we expect.
Next: how could we make our custom field type behave differently if it was used in different forms? Like, what if in one form, we want the user to be able to enter any user's email address but in another form we only want to allow the user to enter the email address of an admin user. Let's learn more about the power of form field options.
// composer.json
{
"require": {
"php": "^7.1.3",
"ext-iconv": "*",
"composer/package-versions-deprecated": "^1.11", // 1.11.99
"knplabs/knp-markdown-bundle": "^1.7", // 1.7.0
"knplabs/knp-paginator-bundle": "^2.7", // v2.8.0
"knplabs/knp-time-bundle": "^1.8", // 1.8.0
"nexylan/slack-bundle": "^2.0,<2.2.0", // v2.0.0
"php-http/guzzle6-adapter": "^1.1", // v1.1.1
"sensio/framework-extra-bundle": "^5.1", // v5.2.1
"stof/doctrine-extensions-bundle": "^1.3", // v1.3.0
"symfony/asset": "^4.0", // v4.1.6
"symfony/console": "^4.0", // v4.1.6
"symfony/flex": "^1.0", // v1.17.6
"symfony/form": "^4.0", // v4.1.6
"symfony/framework-bundle": "^4.0", // v4.1.6
"symfony/orm-pack": "^1.0", // v1.0.6
"symfony/security-bundle": "^4.0", // v4.1.6
"symfony/serializer-pack": "^1.0", // v1.0.1
"symfony/twig-bundle": "^4.0", // v4.1.6
"symfony/validator": "^4.0", // v4.1.6
"symfony/web-server-bundle": "^4.0", // v4.1.6
"symfony/yaml": "^4.0", // v4.1.6
"twig/extensions": "^1.5" // v1.5.2
},
"require-dev": {
"doctrine/doctrine-fixtures-bundle": "^3.0", // 3.0.2
"easycorp/easy-log-handler": "^1.0.2", // v1.0.7
"fzaninotto/faker": "^1.7", // v1.8.0
"symfony/debug-bundle": "^3.3|^4.0", // v4.1.6
"symfony/dotenv": "^4.0", // v4.1.6
"symfony/maker-bundle": "^1.0", // v1.8.0
"symfony/monolog-bundle": "^3.0", // v3.3.0
"symfony/phpunit-bridge": "^3.3|^4.0", // v4.1.6
"symfony/profiler-pack": "^1.0", // v1.0.3
"symfony/var-dumper": "^3.3|^4.0" // v4.1.6
}
}