 Yes, I think I'm going to start. So welcome to my presentation about validation. I have bad news. The title is, this one is supposed to be Validation with Symphony from a Drupal perspective. But unfortunately, my Drupal knowledge, I don't have any Drupal knowledge. I wanted to learn Drupal, but it was a very short time. So I won't be able to cover any Drupal related stuff. I will just focus on using Symphony Validator components. And then I will let you try to use it into Drupal. So please apologize for this little issue. I don't have your skills in Drupal. So let's get started. So my name is Hugo Heman. I'm the head of training at Sensual Apps France. I live in Paris. So I came with my colleagues. And so I'm a Symphony contributor. So I'm Symphony certified and also one of the contributors to the projects and to the documentation. You can find me on Twitter with HMN user accounts. Just a quick talk about Sensual. So we are the creator of Symphony. We raised 5 million euros at the end of 2013. And we create products like Sensual Apps Insights. So let's get into this validation talk. First of all, introduction. Why it's important to validate the data. A quick reminder, as a web developer, you are, I guess, old web developers, make sure that you never trust any user inputs. So everything that comes in on your application should be validated and filtered. So when someone submits a form, for example, or when someone uses a REST API you are offering, so any data that comes in on your web server must be validated and filtered. So that means you should check the data format. So for example, if you expect an email address, check that the value you receive has a valid email address format, that's one of the data format. Check also check the consistency of the data, which means if, for example, you are dealing with an e-commerce website, you are selling conference tickets. If someone can change the quantity, make sure that the quantity, for example, is a valid integer greater than 0. So one, two more, that's all. But don't accept, for example, negative values for quantities. Check that the data integrity, for example, if the data contains HTML code or JavaScript codes, make sure that this code is valid for your needs or otherwise filter that data, remove these sensitive characters or pieces of code from the data you are validated. So it's about validating, but also filtering. In this talk, I will just focus on validation, not filtering, because the validator component only validates the data. But as you know, doing validation is not that simple. If you already have played with validation in PHP projects, you probably have already written lots of codes, lots of loaded code to validate data using regular expression, checking lengths, for example, checking format, and so on. It's not an easy task, because sometimes validation are related to complex rules. And this is what we are trying to offer with this validator component. We want you to write less codes and to be able to write complex rules without complexity. So if you are in this session, it's that probably because you are interested in symphony. Just a quick word about symphony framework, which is used by Drupal. So symphony is a framework, so a toolbox, a set of components that you can pick and choose. It's also a philosophy, which means symphony is an HTTP framework, and we try to embrace the HTTP protocol as much as possible. So we focus on standards. We have lots of, we are trying, yes, focus on standards in symphony. So we respect, for example, PSR0, PSR1, PSR2. We also take lots of inspiration on what it's done in other languages like Java or Python. And of course, I guess the most important symphony is also about the community. So it's not about the symphony community, but in a larger way, it's also the Drupal committee or any user who uses a tool that uses some symphony parts. So that makes symphony a great tool. As I said, symphony is a set of components. So you have something like 26 or 27 components as of today in symphony. And you can just pick and choose those components and use them in your PHP projects. So Drupal already uses something like 12 components. And you can add extra components to your Drupal projects. The side note symphony is also a full-sac framework. So we can use it as a global framework with everything inside and third-party dependencies. So let's take a look at this validation components. So if you want to use it in a PHP project or in a Drupal project, for example, you will have to require the dependency, the validator component dependency. This can be easily done with Composer. So everyone knows about Composer? Yes? So Composer is a dependency management system. You just describe the dependencies your PHP project require. And then you run the command line tool. You run Composer command tool to tell you, install that dependencies. And so Composer will resolve the dependencies you want to install. So if a dependency has other dependencies, Composer will install all the required dependencies in your PHP project. So each component in Symphony can be installed with Composer. So each package name is symphony slash and the name of the package. So in this case, symphony slash validator. This component has several dependencies with other symphony components. So Composer will grab the other dependencies of the validator components. Tile means from. So from 2.4 version, for example. Or you can already install symphony 2.5. 2.5 has been released last week. But Drupal uses symphony 2.3. As symphony 2.3 is a long-term supported version. It's supported for three years. Whether this version 2.4 and 2.5 are just supported for eight months. But it's really up to you to choose 2.3, 2.4, 2.5. Whatever versions you want has the 2.4 and 2.5 versions are quite compatible with 2.3. So if you start using 2.3, you can then migrate to another version, so greater versions, without breaking backward compatibility. I'm using, in this case, 2.4 or 2.5 has the validator components received some new features I will show you in those versions. So how to get that validator in symphony or if you use the components. Let's spread it forward. Once you have installed the dependencies with Composer, you just have to require this validation class, this validation namespace from the validator components. And this validation class has a static method called createValidator. So it just builds a new validator object. So you get back this validator object and then you are ready to go and you are ready to validate data. So just one line and you have a validator setup. With this validator object, you can validate data. So for example, there is this validateValue method. You will see that we have other methods on this validator object. But if I want to validate a single scale of value, I can use validateValue. I give it the value I want to validate. In this case, it's an email address. And I will validate this email address, this value against a constraint. So a constraint in symphony is an object. So as you can see, I'm instantiating the email class. So this email class is the email constraint in symphony. And the validateValue method returns a set of errors. So it's not just an array, it's an object. It's a constraints violation list object, which is an iterator object, iteratable object. So we can count on this object. And if this violation list contains at least one violation inside, that means your value is not valid. If the violation list is empty, your value is valid. Okay, so that's pretty straightforward. You just give them the value you want to validate and the constraints against you want to validate the value. Of course, you can combine those constraints. Let's take this example. I want to validate a username. So my username, double hamon. So I want this username to be between five to 15 characters long. So you can see there is a length, we have a length constraints, which takes some options. So some constraints may have options to configure the behavior of the constraints. So the length constraint has a mean and a max option. So you can constraint the edges, the limits of the string. And I also want to check the formats. So I'm using a regular expression in this case. We have a regex constraints. And this regex constraints has a pattern option. The pattern I want to match is only alpha characters. So only letters from A to Z. And I don't care about the case. So it's case-sensitive in this case. Okay, so you can combine, you can pass an array of constraints. So just one constraint or an array of constraints and the validator will execute all of these constraints on your value. That's for the basics. I will show you the API, the objects involved in this value component. And then from step to step, I will show you an example from very basic validation to more advanced complex rules. So we saw that the primary object is the validator object. This is the main object. The validator simply validates a value, a single scale of value, as we've seen. But you can also validate an object property or you can also validate a whole object as it says against a set of constraints. And this is what we are mostly interested in validating objects. So we are going to encapsulate data into objects and then we will ask the validator to check the content of these objects. You have four validation methods on this validator. So we saw validated value. You also have validated property, which means I want to only execute the validation constraints on the email property of my user object. You can see the user variable is a user object. I can use validator property value, which means I want to check that the value of the email property of the user object is foo at bar dot tld. And the most interesting method is validates. Validates is just a method that receives an object. You give it that object and it will validate the objects. So we are going to focus on this validate method as it's the most interesting one. As I said, the validator, when you validate a value, the validator returns a constraints violation list. It's an object which contains all the violations that have been raised during the validation process. So a violation is a failure, it's an error. So when you validate your user object, for example, you are getting back a constraints violation list, then you can iterate over this violation list to get each error, and each error is also an object. It's a constraints violation, which contains the error message. And this object, this error object, implements a two-string method. So you can easily echo or print the error. It will call the two-string methods for debugging purposes. And you will see that these error messages are translated also. So the components comes with translation files. So the validator validates the data against constraints. As I said, the constraints is the object that describes an assertive statement. So it tells how the data has to be validated, but the constraint doesn't contain any validation logic. It's just a description of the rule. So basically, we saw that a constraint is an object. It's a class, so we have to instantiate the class. All constraints classes extends the base constraints class. So we have a base type constraint, which is an abstract class. And you have few things in those classes. Most of the time, you have public properties, okay? And these public properties are options. So these are the options you can configure. Remember, when I pass the options as an array, a set of array, in fact, when you give an array of options to the construct method, which is defined in the base abstract class, these, the options you have in the array are simply feeding these public properties in your object. So if you search for documentation, just open the classes and you will know which options you can configure in any constraints objects. Some constraints classes may have methods, some methods, but most of the time it's just about public properties. So each constraints to trigger, to perform the validation logic, each constraints has an associated constraints validator instance. So you have, for example, a regex constraints and a regex validator, which triggers the business logic of validating the value against the regular expression. So this is an example, the regex validator, which is a built-in one. Each validator is a class, is an object that extends constraints validator. And this base class is abstract, so you must implement validate method. This validate method receives two arguments, the value you want to validate, and the constraints objects, which contains the business rule. So if you are using the regex validator, that means the object you are receiving here is the regex object, which contains the options of the regular expression validation. So as you can see, the valid methods check if the value is null or empty, that means we are skipping the validation. And if it's not empty, then we are processing the business logic of validating this value. And we have this special object context, the execution context, that allows you to set a violation in the violation list. Okay, so this is this object, which contains all the violations. So I want, this is how we can validate a value against a regular expression with this validator. So we have lots of built-in constraints you can use out of the box. Basic constraints like not blank or blank. So if you want to check that the value is not blank or if the value must be blank, or you want to check that the value must be true. Let's say, for example, a user must accept the terms and conditions of the websites. So you will apply true constraints on the checkbox. You can also check that a value is of a PHP internal type like integer or string or boolean and so on. We have string constraints. For example, the length constraints I've showed you. You have email constraints. The email constraints has options like checkMX if you want to perform an MX query on the web server, on the server on the email server to check that the domain name exists. And recently in Symphony 2.5, we also had it strict, strict option which perform a strict validation. So you can choose when validating an email to just check that the format is valid or that the format is a strict RFC compliant email format. It's really up to you. You can check for URL or an IP address also. They are built-in. Comparison constraints, if you want to check that the value is greater than another value or lower than value or identical or equal to. So all of these constraints are also built-in in the Symphony components. Date constraints, if you want to check a date. So a date can be a daytime object. It can be a timestamp or it can be a valid date string like my SQL strings. Those validators will be able to handle any valid date representation as the value. Unfortunately, we don't have a date range constraints. For example, if you want to validate that the dates you want to add it is between a date and another date. This is not supported as of today. Maybe in the next version there's, we have some requests on the repository about implementing such validators. I really like those ones, number and financial constraints. For example, you are building an e-commerce website so you want to validate a credit card scheme. So we have a card scheme built-in validator. For example, you give it the scheme of the credit card provider like American Express. You have to check that the number is a valid American Express card. Or you can check for an e-ban bank account. So if someone provides a bank account number, you can check that the number is valid using the LUN algorithm. Currency also you can validate that the currency string is valid, let's say USD or EUR. You can check for an ISBN if you are selling books, for example. So these are built-in constraints. I think my favorite one is image constraints. You can validate pictures. So if, for example, you let people upload pictures for their profile, then you can check that the image is one of these MIME types. So GPEG or PNG or GIF, whatever. You can check the max size, let's say one megabytes. And you can also constraints the ways and heights of this picture. So you want to allow pictures with a mean wave of 120 pixels and you can specify the max height, max width or mean height. We have other options for this image constraints. You can, for example, specify the ratio. So if you want to check for a ratio, that's possible. You can check that the picture is portrait or landscape oriented. If you want to force portrait or landscape orientation. So all of these options are built-in in this image constraints. We have range constraints. For collection constraints, for example, checking that a value is in a list of permitted values, of allowed values. So this is the choice option. So for example, I have a choices option saying I want to define an area that contains values between 10 to 99. And if I submit, for example, the value 30, I will check that 30 is the value between 10 and 99. Same for the list of languages or the list of locals or the list of countries. Those are built-in so you can check those information. I will show you this one, count later on, which allows you to check the number of items in a collection. This one is quite complex collection. You can validate an array. If you are using arrays instead of objects and you want to check the values inside an array for each keys, for each associative key, you can use these collection constraints. And for each associative keys of your array, you can apply a set of constraints that will be executed against the value. And last constraints we have built-in, the valid constraints, which check that an object, an embedded object is also valid. I will show you this one in a real example. User password, I don't think you are going to use it. It's really tied to the symphony security components. It allows you to check the user password. So if the user has to retype his password when updating his profile, for example, this is this value that checks that the retype password corresponds to the previous password. I will show you the callback constraint, which is quite useful, and also expression, which is a new one since symphony 2.4. That's a big overview of the constraints we have built-in in symphony. And of course, you can create your own constraints, as I will show you. So you can choose to define the validation in several formats. You can use YAML, Axomo, PHP code, or annotation. It's really up to you. It depends on which format you prefer. I really prefer annotations as it's more concise, so I will mostly focus on annotations during this presentation. But I will show you the four different formats. To configure those validation formats, you have to configure the validator with the validator builder object. So this is basically an object that pre-configures the validator you want to use. And this is how it works. If you want to create validator objects that can use YAML, or XML, or annotations, or PHP code. So when you create a validator builder object, you can add validation mapping formats. So I can register PHP method mapping. So this is a static method. I will be able to use in my object to map the constraints on my objects. Or I can register a YAML file that will contain the validation rules. Or I can register an XML validation file. Or I can enable annotation mapping. So this is how you configure the validator. So this is how it looks like in PHP. If you want to use raw PHP code for validation, if you have your objects, let's say another object. Another has a reference and a customer email address. I want to apply constraints on those two properties so I can implement this load validator metadata static method. Remember that this method is this one. I've configured in my builder. And then this method receives a metadata object in which you push the constraints you want to apply for each property. So for the reference property, I'm adding a node blank constraints. And for the reference property again, I'm pushing a length constraints. And for the customer PHP property, I want to push an email constraint. So this is how you can map constraints to your PHP object properties. PHP is fine as a configuration format, but it's quite verbal so you have lots of code to write. That's why YAML is probably better to extract the validation outside the object and to make it a bit more concise. This is how it looks like in your validation.yaml file, you tell that for this class, shop backslash order, so this is the name space of the class, I want to constraints the properties of my object. And for the reference property, I'm adding a set of constraints, so node blank, length, and regular expression. And for the customer property, I want to add node blank and email. If you want to do that in XML, it's a little bit more verbose, which is this code. So as you can see for this class order, I want to add constraints to the reference property and for each constraints, I will apply the options. So if you have an ID like PHP storm or Eclipse or NetBeans, that's not so verbose to type as the ID will provide code completion. But if you sublime text or Veeam or whatever text editor, it will be quite painful to write. So stick to YAML. And annotations, which is my favorite. If you want to use annotation, you have dependencies, third-party dependencies to install doctrine, especially the doctrine project provides the annotation parser. So you need those dependencies to use annotations. And this is how it looks like with annotation. For each property, you can attach constraints using annotations. So it's just about tagging the rules with annotations and then you're done. So as you can see, it's much more simpler, much more concise. The main drawback is that you are mixing PHP code with commented code with configuration. So that's the main issue. But otherwise, it makes the code concise. So I want to show you now all the capabilities you have as using this component. I will keep my order object. So we have an order object. Let's say we are selling products on the website. And my order project has a reference, a customer email address, and a number of items, a number of lines I want to order. So a collection of items. So we saw how to validate the reference and the email address. So I am adding assert not blank. So as you can see this at assert namespace is this one. Symphony component validator constraints that I'm aliasing with assert to make it shorter. And then I'm using add assert not blank, add assert lengths. We have the options, mean and max, rigor expression, and not blank and email address for the customer. Okay, so if you create your order objects with a reference, an invalid reference and an invalid email address, when you try to validate this order object with the validator, then the violation list, this error violation list returns these strings. So for the reference, we must have exactly 10 characters. For the reference, the rigor expression didn't match. This is a default error message for the regex constraints. And for the customer, I didn't send a valid email address. So I have this error message. Now the most interesting is how to validate this collection of items. I can check that to validate the order. I must have at least one item in the order. If I have zero item, that means I don't have any order. So I want, this is my rule. I want to validate that the order contains at least one item, one line. And it can't have more than 10 line of ordering. So in my order, I'm adding lines with my add line methods. Lines are arrays, which contains some properties like quantity, the quantity of the order I want to order, the product I want to order, the reference, the designation. And I want the designation to be optional. But the other ones are mandatory. So you can just use alasert count on this array. So as you can see, alasert count. And I want at least one element and at most 10 element. And I can also override the default error messages. So we have mean message option and max message option. So these are the two error messages that will be raised. Of course, those messages can be translated. They are just translation strings, translation identifier. So you can just use a unique constant name if you want. Abstract constant name as the identifier. But in this case, I'm just using sentences. And this is how I can validate that these lines array contains between one to 10 lines of products. But I want to get more in-depth in that lines array. Because remember, we are pushing those information, but I want to validate that each line has a quantity key and each line has a price key. So this is what I want to do. So I want to validate each line of my order object. So I'm adding a line with quantity, price, reference, and designation. And then this is going to be tough. We have this line property with the assert count, the previous assert count assertion. I will use at assert all. At assert all means I want to apply constraints on all elements in that collection. And the good thing is that you can nest assertions. You can nest the constraints. So inside the assert all constraints, I am pushing an assert collection sub constraints. So assert collection is for each element, each array, each line item in my lines collection. And for each fields, for example, for the reference associative key, I want that the reference to be required and it must be not blank. So required means the reference associative key in the array must be set, but the value must not be empty. Okay, so required is just about testing that the key is set, but it doesn't check that the value is not empty. That's why I'm using at assert not blank. In these constraints. For the quantity, I want the quantity to be required. So the key must be set in the array and the value is mandatory. It must be a valid integer and it must be at least one. Okay, so I can't have a quantity less than one. And the price is required. It must be a valid double type and I can accept zero as the default price. So if I want to provide free products to order, zero is an acceptable value, but it can be less than zero. And for the designation, it's optional. So if I don't set the designation in the array, then the validation will be skipped for that information. Okay, so it's quite a bit complex in this case, as you can see. So the code is a bit bloated with comments, but it works. This is how you can do that. There is of course a better way to achieve this validation. Can you guess which one? Do you have any ideas? Without, not yet, well, without using a different way, not using add assert all or add assert collection. Yes, adding more objects. Basically you just nest objects and you validate sub-object instead of validating arrays. So that's the deal. Instead of using arrays, you create a new order line object which contains the elements of each line element in your order. And for each property, you will add your validation constraints, okay? So then in your main script, you have your order, you are pushing order line objects, which contains the information. And in your main order class, instead of having this add assert all with all the nested constraints, you can basically just say add assert valid, which means you are explicitly telling the validator, go down into the collection and validate each object inside this collection, okay? So that's the meaning. If you don't put add assert valid, then the validator will just perform the count check, but it will not go down inside the collection to check the values inside it. So avoid using add assert collection or add assert all, try to use the sub-objects if you prefer, it's better. So now let's say we have a coupon. We can apply coupon codes on the order to get a small discount. So the coupon must equal a string. So you have to specify the unique string of the coupon code. So basically you can use add assert equal to, you give it the value of the coupon. And then if I set, let's say, if I set a different value in my property, then the validation will fail. So that's very simple constraints. But I want a more advanced constraint with this coupon. I want the coupon to be valid if the code is valid, but also if I have ordered at least three items and if I have at least $150 USDs of purchase. So I must order it for at least $850. So we have a more dynamic business rule to execute. And the problem with YAML or XAML or annotations formats is that those formats are static, they are static files. So it's difficult to design a dynamic business logic. So since Symphony 2.4, there's a way to achieve that with the expression, the brand new expression assertion. So Symphony 2.4 comes with a new component called expression language. It's an expression engine that allows you to write some expressions like this one. And these expressions will be analyzed by the expression engine. They will be compiled down to PHP and they will be executed in a sandbox environment. So there's no risk of security issues. And this is how I can mix a static configuration format like YAML or annotations or XAML with a more dynamic business rule. So in this case, I'm telling, so the coupon must be Drupalcon 2014. And the coupon will be valid if the number of items in my order are greater than two, so at least three. And if the sub-dota of the order is greater than $850. So I just have to implement those two methods, get number items and get sub-total. And then the expression constraints will be executed. This is how we can have more dynamic business rules. Let's say that's to continue with this other object. If you have an order, you have to set your billing address and your delivery address. So in an address, if you are based in the US or in Canada, you must set your states or your province in Canada. So if you feel your country and if the country is US, I must check that the state code is also provided. If it's another country, I don't care about the state. So my order object has now two properties, billing address and delivery address. And they are both address object. I've created an address object, address class, which contains the elements of an address. So city, zip code, state, country, and so on. So I want those two properties to be set. So they can't be blank. And they must be valid. So I want to validate the nested address object. So this is my address object. It has a street, a zip code, a city, a country, which all have these constraints on them. The country has an asset country built-in constraint. So Symphony knows the list of all countries in the world. So you can check that the selected country is valid. And we have the state, which is optional. And as you can see, the state can be set as the last argument of my construct method. So how to achieve this logic to check that if the country is United States or Canada, the state must be set as well. So you can do that using a validation method. So the constraints can be applied on properties, but you can also add constraints on methods. And those methods must be prefix with git, with git with get or is prefix. That's mandatory. The validator only executes method that returns value. And they must be prefix with is or gets. But then the name you have right after the prefix is or gets is really up to you. So I chose to use is, state, required, and filled. I'm using an assertion on it. That's not false. That means I expect the return value to be false. If it's something other than false, then the error message will be triggered, will be fired. So this is where I can put my validation logic. This is my custom validation row. If the country property contains Canada or US, if it doesn't contain Canada or US, then we don't have to care about the state. Otherwise we have to check that the state is empty or not empty. And if the state is empty, then we are triggering, we are firing this error message. So this is the error that will be output. So we have, for the building address, and for the building address, we have the state required and filled property or methods, but it's considered as a path as a property. And we have the error message that we can translate. So you can apply constraints on properties, but also on methods. And you can also apply constraints on classes with the special callback constraints I will show you. The problem with the getter methods constraint is that you can't attach the error message to a very particular field. If I switch back, the error message is linked to the name of the method we have executed. So we can't put that error message to another field. But I would like this error message to be applied on the state property because it's related to the state. So I can do that with a callback constraints that I will put on the class itself. I want to validate the whole object itself. So we've had a sort of callback here. I will specify the callback method in this class, in this object I want to execute. And when you use the assert callback function, you will receive an execution context object. I think since Symphony 2.4, you can now use the callback constraints on the methods directly on the class. But when you use callback, the callback constraints gives you the execution context. And this object allows you to map the error message to properties. So in this case, I'm telling that the violation I want to attach will be attached to the state property, even if I'm validating the value with a method. And then, as you can see, the error message is now applied on the state instead of on the validation method, which is much more convenient. You can, of course, create your custom validator. So what about validating the state code? Because if you fill the state, it doesn't mean that you have filled a valid state code. So if you are in the US, we have the list of all US codes, a US state code. So we have to check that. We selected, for example, CA or FL, or also TX for Texas. So as Symphony doesn't have these built-in constraints for validating a state, a US state, or a Canada province, you can create your custom validator constraints. Remember, a constraint is just a class. So I will first create the constraints class, which is, for example, North America state, which extends constraints. I want the default error message to be state code. The state code is not valid. And these constraints will be applied on a class. So it must be applied on a class. I'm forcing the target to be a class constraint. You will see why. If you use add annotation, if you write the add annotation annotation, that means this object can be used as a doctrine annotation. You can use add North America state in your code. That's the meaning of add annotation. So remember that the constraints must be associated with its corresponding validator, which performs the logic. So I'm creating a North America state validator. So it must be the name of the constraints followed by validators. This is how Symphony guesses what is the validator associated to your constraints class. So I have my list of US states and my list of Canada province. And the validate method will perform the validation logic. This is what it does. Remember that this constraint is applied on the class. I made it a class constraint, which means the value I will receive is the address object. I will not receive just the state, but I will receive the address object because I want to know the country in the address object. So I'm checking that the value is an address object. If it's an address object, I will leave the validator. I'm not supposed to validate something as an address object. Here I'm receiving the North America state constraint. So from the constraints, from the address, I will pull the country selected by the user. If the country is different than US or Canada, I don't have to validate the state. And if the country is US or Canada, then I will check that the state is a valid state in my allowed list of states. And if it's not, I will add my violation on the state property of the address object. This is fairly simple. So you can write your custom validator. So every time you have a custom logic, you can write your validator. Yep. What do you mean? You speak for the error. You mean here? Validate. I think it's an innate. Yes, you can use an interface here if you want. Yes, the instance of keyword in PHP accepts classes. So concrete classes, abstract classes, or interfaces. It's up to you to choose a type you want to check. So this is my concrete type, my address concrete type, but I could use an address interface if I want. But you can't use it as a type hint because it's, and it needs to inherit the signature of the object. Yes, yes, that's why you could use. You can create validator. Yes, you can't type in with address here because the validate method is an abstract method in the base class, which is an abstract class. So it's part of the interface. So when you implement the method, you have to respect the signature from the base class. So that's why you can't type in with address for the value. And you have to check it inside the validation. So as you can see, I'm putting the North America state constraints on my address object, on my address class. And that's all. This is how I can validate that the state in the address is a valid state in the U.S. or in Canada. You can go further with validation groups. For example, you want to validate your object depending on the context. You want to contextualize the validation of your object. Let's say for example you have a user object and the user object, when the user registered to your application, the user must feel the username and the password. But if the user edits his or her profile, then the username can't be changed. So you don't want to revalidate the username. And you want the password to be, for example, optional when you edit your profile. So depending on the context, you don't want to execute the same set of constraints. And that's the goal of validation groups in symphony. So let's say for my order, that the reference can't be changed after. After the order has been created in my database, for example, the order can't be changed. It's a unique value. So I will add a group's option, which is for example the create group. This is just a name I want to apply. So I want this constraint to be triggered only if the validator is configured to trigger the create validation group. But then the length option is also as we've added in create group and same for the regularization. So the reference property will only be validated when I'm using a create validation context. And this is how you can pass validation groups to your validator. You just give it an array of validation groups. So the default is the default one. So this string is the default validation group. So all constraints by default have this value default. So I want to execute constraints with the default validation groups plus constraints with the create validation groups. So the reference property will be validated if the validator is configured with the create validation group. You also have group sequences, which means you can validate a value, I said that you can create steps to validate your object. So you have a first step to validate a set of data, then you stop, and you have a second step to validate the other data of your object. So the group sequences allow to validate an object in multiple steps. For example, you will attach a group sequence constraints on your class. So the first group is the name of the class. So you must match the name of the class here as the default group sequence. And then we have, let's say, a chipping group sequence and a payment group sequence. So if you want to validate those information separately, you just split your validation process in steps. So for example, the reference will be validated first in the order group sequence. And if the reference is not valid, then the validation will fail and it will stop. So that means I won't validate the other steps as long as the first step is not validated completely. And same for the chipping, I will not validate the payment as long as chipping is not yet validated completely. So that's the meaning of validation of group sequences. So in fact, group sequences are just validation groups. So you just, once again, validate your object with a set of groups and then the validator uses the group sequence annotations to know in which sequences you have to validate your objects. I'm almost done with my presentation. I have a few things to show you. Class inheritance, if you have inheritance in your classes, that also works. Let's say for example, we have a complementary order which extends the base order class. So we want a free order for ordering free product or free services. So my complementary order extends the base order class. So I want to get the constraints from the base class. But I want to override the total and the VATs value to check that they are always zero as it's a complementary order. So as you are using inheritance, the validator will also execute the constraints in the base class. So it will check my lines, my building address and my delivery address and so on. And finally, translations. I showed that you can translate the error messages. So Symphony gives you lots of different kind of formats to store your translation messages. You can use XML files, actually files, which is a standard format for translations. You can use YAML files, PHP arrays. You can use get text or you can use a database storage engine. It's really up to you, Symphony has several adapters with the translator components. In this case, I choose to use an XML file to translate my validator error messages. This is my error message. So this is the key, the unique key, the identifier, which can be a constant. In this case, it's a sentence, state code is not valid. And this is the translation in French for my error message. By default, Symphony provides translations for all the default error message in several languages. So including English, French, German, Italian and so on. And in this case, I want to create my own custom validator.fr.xf file. So I will use the translator components. I need the translator components. I will register my XML file loader. And I will register this file as a translation file. And then I will pass the Symphony translator object into the validator, the Symphony validator. And automatically, all the messages will be translated with these translator objects. I know that Drupal has its own custom translation system. And as far as I seen in the code, they wrapped the Symphony translator components in their Drupal new translation components. So behind the scenes, Drupal 8 is also using the translator component of Symphony. So if I validate my object, as you can see, the error message, if I'm asking for French translations, I will have my error messages translated into French. So as a conclusion, as you can see, there are lots of things you can do with this validator component. It's very well documented in the symphony.com website. I think I gave you the overview of approximately everything you can do with this validator component. So feel free to use it. And that was easy to validate my other objects. If you have any questions, we have 10 to five minutes left. Wow. Yeah, the question was, is it interesting to decouple the translator components from the validator component, or to decouple the validator component and the translator component together to have more loose coupling between the two components? I don't think so. As I said, Symphony is a set of components. You can pick and choose the one, each component you want to use. But also Symphony is a set of components. It's an all-in-one. So for consistency, I guess it's better to have some tight coupling at some point in the framework. So I don't think it's a big deal to have a coupling between the symphony translator component and the validator component. As long as the validator component relies on an interface on the symphony translator interface, so you can create your own implementation of the translator if you want. You are not forced to use the symphony concrete implementation. So it's real. You just have to have the interface to implement. But maybe if one day the PHP FIG group provides a built-in standardized translator interface, maybe Symphony will use it for more standard implementation. But I don't think it's a big deal to have a coupling between the two components. They are consistent together. The question? Yeah, so the question is, in the collection constraints I showed you, I use the, for each line I have the reference, the quantity, the designation, and another property. So it was a limited set of information. So I know them in advance. The question is, can we validate an array which contains an infinite set of properties? The collection constraints allows you to, there's an option which allows you to add extra fields. I think I've described it somewhere. But when you use Adassert collection, you can use the allow extra fields option to true, which allows you to pass more than the fields you have set in the collection constraints. So if your array contains extra fields, they will be skipped in the validation, but the validation will not fail because you have extra fields. No, because you didn't apply any constraints on them. Let me check if there's an option to have maybe an ID, just collection. So we have, so we have the fields we want to validate, allow extra fields, and you can also allow missing fields. Now we don't have any option to configure the default constraints to execute on extra fields, or on extra fields. So maybe it could be an improvement to this constraint to add a new option, let's say, default constraints for extra fields to trigger a set of constraints when you add extra fields. Yep. Are these slides going to be available for us to download? Yes. They are already uploaded. You can get them on my speaker deck. So this is the URL, speaker deck slash HMN. There it is. So they're online. I just have to re-upload them because I've changed a little bit the presentation before the talk, but I will upload them on the same URL. So speaker deck.com slash HMN, and you have my presentations, including this one. No questions anymore? Yeah, you can use your get text loader. There's a get text. No, no, you have the translator component. So component, translator, and loader. There it is. Here are the built-in loaders in the translation component. So URL loader, CSV, ICU, INI, JSON. So MO and PO for get text, PHP file. So PHP arrays and QT and XLIF and YAML files for storing your translations. If you want to support the database engine, you have to write your own implementation. Okay, yes. Yeah, it's 2 p.m. So thank you very much.