1Exclusion Strategies 2==================== 3 4Introduction 5------------ 6The serializer supports different exclusion strategies. Each strategy allows 7you to define which properties of your objects should be serialized. 8 9General Exclusion Strategies 10---------------------------- 11If you would like to always expose, or exclude certain properties. Then, you can 12do this with the annotations ``@ExclusionPolicy``, ``@Exclude``, and ``@Expose``. 13 14The default exclusion policy is to exclude nothing. That is, all properties of the 15object will be serialized. If you only want to expose a few of the properties, 16then it is easier to change the exclusion policy, and only mark these few properties: 17 18.. code-block :: php 19 20 <?php 21 22 use JMS\Serializer\Annotation\ExclusionPolicy; 23 use JMS\Serializer\Annotation\Expose; 24 25 /** 26 * The following annotations tells the serializer to skip all properties which 27 * have not marked with @Expose. 28 * 29 * @ExclusionPolicy("all") 30 */ 31 class MyObject 32 { 33 private $foo; 34 private $bar; 35 36 /** 37 * @Expose 38 */ 39 private $name; 40 } 41 42.. note :: 43 44 A property that is excluded by ``@Exclude`` cannot be exposed anymore by any 45 of the following strategies, but is always hidden. 46 47Versioning Objects 48------------------ 49JMSSerializerBundle comes by default with a very neat feature which allows 50you to add versioning support to your objects, e.g. if you want to 51expose them via an API that is consumed by a third-party: 52 53.. code-block :: php 54 55 <?php 56 57 class VersionedObject 58 { 59 /** 60 * @Until("1.0.x") 61 */ 62 private $name; 63 64 /** 65 * @Since("1.1") 66 * @SerializedName("name") 67 */ 68 private $name2; 69 } 70 71.. note :: 72 73 ``@Until``, and ``@Since`` both accept a standardized PHP version number. 74 75If you have annotated your objects like above, you can serializing different 76versions like this:: 77 78 use JMS\Serializer\SerializationContext; 79 80 $serializer->serialize(new VersionObject(), 'json', SerializationContext::create()->setVersion(1)); 81 82 83Creating Different Views of Your Objects 84---------------------------------------- 85Another default exclusion strategy is to create different views of your objects. 86Let's say you would like to serialize your object in a different view depending 87whether it is displayed in a list view or in a details view. 88 89You can achieve that by using the ``@Groups`` annotation on your properties. Any 90property without an explicit ``@Groups`` annotation will be included in a 91``Default`` group, which can be used when specifying groups in the serialization 92context. 93 94.. code-block :: php 95 96 use JMS\Serializer\Annotation\Groups; 97 98 class BlogPost 99 { 100 /** @Groups({"list", "details"}) */ 101 private $id; 102 103 /** @Groups({"list", "details"}) */ 104 private $title; 105 106 /** @Groups({"list"}) */ 107 private $nbComments; 108 109 /** @Groups({"details"}) */ 110 private $comments; 111 112 private $createdAt; 113 } 114 115You can then tell the serializer which groups to serialize in your controller:: 116 117 use JMS\Serializer\SerializationContext; 118 119 $serializer->serialize(new BlogPost(), 'json', SerializationContext::create()->setGroups(array('list'))); 120 121 //will output $id, $title and $nbComments. 122 123 $serializer->serialize(new BlogPost(), 'json', SerializationContext::create()->setGroups(array('Default', 'list'))); 124 125 //will output $id, $title, $nbComments and $createdAt. 126 127Overriding Groups of Deeper Branches of the Graph 128~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 129In some cases you want to control more precisely what is serialized because you may have the same class at different 130depths of the object graph. 131 132For example if you have a User that has a manager and friends:: 133 134 use JMS\Serializer\Annotation\Groups; 135 136 class User 137 { 138 private $name; 139 140 /** @Groups({"manager_group"}) */ 141 private $manager; 142 143 /** @Groups({"friends_group"}) */ 144 private $friends; 145 146 public function __construct($name, User $manager = null, array $friends = null) 147 { 148 $this->name = $name; 149 $this->manager = $manager; 150 $this->friends = $friends; 151 } 152 } 153 154And the following object graph:: 155 156 $john = new User( 157 'John', 158 new User( 159 'John Manager', 160 new User('The boss'), 161 array( 162 new User('John Manager friend 1'), 163 ) 164 ), 165 array( 166 new User( 167 'John friend 1', 168 new User('John friend 1 manager') 169 ), 170 new User( 171 'John friend 2', 172 new User('John friend 2 manager') 173 ), 174 ) 175 ); 176 177You can override groups on specific paths:: 178 179 use JMS\Serializer\SerializationContext; 180 181 $context = SerializationContext::create()->setGroups(array( 182 'Default', // Serialize John's name 183 'manager_group', // Serialize John's manager 184 'friends_group', // Serialize John's friends 185 186 'manager' => array( // Override the groups for the manager of John 187 'Default', // Serialize John manager's name 188 'friends_group', // Serialize John manager's friends. If you do not override the groups for the friends, it will default to Default. 189 ), 190 191 'friends' => array( // Override the groups for the friends of John 192 'manager_group', // Serialize John friends' managers. 193 'manager' => array( // Override the groups for the John friends' manager 194 'Default', // This would be the default if you did not override the groups of the manager property. 195 ), 196 ), 197 )); 198 $serializer->serialize($john, 'json', $context); 199 200This would result in the following json:: 201 202 { 203 "name": "John", 204 "manager": { 205 "name": "John Manager", 206 "friends": [ 207 { 208 "name": "John Manager friend 1" 209 } 210 ] 211 }, 212 "friends": [ 213 { 214 "manager": { 215 "name": "John friend 1 manager" 216 }, 217 }, 218 { 219 "manager": { 220 "name": "John friend 2 manager" 221 }, 222 }, 223 ] 224 } 225 226Limiting serialization depth of some properties 227----------------------------------------------- 228You can limit the depth of what will be serialized in a property with the 229``@MaxDepth`` annotation. 230This exclusion strategy is a bit different from the others, because it will 231affect the serialized content of others classes than the one you apply the 232annotation to. 233 234.. code-block :: php 235 236 use JMS\Serializer\Annotation\MaxDepth; 237 238 class User 239 { 240 private $username; 241 242 /** @MaxDepth(1) */ 243 private $friends; 244 245 /** @MaxDepth(2) */ 246 private $posts; 247 } 248 249 class Post 250 { 251 private $title; 252 253 private $author; 254 } 255 256In this example, serializing a user, because the max depth of the ``$friends`` 257property is 1, the user friends would be serialized, but not their friends; 258and because the the max depth of the ``$posts`` property is 2, the posts would 259be serialized, and their author would also be serialized. 260 261You need to tell the serializer to take into account MaxDepth checks:: 262 263 use JMS\Serializer\SerializationContext; 264 265 $serializer->serialize($data, 'json', SerializationContext::create()->enableMaxDepthChecks()); 266 267 268Dynamic exclusion strategy 269-------------------------- 270 271If the previous exclusion strategies are not enough, is possible to use the ``ExpressionLanguageExclusionStrategy`` 272that uses the `symfony expression language`_ to 273allow a more sophisticated exclusion strategies using ``@Exclude(if="expression")`` and ``@Expose(if="expression")`` methods. 274 275 276.. code-block :: php 277 278 <?php 279 280 class MyObject 281 { 282 /** 283 * @Exclude(if="true") 284 */ 285 private $name; 286 287 /** 288 * @Expose(if="true") 289 */ 290 private $name2; 291 } 292 293.. note :: 294 295 ``true`` is just a generic expression, you can use any expression allowed by the Symfony Expression Language 296 297To enable this feature you have to set the Expression Evaluator when initializing the serializer. 298 299.. code-block :: php 300 301 <?php 302 use JMS\Serializer\Expression\ExpressionEvaluator; 303 use JMS\Serializer\Expression\SerializerBuilder; 304 use Symfony\Component\ExpressionLanguage\ExpressionLanguage; 305 306 $serializer = SerializerBuilder::create() 307 ->setExpressionEvaluator(new ExpressionEvaluator(new ExpressionLanguage())) 308 ->build(); 309 310.. _symfony expression language: https://github.com/symfony/expression-language 311 312By default the serializer exposes three variables (`object`, `context` and `property_metadata` for use in an expression. This enables you to create custom exclusion strategies similar to i.e. the `GroupExclusionStrategy`_. In the below example, `someMethod` would receive all three variables. 313 314.. code-block :: php 315 316 <?php 317 318 class MyObject 319 { 320 /** 321 * @Exclude(if="someMethod(object, context, property_metadata)") 322 */ 323 private $name; 324 325 /** 326 * @Exclude(if="someMethod(object, context, property_metadata)") 327 */ 328 private $name2; 329 } 330 331.. _GroupExclusionStrategy: https://github.com/schmittjoh/serializer/blob/master/src/Exclusion/GroupsExclusionStrategy.php 332