Utilities
Version 2 (Kien La, 2010-06-19 06:12 PM)
1 | 2 | Kien La | h2. Utilities |
---|---|---|---|
2 | 1 | ||
3 | 1 | ActiveRecord offers numerous ways to make your life easier by adding some interesting features to your models. |
|
4 | 1 | ||
5 | 1 | Delegators |
|
6 | 1 | ||
7 | 1 | This is similar to attribute aliasing, except that it works via your associations. You can alias an attribute on your model to use a particular attribute on an association. Let's take a look. |
|
8 | 1 | ||
9 | 1 | <pre class="code"><code class="php"> |
|
10 | 1 | class Person extends ActiveRecord\Model { |
|
11 | 1 | static $belongs_to = array(array('venue'),array('host')); |
|
12 | 1 | static $delegate = array( |
|
13 | 1 | array('name', 'state', 'to' => 'venue'), |
|
14 | 1 | array('name', 'to' => 'host', 'prefix' => 'host')); |
|
15 | 1 | } |
|
16 | 1 | ||
17 | 1 | $person = Person::first(); |
|
18 | 1 | $person->state # same as calling $person->venue->state |
|
19 | 1 | $person->name # same as calling $person->venue->name |
|
20 | 1 | $person->host_name # same as calling $person->host->name |
|
21 | 1 | </code></pre> |
|
22 | 1 | ||
23 | 1 | Attribute setters |
|
24 | 1 | ||
25 | 1 | Setters allow you to define custom methods for assigning a value to one of your attributes. This means you can intercept the assign process and filter/modify the data to your needs. This is helpful in a situation such as encrypting user passwords. Normally, you define a setter which does not carry the same name as your attribute, but you can set your attribute inside of the method. In the example below, $user->password is a virtual attribute: if you try to read/access the attribute instead of assign, an UndefinedPropertyException will be thrown. |
|
26 | 1 | ||
27 | 1 | <pre class="code"><code class="php"> |
|
28 | 1 | class User extends ActiveRecord\Model { |
|
29 | 1 | static $setters = array('password','second_custom_setter'); |
|
30 | 1 | ||
31 | 1 | # A setter method must have set_ prepended to its name to qualify. |
|
32 | 1 | # $this->encrypted_password is the actual attribute for this model. |
|
33 | 1 | public function set_password($plaintext) { |
|
34 | 1 | $this->encrypted_password = md5($plaintext); |
|
35 | 1 | } |
|
36 | 1 | } |
|
37 | 1 | ||
38 | 1 | $user = new User; |
|
39 | 1 | $user->password = 'plaintext'; # will call $user->set_password('plaintext') |
|
40 | 1 | # if you did an echo $user->password you would get an UndefinedPropertyException |
|
41 | 1 | </code></pre> |
|
42 | 1 | ||
43 | 1 | If you define a custom setter with the same name as an attribute then you will need to use assign_attribute() to assign the value to the attribute. This is necessary due to the way Model::__set() works. For example, assume 'name' is a field on the table and we're defining a custom setter called 'name': |
|
44 | 1 | ||
45 | 1 | <pre class="code"><code class="php"> |
|
46 | 1 | class User extends ActiveRecord\Model { |
|
47 | 1 | static $setters = array('name'); |
|
48 | 1 | ||
49 | 1 | # INCORRECT: |
|
50 | 1 | # function set_name($name) { |
|
51 | 1 | # $this->name = strtoupper($name); |
|
52 | 1 | # } |
|
53 | 1 | ||
54 | 1 | public function set_name($name) { |
|
55 | 1 | $this->assign_attribute('name',strtoupper($name)); |
|
56 | 1 | } |
|
57 | 1 | } |
|
58 | 1 | ||
59 | 1 | $user = new User; |
|
60 | 1 | $user->name = 'bob'; |
|
61 | 1 | echo $user->name; # => BOB |
|
62 | 1 | </code></pre> |
|
63 | 1 | ||
64 | 1 | Aliased attributes |
|
65 | 1 | ||
66 | 1 | This option is fairly straight-forward. An aliased attribute allows you to set/get the attribute via a different name. This comes in handy when you have terrible field names like field_one, field_two, or for legacy tables. |
|
67 | 1 | ||
68 | 1 | <pre class="code"><code class="php"> |
|
69 | 1 | class Person extends ActiveRecord\Model { |
|
70 | 1 | static $alias_attribute = array( |
|
71 | 1 | 'first_name' => 'person_first_name', |
|
72 | 1 | 'last_name' => 'person_last_name'); |
|
73 | 1 | } |
|
74 | 1 | ||
75 | 1 | $person = Person::first(); |
|
76 | 1 | echo $person->person_first_name; # => Jax |
|
77 | 1 | ||
78 | 1 | $person->first_name = 'Tito'; |
|
79 | 1 | echo $person->first_name; # => Tito |
|
80 | 1 | echo $person->person_first_name; # => Tito |
|
81 | 1 | </code></pre> |
|
82 | 1 | ||
83 | 1 | Protected attributes |
|
84 | 1 | ||
85 | 1 | Blacklist of attributes that cannot be mass-assigned. Protecting these attributes allows you to avoid security problems where a malicious user may try to create additional post values. This is the opposite of accessible attributes. |
|
86 | 1 | ||
87 | 1 | <pre class="code"><code class="php"> |
|
88 | 1 | class User extends ActiveRecord\Model { |
|
89 | 1 | static $attr_protected = array('admin'); |
|
90 | 1 | } |
|
91 | 1 | ||
92 | 1 | $attributes = array('first_name' => 'Tito','admin' => 1); |
|
93 | 1 | $user = new User($attributes); |
|
94 | 1 | ||
95 | 1 | echo $user->first_name; # => Tito |
|
96 | 1 | echo $user->admin; # => null |
|
97 | 1 | # now no one can fake post values and make themselves an admin against your will! |
|
98 | 1 | </code></pre> |
|
99 | 1 | ||
100 | 1 | Accessible attributes |
|
101 | 1 | ||
102 | 1 | Whitelist of attributes that are checked from mass-assignment calls such as constructing a model or using Model::update_attributes(). This is the opposite of protected attributes. Accessible attributes can also be used as a security measure against fake post values, except that it is often more pragmatic because it is a whitelist approach. |
|
103 | 1 | ||
104 | 1 | <pre class="code"><code class="php"> |
|
105 | 1 | class User extends ActiveRecord\Model { |
|
106 | 1 | static $attr_accessible = array('first_name'); |
|
107 | 1 | } |
|
108 | 1 | ||
109 | 1 | $attributes = array('first_name' => 'Tito','last_name' => 'J.','admin' => 1); |
|
110 | 1 | $user = new User($attributes); |
|
111 | 1 | ||
112 | 1 | echo $person->last_name; # => null |
|
113 | 1 | echo $person->admin; # => null |
|
114 | 1 | echo $person->first_name; # => Tito |
|
115 | 1 | # first_name is the only attribute that can be mass-assigned, so the other 2 are null |
|
116 | 1 | </code></pre> |
|
117 | 1 | ||
118 | 1 | Serialization |
|
119 | 1 | ||
120 | 1 | This is not the normal kind of PHP serialization you are used to. This will not serialize your entire object; however, it will serialize the attributes of your model to either an xml or a json representation. An options array can take the following parameters: |
|
121 | 1 | ||
122 | 1 | only: a string or array of attributes to be included. |
|
123 | 1 | exclude: a string or array of attributes to be excluded. |
|
124 | 1 | methods: a string or array of methods to invoke. The method's name will be used as a key for the final attributes array along with the method's returned value |
|
125 | 1 | include: a string or array of associated models to include in the final serialized product. |
|
126 | 1 | skip_instruct: set to true to skip the <?xml ...?> declaration. |
|
127 | 1 | Below only includes Model::to_json() examples; however, you can use all of the examples with Model::to_xml() |
|
128 | 1 | ||
129 | 1 | <pre class="code"><code class="php"> |
|
130 | 1 | class User extends ActiveRecord\Model { |
|
131 | 1 | static $has_many = array(array('orders')); |
|
132 | 1 | ||
133 | 1 | public function name() { |
|
134 | 1 | return $this->first_name .' '. $this->last_name; |
|
135 | 1 | } |
|
136 | 1 | } |
|
137 | 1 | ||
138 | 1 | # assume these fields are on our `users` table: |
|
139 | 1 | # id, first_name, last_name, email, social_security, phone_number |
|
140 | 1 | ||
141 | 1 | $user = User::first(); |
|
142 | 1 | ||
143 | 1 | # json should only contain id and email |
|
144 | 1 | $json = $user->to_json(array( |
|
145 | 1 | 'only' => array('id', 'email') |
|
146 | 1 | )); |
|
147 | 1 | ||
148 | 1 | echo $json; # => {"id":1,"email":"[email protected]"} |
|
149 | 1 | ||
150 | 1 | # limit via exclusion (here we use a string, but an array can be passed) |
|
151 | 1 | $json = $user->to_json(array( |
|
152 | 1 | 'except' => 'social_security' |
|
153 | 1 | )); |
|
154 | 1 | ||
155 | 1 | echo $json; # => {"id":1,"first_name":"George","last_name":"Bush", |
|
156 | 1 | # "email":"[email protected]","phone_number":"555-5555"} |
|
157 | 1 | ||
158 | 1 | # call $user->name() and the returned value will be in our json |
|
159 | 1 | $json = $user->to_json(array( |
|
160 | 1 | 'only' => array('email', 'name'), |
|
161 | 1 | 'methods' => 'name' |
|
162 | 1 | )); |
|
163 | 1 | ||
164 | 1 | echo $json; # => {"name":"George Bush","email":"[email protected]"} |
|
165 | 1 | ||
166 | 1 | # call $user->name() and the returned value will be in our json |
|
167 | 1 | $json = $user->to_json(array( |
|
168 | 1 | 'only' => array('email', 'name'), |
|
169 | 1 | 'methods' => 'name' |
|
170 | 1 | )); |
|
171 | 1 | ||
172 | 1 | # include the orders association |
|
173 | 1 | $json = $user->to_json(array( |
|
174 | 1 | 'include' => array('orders') |
|
175 | 1 | )); |
|
176 | 1 | ||
177 | 1 | # you can nest includes .. here orders also has a payments association |
|
178 | 1 | $json = $user->to_json(array( |
|
179 | 1 | 'include' => array('orders' => array('except' => 'id', 'include' => 'payments') |
|
180 | 1 | )); |
|
181 | 1 | </code></pre> |
|
182 | 1 | ||
183 | 1 | DateTime fields are serialized to ISO8601 format by default. If you need to change this call the set_date_format() method in your configuration block. |
|
184 | 1 | ||
185 | 1 | <pre class="code"><code class="php"> |
|
186 | 1 | ActiveRecord\Config::initialize(function($cfg) |
|
187 | 1 | { |
|
188 | 1 | # set the date format for serialization |
|
189 | 1 | $cfg->set_date_format('Y-m-d H:i:s'); |
|
190 | 1 | ||
191 | 1 | # your other configuration stuff |
|
192 | 1 | ... |
|
193 | 1 | }); |
|
194 | 1 | </code></pre> |