Home  >  Article  >  Backend Development  >  CakePHP 2.x CookBook Chinese Version Chapter 7 Model - Saving Data_PHP Tutorial

CakePHP 2.x CookBook Chinese Version Chapter 7 Model - Saving Data_PHP Tutorial

WBOY
WBOYOriginal
2016-07-14 10:08:40939browse

save data

CakePHP will take a snapshot of the saved model data. The data to be saved is passed to the save() method of the model using the following basic format:
1 Array
2 (
3 [ModelName] => Array
4 (
5 [fieldname1] => 'value'
6 [fieldname2] => 'value'
7 )
8 )
Most of the time you don't need to worry about this format: CakePHP's FormHelper and the model's find method package all data in this format. If using other helpers, the data is also conveniently available in the form $this->request->data.
Here is an example of a controller action that uses the CakePHP model to store data into a database table:
1 public function edit($id) {
2 // Is there any form data being POST?
3 if ($this->request->is('post')) {
4 // If the form data can pass the verification and be saved...
5 if ($this->Recipe->save($this->request->data)) {
6                                                                                   // Set session jump information and jump
7               $this->Session->setFlash('Recipe Saved!');
8 $this->redirect('/recipes');
9 }
10 }
11
12 // If there is no form data, find the edited recipe and assign it to the view.
13 $this->set('recipe', $this->Recipe->findById($id));
14}
When the save method is called, the data passed to it in the first parameter is verified by the CakePHP verification mechanism (see the Data Verification section for more information). If for some reason the data is not saved, check to see if it does not comply with certain validation rules. You can debug this situation by outputting Model::$validationErrors.
1 if ($this->Recipe->save($this->request->data)) {
2 // Processing logic after "save" is successful
3}
4 debug($this->Recipe->validationErrors);
Some other useful model methods related to saving:
Model::set($one, $two = null)
Model::set() can be used to place one or more columns of data into the model's data array. Useful when using a model with the ActiveRecord attribute provided by Model:
1 $this->Post->read(null, 1);
2 $this->Post->set('title', 'New title for the article');
3 $this->Post->save();
This example shows how to update and save a single column using ActiveRecord's set() method. You can also use set() to assign new values ​​to multiple columns:
1 $this->Post->read(null, 1);
2 $this->Post->set(array(
3 'title' => 'New title',
4 'published' => false
5 ));
6 $this->Post->save();
The above example will update title and published columns and save them to the database.
Model::save(array $data = null, boolean $validate =true, array $fieldList = array())
This method saves data in array format. The second parameter allows to skip validation and the third parameter allows to provide a list of columns of the model to be saved. For added security, you can use $fieldList to limit the columns to be saved.
Annotations
If $fieldList is not provided, a malicious user can add additional columns to the form data (when you are not using SecurityComponent), and in this way change columns that cannot be changed.
The
save method also has an alternative syntax:
1 save(array $data = null, array $params = array())
The $params array can have the following options as its keys:
validate is set to true/false to allow/disable verification.
fieldList allows an array of columns to be saved.
callbacks Set to false to disable callbacks. Using 'before' or 'after' will only allow the specified callback.
More information about model callbacks can be found here
Tips
If you don't want the update column to be updated when saving some data, add 'updated' => false in the $data array.
Once saved, the object's ID can be obtained using the model object's $id property - which can be useful when creating new objects.
1 $this->Ingredient->save($newData);
2 $newIngredientId = $this->Ingredient->id;
Creation or update is controlled through the id column of the model. If $Model->id is set, records with this primary key will be updated. Otherwise, a new record is created:
1 // Create new record: id is not set or set to null
2 $this->Recipe->create();
3 $this->Recipe->save($this->request->data);
4
5 //Update record: id is set to a numeric value
6 $this->Recipe->id = 2;
7 $this->Recipe->save($this->request->data);
Tips
Don’t forget to call create() when calling save in a loop.
If you want to update a value rather than create a new record, you must ensure that the primary key column is passed to the data array:
1 $data = array('id' => 10, 'title' => 'My new title');
2 // Will update the Recipe record with id 10
3 $this->Recipe->save($data);
Model::create(array $data = array())
This method resets the model's state to save new information. It doesn't actually create a new record in the database, but clears the preset Model::$id and sets a default value in Model::$data based on the database column default.
If the $data parameter is passed (using the array format described above), the model instance will be prepared to save this data (using $this->data).
If false is passed to this method instead of an array, the model will not actually initialize the columns according to the model structure that has not been set before, but will only reset the columns that have been set, and leave the unset columns. This is done to avoid updating the value of a column that is already set in the database.
Tips
If you want to insert a new row instead of updating an existing row, you must first call create(). This avoids conflicts with saves that have been called in callbacks or elsewhere.
Model::saveField(string $fieldName, string$fieldValue, $validate = false)
Used to save the value of a single column. Before using saveField(), set the model ID ($this->ModelName->id = $id). When using this method, $fieldName only needs to contain the column name, not the model name and column.
For example, to update the title of a blog, you can call saveField in the controller as follows:
1 $this->Post->saveField('title', 'A New Title for a New Day');
Warning
You cannot stop updating columns when updating using this method, you need to use the save() method.
The
saveField method also has an alternative syntax:
1 saveField(string $fieldName, string $fieldValue, array $params = array())
The $params array can have the following options as its keys:
validate is set to true/false to allow/disable verification.
callbacks Set to false to disable callbacks. Using 'before' or 'after' will only allow the specified callback.
Model::updateAll(array $fields, array $conditions)
Update one or more records in one call. The records to be updated are identified by the $conditions array, and the columns and values ​​specified by the $fields parameter are updated.
For example, to approve all bakers who have been members for more than one year, call the following update statement:
1 $this_year = date('Y-m-d h:i:s', strtotime('-1 year'));
2
3 $this->Baker->updateAll(
4 array('Baker.approved' => true),
5 array('Baker.created <=' => $this_year)
6 );
Tips
The $fields array accepts SQL expressions. Literals are quoted manually using Sanitize::escape().
Annotations
Even if the edit column present in the column is updated, it will not be automatically updated via the ORM. You must manually add it to the array you want to update.
For example, to close all tickets belonging to a specified customer:
1 $this->Ticket->updateAll(
2 array('Ticket.status' => "'closed'"),
3 array('Ticket.customer_id' => 453)
4 );
By default, updateAll() will automatically connect belongsTo associations of databases that support join. This connection can be prevented by temporarily binding the association.
Model::saveMany(array $data = null, array $options= array())
This method is used to save multiple rows of the same model at the same time. Can have the following options:
validate: Set to false to disable validation, set to true to validate each record before saving, set to 'first' (this is the default) to check all records before any one is saved.
atomic: If true (default), all records will be saved in a single instruction. If the database/table does not support a single instruction, it needs to be set to false.
fieldList: Same as the $fieldList parameter of the Model::save() method.
deep: (since version 2.1) If set to true, associated data is also saved, see saveAssociated.
To save multiple records for a single model, $data needs to be a numerically indexed record array:
1 $data = array(
2 array('title' => 'title 1'),
3 array('title' => 'title 2'),
4 );
Annotations
We pass the numeric index instead of the Article key that $data would normally contain. When saving multiple records of the same model, the record array needs to be indexed using numbers rather than the keys of the model.
It can also accept data in the following format:
1 $data = array(
2 array('Article' => array('title' => 'title 1')),
3 array('Article' => array('title' => 'title 2')),
4 );
If you were also saving associated data with $options['deep'] = true, the two examples above would look like the following code:
1 $data = array(
2 array('title' => 'title 1', 'Assoc' => array('field' => 'value')),
3 array('title' => 'title 2'),
4 );
5 $data = array(
6 array('Article' => array('title' => 'title 1'), 'Assoc' => array('field' => 'value')),
7 array('Article' => array('title' => 'title 2')),
8 );
9 $Model->saveMany($data, array('deep' => true));
Remember, if you want to update records instead of creating new records, you need to add a primary key index to the data row:
1 $data = array(
2 array('Article' => array('title' => 'New article')), // Create a new record
3 array('Article' => array('id' => 2, 'title' => 'title 2')), // Update existing records
4 );
Model::saveAssociated(array $data = null, array$options = array())
This method is used to save multiple model associations at once. Can have the following options:
validate: Set to false to disable validation, set to true to validate each record before saving, set to 'first' (this is the default) to check all records before any one is saved.
atomic: If true (default), all records will be saved in a single instruction. If the database/table does not support a single instruction, it needs to be set to false.
fieldList: Same as the $fieldList parameter of the Model::save() method.
deep: (since version 2.1) If set to true, associated data is also saved, see saveAssociated.
In order to save records while also saving records that have hasOne or belongsTo relationships with them, the data array looks like the following:
1 $data = array(
2 'User' => array('username' => 'billy'),
3 'Profile' => array('sex' => 'Male', 'occupation' => 'Programmer'),
4 );
In order to save records while also saving records that have hasMany associated with them, the data array looks like the following:
1 $data = array(
2 'Article' => array('title' => 'My first article'),
3 'Comment' => array(
4 array('body' => 'Comment 1', 'user_id' => 1),
5 array('body' => 'Comment 2', 'user_id' => 12),
6 array('body' => 'Comment 3', 'user_id' => 40),
7 ),
8 );
In order to save records while also saving records that have a hasMany associated with them that are more than two levels deep, the data array looks like this:
1 $data = array(
2 'User' => array('email' => 'john-doe@cakephp.org'),
3 'Cart' => array(
4 array(
5             'payment_status_id' => 2,
6           'total_cost' => 250,
7             'CartItem' => array(
8           array(
9                   'cart_product_id' => 3,
10                     'quantity' => 1,
11                   'cost' => 100,
12 ),
13 array(
14                     'cart_product_id' => 5,
15                     'quantity' => 1,
16                   'cost' => 150,
17 )
18 )
19 )
20 )
21 );
Annotations
If the save is successful, the foreign key of the main model will be stored in the id column of the related model, such as $this->RelatedModel->id.
Warning
Be careful when calling the saveAssociated method with the atomic option set to false. It returns an array, not a logical value.
Changed in version 2.1: You can now save data from deep associations (set with $options['deep'] = true).
In order to save records while also saving related records with hasMany association and deeply associated Comment belongsTo User data, the data array looks like the following: :
1 $data = array(
2 'Article' => array('title' => 'My first article'),
3 'Comment' => array(
4 array('body' => 'Comment 1', 'user_id' => 1),
5 array('body' => 'Save a new user as well', 'User' => array('first' => 'mad', 'last' => 'coder')) ,
6 ),
7 );
And save it with the following statement:
1 $Article->saveAssociated($data, array('deep' => true));
Changed in version 2.1: Model::saveAll() and family methods now support passing fieldList for multiple models.
Example of passing fieldList to multiple models:
1 $this->SomeModel->saveAll($data, array(
2 'fieldList' => array(
3 'SomeModel' => array('field_1'),
4 'AssociatedModel' => array('field_2', 'field_3')
5 )
6 ));
fieldList is an array with model aliases as keys and arrays of columns as values. Model names are used as in the saved data and cannot be nested.
Model::saveAll(array $data = null, array $options =array())
The saveAll function is just a wrapper around the savaMany and saveAssociated methods. It examines the data and decides which type of data saving to perform. It looks at the data and decides what type of save to perform. If the data is a numerically indexed array, saveMany is called, otherwise saveAssociated is called.
This function has the same options as the previous two functions and is backwards compatible. It is recommended to use saveMany or saveAssociated according to the actual situation.
Save related model data (hasOne, hasMany, belongsTo)
When working with associated models, you must realize that the saving of model data is always done by the corresponding CakePHP model. If you save a new Post and its associated Comment, you need to use both the Post and Comment models during the save operation.
If there is no associated model record in the system (for example, if you want to save a new User and save the related Profile record at the same time), you need to save the main model or parent model first.
To understand how this works, imagine we have an action in a controller that handles saving the new User and associated Profile. The following example action assumes that sufficient data has been POSTed (using FormHelper) to create a single User and a single Profile:
1 public function add() {
2 if (!empty($this->request->data)) {
3 // We can save User data:
4 // It is placed in $this->request->data['User']
5
6 $user = $this->User->save($this->request->data);
7
8 // If the user is saved, add this information to the data and save the Profile.
9
10 if (!empty($user)) {
11                                               // The newly created User ID has been assigned to $this->User->id.
12 $this->request->data['Profile']['user_id'] = $this->User->id;
13
14                                                                             // Since User hasOne Profile, the Profile model can be accessed through the User model:
15 $this->User->Profile->save($this->request->data);
16 }
17 }
18}
As a rule, when it comes to associations with hasOne, hasMany, belongsTo, it's all about the key. The basic idea is to get the key from one model and put it into a foreign key column in another model. Sometimes this involves using the $id attribute of the saved model class, but other times it just involves the ID obtained from the hidden input of the form that POSTs to the controller action.
As a supplement to the above basic methods, CakePHP also provides a very useful method saveAssociated(), which allows you to checksum save multiple models in a short way. In addition, saveAssociated() also provides transaction support to ensure the integrity of the data in the database (for example, if one model fails to save, the other model will not be saved).
Annotations
For transactions to work properly in MySQL, the table must use the InnoDB engine. Remember, MyISAM tables do not support transactions.
Let’s see how to use saveAssociated() to save the Company and Account models at the same time.
First, you need to create forms for both Company and Account (assuming Company hasMany Account):
1 echo $this->Form->create('Company', array('action' => 'add'));
2 echo $this->Form->input('Company.name', array('label' => 'Company name'));
3 echo $this->Form->input('Company.description');
4 echo $this->Form->input('Company.location');
5
6 echo $this->Form->input('Account.0.name', array('label' => 'Account name'));
7 echo $this->Form->input('Account.0.username');
8 echo $this->Form->input('Account.0.email');
9
10 echo $this->Form->end('Add');
Look at how to name form columns for the Acount model. If Company is the main model, saveAssociated() expects the associated model (Account) data to be put into the array in the specified format. And has Account.0.fieldName which we need.
Annotations
The column naming above is required for hasMany relationships. If the association is hasOne, you have to use ModelName.fieldName for the associated model.
Now, you can create the add() action in CompaniesController:
1 public function add() {
2 if (!empty($this->request->data)) {
3 // Use the following methods to avoid verification errors:
4 unset($this->Company->Account->validate['company_id']);
5 $this->Company->saveAssociated($this->request->data);
6 }
7}
That’s all the steps. Now the Company and Account models will be verified and saved at the same time. By default, saveAssociated will check all values ​​passed in and then attempt to perform each save.
Save data via hasMany
Let’s take a look at how the data of the two models existing in the join table is saved. As shown in the hasMany Through (Joining Models) section, the join table is associated with each model using a hasMany type of relationship. Our example included the director of Cake School asking us to write a program that would allow it to record the number of days and grade a student had attended in a certain class. Here is the sample code:
1 // Controller/CourseMembershipController.php
2 class CourseMembershipsController extends AppController {
3 public $uses = array('CourseMembership');
4
5 public function index() {
6 $this->set('courseMembershipsList', $this->CourseMembership->find('all'));
7 }
8
9 public function add() {
10 if ($this->request->is('post')) {
11 if ($this->CourseMembership->saveAssociated($this->request->data)) {
12 $this->redirect(array('action' => 'index'));
13 } }
14 }
15 }
16}
17
18 // View/CourseMemberships/add.ctp
19
20 Form->create('CourseMembership'); ?>
21 Form->input('Student.first_name'); ?>
22 Form->input('Student.last_name'); ?>
23 Form->input('Course.name'); ?>
24 Form->input('CourseMembership.days_attended'); ?>
25 Form->input('CourseMembership.grade'); ?>
26
27 Form->end(); ?>
The submitted data array is as follows:
1 Array
2 (
3 [Student] => Array
4 (
5 [first_name] => Joe
6 [last_name] => Bloggs
7 )
8
9 [Course] => Array
10 (
11 [name] => Cake
12 )
13
14 [CourseMembership] => Array
15 (
16 [days_attended] => 5
17 [grade] => A
18 )
19
20 )
Cake will happily save many at once using a single saveAssociated call with this data structure, and assign the Student and Course foreign keys to CouseMembership. If we run the index action on the CourseMembershipsController, from find('all' ) is as follows:
1 Array
2 (
3 [0] => Array
4 (
5 [CourseMembership] => Array
6 (
7           [id] => 1
8             [student_id] => 1
9               [course_id] => 1
10 [days_attended] => 5
11 [grade] => A
12 )
13
14 [Student] => Array
15 (
16 [id] => 1
17 [first_name] => Joe
18 [last_name] => Bloggs
19 )
20
21 [Course] => Array
22 (
23 [id] => 1
24 [name] => Cake
25 )
26 )
27 )
Of course, there are many ways to work with connected models. The version above assumes you want to save everything immediately. There are also cases where you want to create Student and Course independently and later specify their association with CourseMembership. So you might have a form that allows selection of existing students and courses using a list or ID and two CourseMembership meta columns, for example:
1 // View/CourseMemberships/add.ctp
2
3 Form->create('CourseMembership'); ?>
4 Form->input('Student.id', array('type' => 'text', 'label' => 'Student ID', ' default' => 1)); ?>
5 Form->input('Course.id', array('type' => 'text', 'label' => 'Course ID', ' default' => 1)); ?>
6 Form->input('CourseMembership.days_attended'); ?>
7 Form->input('CourseMembership.grade'); ?>
8
9 Form->end(); ?>
Resulting POST data:
1 Array
2 (
3 [Student] => Array
4 (
5 [id] => 1
6 )
7
8 [Course] => Array
9 (
10 [id] => 1
11 )
12
13 [CourseMembership] => Array
14 (
15 [days_attended] => 10
16 [grade] => 5
17 )
18 )
Cake uses saveAssociated to push the Student id and Course id into CourseMembership.
Save related model data (HABTM)
Saving related models through hasOne, belongsTo, and hasMany is very simple: just fill in the ID of the related model into the foreign key column. After filling it out, just call the save() method on the model and everything will be connected correctly. Here is an example of the format of the data array to be passed to the save() method of the Tag model:
1 Array
2 (
3 [Recipe] => Array
4 (
5           [id] => 42
6 )
7 [Tag] => Array
8 (
9           [name] => Italian
10 )
11 )
You can also use this format in saveAll() to save multiple records and models associated with them with HABTM. The format is as follows:
1 Array
2 (
3 [0] => Array
4 (
5             [Recipe] => Array
6         (
7                 [id] => 42
8         )
 9             [Tag] => Array
10                 (
11                     [name] => Italian
12                 )
13         )
14     [1] => Array
15         (
16             [Recipe] => Array
17                 (
18                     [id] => 42
19                 )
20             [Tag] => Array
21                 (
22                     [name] => Pasta
23                 )
24         )
25     [2] => Array
26         (
27             [Recipe] => Array
28                 (
29                     [id] => 51
30                 )
31             [Tag] => Array
32                 (
33                     [name] => Mexican
34                 )
35         )
36     [3] => Array
37         (
38             [Recipe] => Array
39                 (
40                     [id] => 17
41                 )
42             [Tag] => Array
43                 (
44                     [name] => American (new)
45                 )
46         )
47 )
将上面的数组传递给 saveAll() 将创建所包含的 tag ,每个都与它们各自的 recipe 关联。
 
作为示例,我们建立了创建新 tag 和运行期间生成与 recipe 关联的正确数据数组的表单。
 
这个简单的表单如下:(我们假定 $recipe_id 已经设置了):
 
1 Form->create('Tag'); ?>
2 Form->input(
3         'Recipe.id',
4         array('type' => 'hidden', 'value' => $recipe_id)
5     ); ?>
6 Form->input('Tag.name'); ?>
7 Form->end('Add Tag'); ?>
在这个例子中,你能看到 Recipe.id hidden 域,其值被设置为我们的 tag 想要连接的 recipe 的 ID。
 
当在控制器中调用 save() 方法,它将自动将 HABTM 数据保存到数据库:
 
1 public function add() {
2     // 保存关联
3     if ($this->Tag->save($this->request->data)) {
4         // 保存成功后要做的事情
5     }
6 }
这段代码将创建一个新的 Tag 并与 Recipe 相关联,其 ID 由 $this->request->data['Recipe']['id'] 设置。
 
某些情况下,我们可能希望呈现的关联数据能够包含下拉 select 列表。数据可能使用 find('list') 从模型中取出并且赋给用模型名命名的视图变量。 同名的 input 将自动把数据放进 that allows multiple selections. For example, a Recipe may be assigned multiple Tags. In this case, the data is taken out of the model in the same way, but the form input definition is slightly different. Tag naming uses the ModelName convention:
1 // Code in controller:
2 $this->set('tags', $this->Recipe->Tag->find('list'));
1 // Code in view:
2 $this->Form->input('Tag');
Using the above code, a drop-down list (select) with multiple selections will be created, allowing multiple selections to be automatically saved to the Recipe that has been added or saved to the database.
What to do when HABTM gets complicated?
By default, when Cake saves a HABTM relationship, it will first delete all rows in the join table. For example, there is a Club with 10 Children associations. Update Club with 2 children. Club will only have 2 Children instead of 12.
Be aware that if you want to add more columns (build time or metadata) to a join table with HABTM it is possible, it is important to understand that you have a simple option.
The HasAndBelongsToMany association between two models is actually the abbreviation of three model relationships that have both hasMany and belongsTo associations.
Consider the following example:
Child hasAndBelongsToMany Club
Another way is to add a Membership model:
Child hasMany Membership
Membership belongsTo Child, Club
Club hasMany Membership.
These two examples are almost identical. They use the same named amount column in the database and the same amount in the model. The most important difference is that the "join" table is named differently and its behavior is more predictable.
Tips
When the join table contains extension columns other than foreign keys, you can prevent the value of the extension column from being lost by setting the 'unique' of the array to "'keepExisting'". Similarly, it can be considered that by setting ‘unique’ => true, the data of the extended column will not be lost during the save operation. See HABTM association arrays.
However, in more cases, it is simpler to build a model for the join table and set up the hasMany, belongsTo associations as in the example above, instead of using the HABTM association.
Data sheet
Although CakePHP can have non-database-driven data sources, most of the time, it is database-driven. CakePHP is designed to work with MySQL, MSSQL, Oracle, PostgreSQL and other databases. You can create tables in the database system you normally use. When creating a model class, the model will automatically be mapped to the established table. Table names are converted to plural lowercase, and words in multi-word table names are separated by underscores. For example, a model named Ingredient has a table named ingredients. The model named EventRegistration corresponds to a table named event_registrations. CakePHP will examine the table to determine the data type of each column and use this information to automate various features, such as form fields that are output in views. Column names are converted to lowercase and separated by underscores.
Use created and modified columns
By defining created and modified columns as datetime columns in the database table, CakePHP can identify these fields and automatically fill them in with the time the record was created in the database and the time it was saved (unless the data being saved already contains these domain value).
When the record is initially added, the created and modified columns will be set to the current date and time. When an existing record is saved, the modified column will be updated to the current date and time.
If $this->data contains updated, created, modified data (such as Model::read or Model::set) before Model::save(), then these values ​​will be changed from $this-> data and is not updated automatically. Or use methods such as unset($this->data['Model']['modified']). It's always possible to override the Model::save() method to do this:
1 class AppModel extends Model {
2
3 public function save($data = null, $validate = true, $fieldList = array()) {
4        // Clear the modified field value before each save operation:
5 $this->set($data);
6 if (isset($this->data[$this->alias]['modified'])) {
7 unset($this->data[$this->alias]['modified']);
8 }
9 return parent::save($this->data, $validate, $fieldList);
10 }
11
12}

www.bkjia.comtruehttp: //www.bkjia.com/PHPjc/477776.htmlTechArticleSaving data CakePHP will make a snapshot for saving model data. The data to be saved is passed to the model's save() method using the following basic format: 1 Array 2 ( 3 [ModelName] = Array 4 ( 5...
Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn