1
votes

I want to make this tutorial http://miftyisbored.com/complete-tutorial-habtm-relationships-cakephp/ in cakePHP 3.0

I have 3 tables: recipes, ingredients and ingredients_recipes.

When making a recipe, I want to select ingredients. Then I want to store the recipe_id and ingredient_id in the ingredients_recipes table, but fail to do so. I think there's something wrong in my RecipesController. Can someone help me or point me in the right direction?

Problem:

$ingredients = $this->Recipes->Ingredients->find('list', ['limit' => 200]);
// => THIS GIVES ME THE MESSAGE "The recipe could not be saved. Please, try again."

$ingredients = $this->Ingredients->find('list', ['limit' => 200]);
// => THIS GIVES ME THE ERROR "Call to a member function find() on boolean"

When I do var dump (when using this $this->Recipes->Ingredients->find) I get this:

array(3) { 
   ["recipe_name"]=> string(4) "Test" 
   ["recipe_description"]=> string(4) "Test" 
   ["Recipe"]=> array(1) { 
      ["Ingredient"]=> array(1) { [0]=> string(1) "1" } 
   } 
}

Tables:

CREATE TABLE `recipes` (
  `recipe_id` int(11) NOT NULL auto_increment,
  `recipe_name` varchar(255) NOT NULL,
  `recipe_description` text NOT NULL,
  PRIMARY KEY  (`recipe_id`)
);
CREATE TABLE `ingredients` (
  `ingredient_id` int(11) NOT NULL auto_increment,
  `ingredient_name` varchar(255) NOT NULL,
  `ingredient_description` text NOT NULL,
  PRIMARY KEY  (`ingredient_id`)
);
CREATE TABLE `ingredients_recipes` (
  `ingredient_id` int(11) NOT NULL,
  `recipe_id` int(11) NOT NULL,
  PRIMARY KEY  (`ingredient_id`,`recipe_id`)
);

Here's my code below:

Model > Entity:

Recipe

class Recipe extends Entity
{
    protected $_accessible = [
        'recipe_id' => true,
        'recipe_name' => true,
        'recipe_description' => true,
    ];
}

Ingredient

class Ingredient extends Entity
{
    protected $_accessible = [
        'ingredient_id' => true,
        'ingredient_name' => true,
        'ingredient_description' => true,
    ];
}

IngredientsRecipe

class IngredientsRecipe extends Entity
{
    protected $_accessible = [
        'ingredient' => true,
        'recipe' => true,
    ];
}

Model > Table :

RecipesTable

class RecipesTable extends Table
{
    public function initialize(array $config)
    {
        $this->table('recipes');
        $this->displayField('recipe_name');
        $this->primaryKey('recipe_id');

        $this->belongsTo('Recipes', [
            'foreignKey' => 'recipe_id',
            'joinType' => 'INNER'
        ]);

        $this->belongsToMany('Ingredients', [
            'className' => 'Ingredients',
            'joinTable' => 'ingredients_recipes',
            'foreignKey' => 'recipe_id',
            'targetForeignKey' => 'ingredient_id' 
        ]);
    }
    public function validationDefault(Validator $validator)
    {
        $validator
            ->requirePresence('recipe_name', 'create')
            ->notEmpty('recipe_name')

            ->requirePresence('recipe_description', 'create')
            ->notEmpty('recipe_description')

            ->requirePresence('Ingredients', 'create')
            ->notEmpty('Ingredients');

        return $validator;
    }
}

IngredientsTable

class IngredientsTable extends Table
{
    public function initialize(array $config)
    {
        $this->table('ingredients');
        $this->displayField('ingredient_name');
        $this->primaryKey('ingredient_id');

        $this->belongsTo('Ingredients', [
            'foreignKey' => 'ingredient_id',
            'joinType' => 'INNER'
        ]);

        $this->belongsToMany('Recipies', [
            'className' => 'Recipies',
            'joinTable' => 'ingredients_recipes',
            'foreignKey' => 'ingredient_id',
            'targetForeignKey' => 'recipe_id' 
        ]);
    }
}

IngredientsRecipesTable

class IngredientsRecipesTable extends Table
{
    public function initialize(array $config)
    {
        $this->table('ingredients_recipes');

        $this->displayField('recipe_id');

        $this->primaryKey(['recipe_id', 'ingredient_id']);

        $this->belongsTo('Recipies', [
            'foreignKey' => 'recipe_id',
            'joinType' => 'INNER'
        ]);

        $this->belongsTo('Ingredients', [
            'foreignKey' => 'ingredient_id',
            'joinType' => 'INNER'
        ]);
    }

Controller:

RecipesController

public function add()
{
    $recipe = $this->Recipes->newEntity();
    if ($this->request->is('post')) {
        $recipe = $this->Recipes->patchEntity($recipe, $this->request->data);
        // var_dump($this->request->data);
        if ($this->Recipes->save($recipe)){
            $this->Flash->success('The recipe has been saved.');
            return $this->redirect(['action' => 'index']);
        } else {
            $this->Flash->error('The recipe could not be saved. Please, try again.');
        }
    }
    $recipes = $this->Recipes->find('list', ['limit' => 200]);

    $ingredients = $this->Recipes->Ingredients->find('list', ['limit' => 200]);
    // => THIS GIVES ME THE MESSAGE "The recipe could not be saved. Please, try again."
    $ingredients = $this->Ingredients->find('list', ['limit' => 200]);
    // => THIS GIVES ME THE ERROR "Call to a member function find() on boolean"

    $this->set(compact('recipe', 'recipes', 'ingredients'));
    $this->set('_serialize', ['recipe']);
}

Template > Recipes

add.ctp

<?= $this->Form->create($recipe); ?>
    <fieldset>
        <legend><?= __('Add Recipe') ?></legend>
        <?php
            echo $this->Form->input('recipe_name', array(
                'label' => 'Name'
                )
            );
            echo $this->Form->input('recipe_description', array(
                'label' => 'Description'
                )
            );

            echo $this->Form->input('Recipes.Ingredients', ['multiple'=>true]);
        ?>
    </fieldset>
    <?= $this->Form->button(__('Submit')) ?>
    <?= $this->Form->end() ?>
1
One thing is noted is that the recipes table yo have 'recipe_id' and not id. Your recipes table should have columns as id, name, description. If they are already setup like that in DB, then you need to fix your code to reflect that. Take a look at CakePHP standards: book.cakephp.org/3.0/en/contributing/… - AKKAweb
Also I failed to notice that is a tutorial for CakePHP 2. There are a couple of tutorials in the CakePHP book that are 3.0 examples, namely a Blog and Bookmark tutorial. - AKKAweb
Yeah I know the tutorial is for cakePHP 2.0, but I want to remake the tutorial in cakePHP 3.0 - Gilko
Well.. ok then. I would say, run your code on a server and come back with errors. Someone in here should be able to help you at that point. Or better yet, create your database tables correctly per CakePHP's convention (See docs), use bin/cake bake all Recipes, etc and look at your code.... then add what else you need. - AKKAweb

1 Answers

0
votes

Maybe this tutorial could help: http://book.cakephp.org/3.0/en/tutorials-and-examples/bookmarks/intro.html.

It explains exactly how to set up HABTM relations, adding tags to bookmarks, and more.

Good luck and happy coding :)