phpcakephpcakephp-2.0

Stuck with HasMany through saving and error array_merge()


I'm trying to set up a pretty simple website to create and edit recipes ('Recettes' in french).

I'm an experienced frontend developer with a good knowledge (not advanced) of php, and I have been working on CakePhp with a team of developers in the past. I'm kind of learning the bases of starting a project from scratch and it is really not that easy. I've set up a project, database (Ingredients, Recette and IngredientRecette) and used Bake to generate most of the code.

I have a working CRUD workflow for my 3 models and the only thing left to do is to be able to add ingredients from the Recette/add page but i'm stuck. I followed the instructions on the cake php website (http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html#hasmany-through-the-join-model) and other website (cause the help on cakephp's doc is really not that helpful) and I beleive I have setup a correct Hasmany Through relationship. But the saveAll function doesn't save anything in the join model (IngredientRecette) and I've came accross a particular error (see below) after I've successfully solved another one that took me a couple of hours to work out ! So I have the feeling that I've checked, and double checked, and triple checked everything in my code and I've read every questions and answers on forums etc...

And I am stuck with this problem, maybe there is something obvious I didn't figured, or maybe and definitely don't understand how Cakephp really wordk :( Anyway, thanks in advance for those who will be able to bring there advices or help on this :

Here is the error I get after I submitted /recettes/add (I added some form elements to add an ingredient and a quantity to my Recette) :

Warning (2): array_merge() [function.array-merge]: Argument #2 is not an array [CORE\Cake\Model\Model.php, line 2250]

Here is the array I'm passing to the saveAll() method in the controller (output from debug()):

    array(
    'Recette' => array(
    'auteur' => '7',
    'nom' => 'Nouvelle Recette',
    'cout' => 'Pas cher',
    'niveau' => '5',
    'tps_realisation' => '30 min',
        'nb_personnes' => '6',
        'description' => 'Description data',
        'remarque' => ''
    ),
    'AssociatedIngredient' => array(
        'id_ingredient' => '6',
        'quantite' => '70 cl',
        'id_recette' => '7654'
    )
)

Here is my controller code :

<?php
App::uses('AppController', 'Controller');
/**
 * Recettes Controller
 *
 * @property Recette $Recette
 */
class RecettesController extends AppController {


/**
 * index method
 *
 * @return void
 */
    public function index() {
        $this->Recette->recursive = 0;
        $this->set('recettes', $this->paginate());
    }

/**
 * view method
 *
 * @param string $id
 * @return void
 */
    public function view($id = null) {
        $this->Recette->id = $id;
        if (!$this->Recette->exists()) {
            throw new NotFoundException(__('Invalid recette'));
        }
        $this->set('recette', $this->Recette->read(null, $id));
    }

/**
 * add method
 *
 * @return void
 */
    public function add() {

        if ($this->request->is('post')) {
            debug($this->request->data);
            $this->Recette->create();
            if ($this->Recette->saveAll($this->request->data)) {
                $this->Session->setFlash(__('The recette has been saved'));
                //$this->redirect(array('action' => 'index'));
            } else {
                $this->Session->setFlash(__('The recette could not be saved. Please, try again.'));
            }
        }

        $this->loadModel('Ingredient');
        $liste_ingr = $this->Ingredient->find('all');

        $this->set('liste_ingr', $liste_ingr);
    }

The IngredientRecette model

<?php
App::uses('AppModel', 'Model');
/**
 * Recette Model
 *
 * @property IngredientRecette $ingredient
 */
class Recette extends AppModel {
/**
 * Use database config
 *
 * @var string
 */
    public $useDbConfig = 'default';
/**
 * Use table
 *
 * @var mixed False or table name
 */
    public $useTable = 'recette';
/**
 * Primary key field
 *
 * @var string
 */
    public $primaryKey = 'id_recette';
/**
 * Display field
 *
 * @var string
 */
    public $displayField = 'nom';
    public $recursive = 2;


/**
 * Validation rules
 *
 * @var array
 */
    public $validate = array(
        'id_recette' => array(
            'numeric' => array(
                'rule' => array('numeric'),
            ),
        ),
        'auteur' => array(
            'numeric' => array(
                'rule' => array('numeric'),
            ),
        ),
        'nom' => array(
            'notempty' => array(
                'rule' => array('notempty'),
            ),
        ),
        'niveau' => array(
            'numeric' => array(
                'rule' => array('numeric'),
            ),
        ),
        'nb_personnes' => array(
            'numeric' => array(
                'rule' => array('numeric'),
            ),
        ),

    );

    //The Associations below have been created with all possible keys, those that are not needed can be removed

/**
 * hasMany associations
 *
 * @var array
 */
    public $hasMany = array(
        'AssociatedIngredient' => array(
            'className' => 'IngredientRecette',
            'foreignKey' => 'id_recette',
            'dependent' => false,
            'conditions' => '',
            'fields' => '',
            'order' => '',
            'limit' => '',
            'offset' => '',
            'exclusive' => '',
            'finderQuery' => '',
            'counterQuery' => ''
        )
    );

}

And IngredientRecette model (the join model)

<?php
App::uses('AppModel', 'Model');
/**
 * IngredientRecette Model
 *
 * @property ingredient $ingredient
 * @property recette $recette
 */
class IngredientRecette extends AppModel {
/**
 * Use database config
 *
 * @var string
 */
    public $useDbConfig = 'default';
/**
 * Use table
 *
 * @var mixed False or table name
 */
    public $useTable = 'ingredient_recette';
/**
 * Primary key field
 *
 * @var string
 */
    public $primaryKey = 'id_ingredient_recette';
    public $recursive = 2;

    //The Associations below have been created with all possible keys, those that are not needed can be removed

/**
 * belongsTo associations
 *
 * @var array
 */
    public $belongsTo = array(
        'IngredientLiaison' => array(
            'className' => 'Ingredient',
            'foreignKey' => 'id_ingredient',
            'conditions' => '',
            'fields' => '',
            'order' => ''
        ),
        'RecetteLiaison' => array(
            'className' => 'Recette',
            'foreignKey' => 'id_recette',
            'conditions' => '',
            'fields' => '',
            'order' => ''
        )
    );
}

So nothing is saved in the join model and I have this warning...

Any help appreciated and of course please let me know if anything is unclear ! thanks a lot !!


Solution

  • I think your data is not formatted correctly. How about trying this instead (notice the extra array I put inside Associated Ingredient). Since recipe hasMany associated ingredient, the data for Associated Ingredient should be a series of arrays.

     array(
    'Recette' => array(
    'auteur' => '7',
    'nom' => 'Nouvelle Recette',
    'cout' => 'Pas cher',
    'niveau' => '5',
    'tps_realisation' => '30 min',
        'nb_personnes' => '6',
        'description' => 'Description data',
        'remarque' => ''
    ),
    'AssociatedIngredient' => array( 
         array( 
            'id_ingredient' => '6',
            'quantite' => '70 cl',
            'id_recette' => '7654'
         ),
         array( /*ingredient 2 data*/ ),
       )
    );