Sometimes it may be benefical to put static data into an associative array on the file system instead of into the database. This may include some sort of configuration data which needs to be loaded every time or repeating static data, like cities, countries, regions, provinces etc. Unfortunately, in Yii there is no kind of model to access and/or manipulate this kind of data. At this time, EArrayModel comes in.
EArrayModel has been designed in such way that the structure of the class is almost exactly the same as CActiveRecord, except the specific database functionalities. It has validate, scenarios, find, save (insert/update) and delete methods, but also the overwritable events before...() and after...(). This model also allows to search the data by using conditions. To understand the main usage of this model, I'd like to refer to the tutorials about models and active record on the website of the Yii Framework.
EArrayModel (like every other yii model) also works with attributes. These attributes are linked to a single array element. You can (actually must) define which element of the array is linked to which attribute. You do this by defining the data structure via overriding the method arrayStructure() (See paragraph Creating the model class). Besides these normal attributes defined in the array structure, we also have the magic id attribute. This id attribute is always present and refers to the unique key of a data array row. This id can also be changed like every other attribute. If the changed id already exists in the data file, then the data row with that corresponding id is getting overwritten.
$model = new City; $model->name = 'Amsterdam'; $model->position_x = 205; $model->position_y = 673; $model->save();
$model = City::model()->findById(1); $model->position_x = 100; $model->position_y = 201; $model->save();
$model = City::model()->findById(1); $model->delete();
City::model()->deleteAll(); // Deletes all rows City::model()->deleteAll(/*condition*/); // Deletes all rows matched by the condition
$model = City::model()->findById(4); // Returns a single row with id 4 $model = City::model()->find(); // Returns the first found row $models = City::model()->findAll(); // Returns all rows, conditions may be used $models = City::model()->findAll(array(/*condition*/)); // Returns all rows matched by the condition $models = City::model()->findAll(array(/*condition*/), 5, 10); // Returns 5 rows matched by the condition, beginning on row number 10 (does exactly work like LIMIT in MySQL)
A condition needs to be an array and must consist of conditional statements with the structure 'attribute => value'. Every conditional statement needs to be seperated by an AND or OR operator. The condition behaves like normal IF statements in PHP and may contain the following comparison operators:
>, >=, <, <=, = (or ==), !=, ===, !==, %, !%
In addition to PHP there are two more operators, % and !%. These operators stand for respectively 'contains' and 'not contains'. It will check whether the given string can be found or not found inside the value of a specific attribute. The operator will search case insensitive.
When no comparison operator has been used, the condition will automatically function like exact matching (= or ==).
Just like in PHP, the condition can contain sub-conditions, sub-sub-conditions, and so forth. It can be realised by just adding new arrays, containing conditional statements. In this way, an endless condition can be created. Some examples:
Contact::model()->findAll(array(array('id' => 1)); // Return data with ID 1 (exact matching) Contact::model()->findAll(array(array('id >' => 5), 'AND', array('id >' => 15)); // Matches data with an ID bigger than 5 and smaller than 15 Contact::model()->findAll(array(array('name %' => 'asd'), 'OR', array('name %' => 'qwe'))); // Matches data which contains asd or qwe Contact::model()->findAll(array(array(array('first_name' => 'John'), 'OR', array('first_name' => 'Matthew')), 'AND', array('last_name' => 'Smith'))); // Matches data where the first name is John or Matthew and the last name is Smith
To make conditions a little bit more readable and shorter, you can leave out some array elements:
Normal usage:
Contact::model()->findAll(array(array('id >' => 5)));
Shorter usage
Contact::model()->findAll(array('id >' => 5));
However, with the shorter usage you can't use the same attributes inside one condition statement. With the following example, only the last attribute will be checked:
Contact::model()->findAll(array('id' => 5, 'OR', 'id' => 7)); // Only row with ID 7 will be returned
The following on the other hand will work as aspected, because of the >= and <= comparison operators.
Contact::model()->findAll(array('id >=' => 5, 'AND', 'id <=' => 7)); // All rows with ID 5, 6 and 7 will be returned
This limitation is there because the condition 'array' can't have two or more elements with the same key. The first id will be overwritten by the last defined id. In this case you still need to use the normal usage instead.
Every array model class must extend from EArrayModel and needs to override a couple of methods. The structure of this class differs from CActiveModel by the methods fileName() and arrayStructure().
Example EArrayModel class:
class RankArray extends ArrayModel { /** * Returns the static model of the specified AM class. * @return the static model class */ public static function model($className=__CLASS__) { return parent::model($className); } /** * @return string the associated array data file location (must be writable, to make use of the saving functionalities) */ public function fileName() { return 'application.data.ranks'; } /** * @return array the associated array structure ('key' => 'attribute'). The list of * available attributes will be based on this list. */ public function arrayStructure() { return array( 'name' => array( 'male' => 'name_male', 'female' => 'name_female', ), 'points' => 'points', ); } /** * @return array validation rules for model attributes. */ public function rules() { return array( array('name_male, name_female', 'length', 'max' => 20), ); } /** * @return array validation rules for model attributes. */ public function attributeLabels() { return array(); } }
The data file protected/data/ranks.php, related to the RankArray model of the previous paragraph
/** * Data file generated by RankArray (ArrayModel) * Date: June 30, 2011, 9:57 pm * * Allowed data structure: * array( * 'name' => array( * 'male' => 'name_male', * 'female' => 'name_female', * ), * 'points' => 'points', * ) */ return array( 1 => array( 'name' => array( 'male' => 'Cleaner', 'female' => 'Cleaner', ), 'points' => 5, ), 2 => array( 'name' => array( 'male' => 'Bagman', 'female' => 'Bagman', ), 'points' => 50, ), );
$model->isNew; // Checks whether the current data model is new, works exactly like isNewRecord ModelName::model()->getData(); // Returns the raw data for manual data manipulation ModelName::model()->setData($data); // Set raw data manually after manipulation ModelName::model()->flushData(); // Cleans the cached data and forces to renew the data on next data file access
In addition, I would like to thank the developers behind Yii for creating such great framework! ;-)
Total 1 comment
I am using all the functionality without adding this extension to my application except misc. I am working with all the mentioned syntax's.
Can you please explain me what exactly does this extension do.
Thanks
Leave a comment
Please login to leave your comment.