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