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>