{ES} - 3.7.4.1 Guardando Datos de Modelos Relacionados (hasOne, hasMany, belongsTo)

Cuando estamos trabajando con modelos asociados, es importante tener en cuenta que al guardar los datos de un modelo hay que hacerlo con el correspondiente modelo de CakePHP. Si estás guardando una nueva Entrada y sus Comentarios asociados, entonces deberías usar ambos modelos, Entrada y Comentario, durante la operación de guardado.

Si ninguno de los registros de los modelos asociados existe aún (por ejemplo, quieres guardar registros de un nuevo Usuario y su Perfil relacionado a la vez ), primero necesitarás guardar el modelo primario o padre.

Para tener una idea de cómo funciona esto, imaginemos que tenemos una acción en nuestro controlador de usuarios UsersController que maneja el guardado de un nuevo usuario y su perfil correspondiente. En la acción de ejemplo mostrada abajo se asumirá que has POSTeado sufientes datos (usando el FormHelper) para crear un solo Usuario y un solo Perfil.

<?php
function add() {
    if (!empty($this->data)) {
        // Podemos guardar los datos de Usuario
        // deberían estar en: $this->data['Usuario']
        $this->Usuario->save($this->data);

        // El ID del nuevo Usuario está ahora en $this->User->id, así que lo
        // añadimos a los datos a grabar y grabamos el Perfil
        $this->data['Perfil']['usuario_id'] = $this->Usuario->id;

        // Como nuestro "Usuario hasOne Perfil", podemos acceder
        // al modelo Perfil a través del modelo Usuario
        $this->Usuario->Perfil->save($this->data);
    }
}
?>
  1. <?php
  2. function add() {
  3. if (!empty($this->data)) {
  4. // Podemos guardar los datos de Usuario
  5. // deberían estar en: $this->data['Usuario']
  6. $this->Usuario->save($this->data);
  7. // El ID del nuevo Usuario está ahora en $this->User->id, así que lo
  8. // añadimos a los datos a grabar y grabamos el Perfil
  9. $this->data['Perfil']['usuario_id'] = $this->Usuario->id;
  10. // Como nuestro "Usuario hasOne Perfil", podemos acceder
  11. // al modelo Perfil a través del modelo Usuario
  12. $this->Usuario->Perfil->save($this->data);
  13. }
  14. }
  15. ?>

Como norma general, cuando trabajamos con asociaciones hasOne, hasMany y belongsTo ('tiene un', 'tiene varios', y 'pertenece a'), todo es cuestión de las claves. La idea básica es coger la clave de un modelo y ponerla en el campo de clave foránea en el otro. A veces esto puede implica usar el atributo $id de la clase del modelo después de save(), pero otras veces podría simplemente implicar obtener el ID desde un campo oculto de un formulario POSTeado a una acción del controlador.

Para complementar el enfoque básico usado arriba, CakePHP también ofrece el método muy útil saveAll, el cual te permite validar y grabar múltiples modelos de golpe. Además, saveAll provee de soporte transaccional para asegurar la integridad de los datos en tu base de datos (p.ej. si un modelo falla en la grabación, los otros modelos tampoco serán grabados).

Para que las transacciones funcionen correctametne en MySQL, tus tablas han de usar el mecanismo InnoDB. Recuerda que las tablas MyISAM no soportan transacciones.

Veamos cómo podemos usar saveAll() para grabar modelos de Compañía (utilizamos este nombre incorrecto por motivos didácticos) y Cuenta al mismo tiempo.

Primero, necesitas construir tu formulario tanto para el modelo Compañía como el modelo Cuenta (asumismo que Compañía hasMany Cuenta).

echo $form->create(Compañía, array('action'=>'añadir'));
echo $form->input('Compañía.nombre', array('label'=>'Nombre de compañía'));
echo $form->input('Compañía.descripción');
echo $form->input('Compañía.localización');

echo $form->input('Cuenta.0.nombre', array('label'=>'Nombre de cuenta'));
echo $form->input('Cuenta.0.nombreusuario');
echo $form->input('Cuenta.0.email');

echo $form->end('Añadir');

  1. echo $form->create(Compañía, array('action'=>'añadir'));
  2. echo $form->input('Compañía.nombre', array('label'=>'Nombre de compañía'));
  3. echo $form->input('Compañía.descripción');
  4. echo $form->input('Compañía.localización');
  5. echo $form->input('Cuenta.0.nombre', array('label'=>'Nombre de cuenta'));
  6. echo $form->input('Cuenta.0.nombreusuario');
  7. echo $form->input('Cuenta.0.email');
  8. echo $form->end('Añadir');

Echemos un vistazo a la manera en que hemos nombrado los campos del formulario para el modelo Cuenta. Si Compañía es nuestro modelo principal, saveAll esperará que los datos de los modelos relacionados (en este caso, Cuenta) llegue en un formado específico, y teniendo Cuenta.0.nombreCampo es exactamente lo que necesitamos.

El nombrado de campos de arriba es necesario para la asociación hasMany. Si la asociación entre los modelos es hasOne, necesitarás usar la notación NombreModelo.nombreCampo para el modelo asociado.

Ahora, en nuestro compañias_controler.php podemos crear una acción add():

function add() {
   if(!empty($this->data)) {
      $this->Compañia->saveAll($this->data, array('validate'=>'first'));
   }
}
  1. function add() {
  2. if(!empty($this->data)) {
  3. $this->Compañia->saveAll($this->data, array('validate'=>'first'));
  4. }
  5. }

Esto es todo para ello. Ahora nuestros modelos Compañía y Cuenta serán validados y grabados al mismo tiempo. Una cosa rápida que comentar aquí es el uso de array('validate'=>'first'): esa opción asegurará que ambos modelos son validados.

{EN} - 3.7.4.1 Saving Related Model Data (hasOne, hasMany, belongsTo)

When working with associated models, it is important to realize that saving model data should always be done by the corresponding CakePHP model. If you are saving a new Post and its associated Comments, then you would use both Post and Comment models during the save operation.

If neither of the associated model records exists in the system yet (for example, you want to save a new User and their related Profile records at the same time), you'll need to first save the primary, or parent model.

To get an idea of how this works, let's imagine that we have an action in our UsersController that handles the saving of a new User and a related Profile. The example action shown below will assume that you've POSTed enough data (using the FormHelper) to create a single User and a single Profile.

<?php
function add() {
	if (!empty($this->data)) {
		// We can save the User data:
		// it should be in $this->data['User']
 
		$this->User->save($this->data);
 
		// Now we add this information to the save data
		// and save the Profile.
 
		// The ID of the newly created user has been set
		// as $this->User->id.
		$this->data['Profile']['user_id'] = $this->User->id;
 
		// Because our User hasOne Profile, we can access
		// the Profile model through the User model:
		$this->User->Profile->save($this->data);
	}
}
?>
  1. <?php
  2. function add() {
  3. if (!empty($this->data)) {
  4. // We can save the User data:
  5. // it should be in $this->data['User']
  6. $this->User->save($this->data);
  7. // Now we add this information to the save data
  8. // and save the Profile.
  9. // The ID of the newly created user has been set
  10. // as $this->User->id.
  11. $this->data['Profile']['user_id'] = $this->User->id;
  12. // Because our User hasOne Profile, we can access
  13. // the Profile model through the User model:
  14. $this->User->Profile->save($this->data);
  15. }
  16. }
  17. ?>

As a rule, when working with hasOne, hasMany, and belongsTo associations, its all about keying. The basic idea is to get the key from one model and place it in the foreign key field on the other. Sometimes this might involve using the $id attribute of the model class after a save(), but other times it might just involve gathering the ID from a hidden input on a form that’s just been POSTed to a controller action.

To supplement the basic approach used above, CakePHP also offers a very handy method saveAll(), which allows you to validate and save multiple models in one shot. In addtion, saveAll() provides transactional support to ensure data integrity in your database (i.e. if one model fails to save, the other models will not be saved either).

For transactions to work correctly in MySQL your tables must use InnoDB engine. Remember that MyISAM tables do not support transactions.

Let's see how we can use saveAll() to save Company and Account models at the same time.

First, you need to build your form for both Company and Account models (we'll assume that Company hasMany Account).


echo $form->create(Company, array('action'=>'add'));
echo $form->input('Company.name', array('label'=>'Company name'));
echo $form->input('Company.description');
echo $form->input('Company.location');

echo $form->input('Account.0.name', array('label'=>'Account name'));
echo $form->input('Account.0.username');
echo $form->input('Account.0.email');

echo $form->end('Add');

  1. echo $form->create(Company, array('action'=>'add'));
  2. echo $form->input('Company.name', array('label'=>'Company name'));
  3. echo $form->input('Company.description');
  4. echo $form->input('Company.location');
  5. echo $form->input('Account.0.name', array('label'=>'Account name'));
  6. echo $form->input('Account.0.username');
  7. echo $form->input('Account.0.email');
  8. echo $form->end('Add');

Take a look at the way we named the form fields for the Account model. If Company is our main model saveAll() will expect the related model's (Account) data to arrive in a specific format. And having Account.0.fieldName is exactly what we need.

The above field naming is required for a hasMany association. If the association between the models is hasOne, you have to use ModelName.fieldName notation for the associated model.

Now, in our companies_controller we can create an add() action:


function add() {
   if(!empty($this->data)) {
      $this->Company->saveAll($this->data, array('validate'=>'first'));
   }
}

  1. function add() {
  2. if(!empty($this->data)) {
  3. $this->Company->saveAll($this->data, array('validate'=>'first'));
  4. }
  5. }

That's all there is to it. Now our Company and Account models will be validated and saved all at the same time. A quick thing to point out here, is the use of array('validate'=>'first'), this option will ensure that both of our models are validated.

Diferencias

Lines: 1-96Lines: 1-66
-<title>Saving Related Model Data (hasOne, hasMany, belongsTo)</title>
<p> /> When working with associated models, it is important to realize that saving model data should always be done by the corresponding CakePHP model. If you are saving a new Post and its associated Comments, then you would use both Post and Comment models during the save operation. /></p>
<p>
If
neither of the associated model records exists in the system yet (for example, you want to save a new User and their related Profile records at the same time), you'll need to first save the primary, or parent model.
</p>
<p>r /> To get an idea of how this works, let's imagine that we have an action in our UsersController that handles the saving of a new User and a related Profile. The example action shown below will assume that you've POSTed enough data (using the FormHelper) to create a single User and a single Profile.
</p>
+<title>Guardando Datos de Modelos Relacionados (hasOne, hasMany, belongsTo)</title>
<p>Cuando estamos trabajando con modelos asociados, es importante tener en cuenta que al guardar los datos de un modelo hay que hacerlo con el correspondiente modelo de CakePHP. Si estás guardando una nueva Entrada y sus Comentarios asociados, entonces deberías usar ambos modelos, Entrada y Comentario, durante la operación de guardado.</p>

<p>Si ninguno de los registros de los modelos asociados existe n (por ejemplo, quieres guardar registros de un nuevo Usuario y su Perfil relacionado a la vez ), primero necesitarás guardar el modelo primario o padre.</p>

<p>Para tener una idea de cómo funciona esto, imaginemos que tenemos una acción en nuestro controlador de usuarios <code>UsersController&lt;/code&gt; que maneja el guardado de un nuevo usuario y su perfil correspondiente. En la acción de ejemplo mostrada abajo se asumirá que has POSTeado sufientes datos (usando el <code>FormHelper&lt;/code>) para crear un solo Usuario y un solo Perfil.</p>
 <pre> <pre>
 &lt;?php &lt;?php
 function add() { function add() {
- if (!empty($this-&gt;data)) {
// We can save the User data:
// it should be in $this-&gt;data['User']
/> $this-&gt;User-&gt;save($this-&gt;data);

// Now we add this information to the save datar /> // and save the Profile.
/> // The ID of the newly created user has been set<br /> // as $this-&amp;gt;User-&gt;id.
$this-&gt;data['Profile']['user_id'] = $this-&gt;User-&gt;id;

// Because our User hasOne Profile, we can access
// the Profile model through the User model:
$this-&gt;User-&gt;Profile-&gt;save($this-&gt;data);
}
+ if (!empty($this-&gt;data)) {
// Podemos guardar los datos de Usuario
// deberían estar en: $this-&gt;data['Usuario']
$this-&gt;Usuario-&gt;save($this-&gt;data);

// El ID del nuevo Usuario está ahora en $this-&amp;gt;User-&amp;gt;id, así que lo
// añadimos a los datos a grabar y grabamos el Perfil
$this-&gt;data['Perfil']['usuario_id'] = $this-&gt;Usuario-&gt;id;

// Como nuestro "Usuario hasOne Perfil", podemos acceder
// al modelo Perfil a través del modelo Usuario
$this-&gt;Usuario-&gt;Perfil-&gt;save($this-&gt;data);
}
 } }
 ?&gt; ?&gt;
 </pre> </pre>
-<p> 
- As a rule, when working with hasOne, hasMany, and belongsTo associations, its all about keying. The basic idea is to get the key from one model and place it in the foreign key field on the other. Sometimes this might involve using the <code>$id</code> attribute of the model class after a <code>save()</code>, but other times it might just involve gathering the ID from a hidden input on a form that’s just been POSTed to a controller action. 
-</p> 
-<p> /> To supplement the basic approach used above, CakePHP also offers a very handy method <code>saveAll()</code>, which allows you to validate and save multiple models in one shot. In addtion, <code>saveAll()</code> provides transactional support to ensure data integrity in your database (i.e. if one model fails to save, the other models will not be saved either).r /></p> +<p>Como norma general, cuando trabajamos con asociaciones <em>hasOne</em>, <em>hasMany</em&gt; y <em>belongsTo</em> ('tiene un', 'tiene varios', y 'pertenece a'), todo es cuestión de las claves. La idea sica es coger la clave de un modelo y ponerla en el campo de clave foránea en el otro. A veces esto puede implica usar el atributo <code>$id</code> de la clase del modelo después de <code&gt;save()&lt;/code&gt;, pero otras veces podría simplemente implicar obtener el ID desde un campo oculto de un formulario POSTeado a una acción del controlador.</p>
-<p class=&quot;note&quot;>r />For transactions to work correctly in MySQL your tables must use InnoDB engine. Remember that MyISAM tables do not support transactions.
</p>
+<p>Para complementar el enfoque básico usado arriba, CakePHP también ofrece el método muy útil <code&gt;saveAll</code>, el cual te permite validar y grabar múltiples modelos de golpe. Además, <code&gt;saveAll</code> provee de soporte transaccional para asegurar la integridad de los datos en tu base de datos (p.ej. si un modelo falla en la grabación, los otros modelos tampoco serán grabados).</p>
-<p>r />Let's see how we can use <code&gt;saveAll()&lt;/code&gt; to save Company and Account models at the same time.
</p>
+<p class="note">Para que las transacciones funcionen correctametne en MySQL, tus tablas han de usar el mecanismo InnoDB. Recuerda que las tablas MyISAM no soportan transacciones.</p>
-<p>r />First, you need to build your form for both Company and Account models (we'll assume that Company hasMany Account).
</p>
+<p>Veamos cómo podemos usar <code>saveAll()</code> para grabar modelos de Compañía (utilizamos este nombre incorrecto por motivos didácticos) y Cuenta al mismo tiempo.</p>

<p>Primero, necesitas constr
uir tu formulario tanto para el modelo Compañía como el modelo Cuenta (asumismo que Compañía <em>hasMany</em> Cuenta).</p>
 <pre> <pre>
 +echo $form-&gt;create(Compañía, array('action'=&gt;'añadir'));
 +echo $form-&gt;input('Compañía.nombre', array('label'=&gt;'Nombre de compañía'));
 +echo $form-&gt;input('Compañía.descripción');
 +echo $form-&gt;input('Compañía.localización');
-echo $form-&gt;create(Company, array('action'=&amp;gt;'add'));
echo $form-&gt;input('Company.name', array('label'=&gt;'Company name'));
echo $form-&gt;input('Company.description');
echo $form-&gt;input('Company.location');
+echo $form-&gt;input('Cuenta.0.nombre', array('label'=&gt;'Nombre de cuenta'));
echo $form-&gt;input('Cuenta.0.nombreusuario');
echo $form-&gt;input('Cuenta.0.email');
-echo $form-&gt;input('Account.0.name', array('label'=&gt;'Account name'));
echo $form-&gt;input
('Account.0.username');
echo $form-&gt;
input('Account.0.email');r />
echo $form-&gt;end('Add
');
+echo $form-&gt;end('Añadir');
 </pre> </pre>
-<p> />Take a look at the way we named the form fields for the Account model. If Company is our main model <code>saveAll()</code> will expect the related model's (Account) data to arrive in a specific format. And having <code>Account.0.fieldName</code> is exactly what we need.
</p>
+<p>Echemos un vistazo a la manera en que hemos nombrado los campos del formulario para el modelo Cuenta. Si Compañía es nuestro modelo principal, <code>saveAll</code> esperará que los datos de los modelos relacionados (en este caso, Cuenta) llegue en un formado específico, y teniendo <code>Cuenta.0.nombreCampo</code> es exactamente lo que necesitamos.</p>
-<p class="note"><br />The above field naming is required for a hasMany association. If the association between the models is hasOne, you have to use ModelName.fieldName notation for the associated model.
</p>
+<p class="note">El nombrado de campos de arriba es necesario para la asociación &lt;em>hasMany</em>. Si la asociación entre los modelos es <em>hasOne</em>, necesitarás usar la notación <code>NombreModelo.nombreCampo&lt;/code> para el modelo asociado.</p>
-<p>r />Now, in our companies_controller we can create an <code>add()</code> action:
</p>
+<p>Ahora, en nuestro <kbd>compañias_controler.php</kbd> podemos crear una acción <code>add()</code>:</p>
 <pre> <pre>
 function add() { function add() {
  if(!empty($this-&gt;data)) {  if(!empty($this-&gt;data)) {
- $this-&gt;Company-&gt;saveAll($this-&gt;data, array('validate'=&gt;'first')); + $this-&gt;Compañia-&gt;saveAll($this-&gt;data, array('validate'=&gt;'first'));
  }  }
 } }
 </pre> </pre>
-<p>
Tha
t's all there is to it. Now our Company and Account models will be validated and saved all at the same time. />
A
quick thing to point out here, is the use of <code>array('validate'=>'first')</code>, this option will ensure that both of our models are validated.
</p>
+<p>Esto es todo para ello. Ahora nuestros modelos Compañía y Cuenta serán validados y grabados al mismo tiempo. Una cosa rápida que comentar aquí es el uso de <code>array('validate'=>'first')</code>: esa opción asegurará que ambos modelos son validados.</p>