Skip to content

Commit 7cabc1b

Browse files
committed
Problem file
1 parent 8039260 commit 7cabc1b

File tree

1 file changed

+143
-0
lines changed
  • exercises/the-attributes-of-success/problem

1 file changed

+143
-0
lines changed
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
You have been given a few pieces of code (look for `attributes.php`, `deserialize.php` & `the-attributes-of-success.php` in your working directory).
2+
3+
Your entry point is `the-attributes-of-success.php`. This is the file you should edit and work on. The other files should not be modified. However, they are included by `the-attributes-of-success.php`.
4+
5+
You can run and verify your program like so:
6+
7+
```sh
8+
$ {appname} run the-attributes-of-success.php
9+
$ {appname} verify the-attributes-of-success.php
10+
```
11+
12+
Your task is split into two sections. The overall task is to write a class using properties and attributes which describe how to map data to an instance of the class.
13+
14+
The data will be passed to you in a JSON encoded string via the first command line argument.
15+
16+
The data will represent a product review.
17+
18+
You pass the `JSON` data and the name of your class to a function named `deserialize` which is provided to you in the file `deserialize.php`. For reference, its signature is:
19+
20+
```php
21+
function deserialize(string $data, string $className): object;
22+
```
23+
24+
It will return to you an instance of `$className` with the data from the `JSON` string `$data` mapped to its properties.
25+
26+
You should dump out the object using `var_dump`.
27+
28+
### Task 1 - Annotate a class with existing attributes
29+
30+
Create a class named `Review` with five public properties which represent the data of the review. The properties should all be `string` types and should be named `comment`, `starRating`, `date`, `id` and `reviewer`.
31+
32+
The class should use the Attribute `Deserialize` so that our `deserialize` function knows that this is a valid class to use.
33+
34+
By default, our `deserialize` function will use the names of the class properties to locate the field value in the `JSON` data.
35+
36+
For example, when passing the following class to our `deserialise` function it would look for the `sku` key in the `JSON` data and set it on the `sku` property.
37+
38+
```php
39+
#[Deserialize]
40+
class Product {
41+
public string $sku;
42+
}
43+
```
44+
45+
#### Mapping properties
46+
47+
However, the `starRating` key does not exist in the `JSON` data. It exists as `rating`. So here, we need to use the `Map` attribute. By using the `Map` attribute we can tell our `deserialize` function to fetch the star rating from a different key in the `JSON` data.
48+
49+
Use it like so:
50+
51+
```php
52+
#[Deserialize]
53+
class Product {
54+
#[Map('reference')]
55+
public string $sku;
56+
}
57+
```
58+
59+
Where `reference` is the key in the `JSON` data you want to use rather than `sku`.
60+
61+
#### Skipping properties
62+
63+
We don't care about the ID value, this relates to a 3rd party system and is not relevant in our code.
64+
65+
Use the `Skip` attribute on the `id` property of our `Review` class to tell our `deserialize` function to skip this piece of data.
66+
67+
### Task 2 - Create your own attribute
68+
69+
By now you should be able to call the `deserialize` function with the `JSON` data and your class name.
70+
71+
When executing your program with
72+
73+
```sh
74+
$ {appname} run the-attributes-of-success.php
75+
```
76+
77+
You should see a dump of your `Review` instance.
78+
79+
Here comes our problem: The reviewers name is not anonymous. We have to comply with strict privacy laws, we cannot display this data without the reviewer's permission.
80+
81+
For now, we will have to obfuscate this data. We can accomplish this using a custom attribute.
82+
83+
#### Create the obfuscate method
84+
85+
Create a method on your `Review` class named `obfuscateReviewer`. It should take a string input, run it through the `md5` function and return it.
86+
87+
#### Create an attribute
88+
89+
Create an attribute named `Obfuscate`. It should have a public property named `key` and it's constructor should assign the first passed in string value to this property.
90+
91+
The attribute must be designated as an attribute by using the `Attribute` attribute (confused much??) and it should target methods only.
92+
93+
Targets designate where an attribute can be used, on classes, methods or properties and so on. For reference, the `Deserialize` attribute can only be used on classes and hence its target is `Attribute::TARGET_CLASS`.
94+
95+
See below for an example of designating a class as an attribute and configuring its target as classes only.
96+
97+
```php
98+
#[Attribute(Attribute::TARGET_CLASS)] //This is how we designate `MyAttribute` as an attribute with its target.
99+
class MyAttribute {
100+
public function __construct(string $someValue) {
101+
}
102+
}
103+
```
104+
105+
#### Use the attribute
106+
107+
The last step is to use the attribute on your `obfuscateReviewer` method. We need to tell our `deserialize` function that this method should be called when accessing the `reviewer` key from the `JSON` data.
108+
109+
Use the `Obfuscate` attribute on the method and pass to it the name of the key in the `JSON` data we want the obfuscator to run over, which is the `reviewer` key.
110+
111+
When the `deserialize` function sees a method with the `Obfuscate` attribute it will use the key found in the public property named `key` of the attribute. It will find the value referenced by that key in the `JSON` data and pass it to the obfuscator method.
112+
113+
Finally, the returned data will be set on the `Review` object instance.
114+
115+
### Dump your object
116+
117+
The last task is to dump your object instance out using the PHP function `var_dump` - we use this output to verify the structure and data in your `Review` instance.
118+
119+
### The advantages of Attributes
120+
121+
* Add Metadata to classes, methods, properties and arguments and so on
122+
* They can replace PHP doc blocks, each with custom parsers and rules to a unified standard supported by PHP
123+
* The data can be introspected using PHP's Reflection API's
124+
* PHP Core and extensions can provide new behaviour and runtime configuration which is opt-in, such as conditionally declaring functions, deprecating features and so on
125+
126+
----------------------------------------------------------------------
127+
## HINTS
128+
129+
Documentation on the Attributes feature can be found by pointing your browser here:
130+
[https://www.php.net/manual/en/language.attributes.overview.php]()
131+
132+
Remember, do not edit `attributes.php` or `deserialize.php` - verification will fail if you do. Feel free to read the files to get a better understanding of the deserialization process.
133+
134+
You must call the `deserialize` function and you must use the `var_dump` function to output your deserialized object.
135+
136+
If you want to see the `JSON` data - use `var_dump` to dump it out.
137+
138+
139+
## Extra
140+
141+
If you're not sure how to access command line arguments - you should maybe try a different workshop which covers that topic. Try `learnyouphp`.
142+
143+
`json_decode` can fail if it is passed a malformed string. Wrap the decode in a `try\catch` statement and pass the `JSON_THROW_ON_ERROR` flag to `json_decode`'s fourth parameter.

0 commit comments

Comments
 (0)