0

I'm trying to use DerEuromark's Passwordable behavior with my CakePHP app but am having trouble getting it to work. I followed the installation instructions (http://www.dereuromark.de/2011/08/25/working-with-passwords-in-cakephp/), modifying my controller and views, but I keep getting an error saying that my BeforeValidate and BeforeSave aren't compatible with the behavior - and of course, the behavior doesn't work.

I know I need to get these two set up correctly in my model, but I don't know what they should look like- the instructions didn't cover this point.

What would a basic, vanilla BeforeValidate and BeforeSave need to look like to work with this behavior?

Under my Users controller:

public function register() {
if ($this->request->is('post') || $this->request->is('put')) {
    $this->User->Behaviors->attach('Tools.Passwordable');
    if ($this->User->save($this->request->data, true, array('username', 'name', 'email', 'pwd', 'pwd_repeat', 'group_id'))) {
    $this->Session->setFlash(__('The user has been saved'), 'flash/success');
            $this->redirect(array('action' => 'index'));
} else {
            $this->Session->setFlash(__('The user could not be saved. Please, try again.'), 'flash/error');
        }
   unset($this->request->data['User']['pwd']);
    unset($this->request->data['User']['pwd_repeat']);
}

The Passwordable behavior with the BeforeValidate and BeforeSave that my user.php needs to be compatible with: https://github.com/dereuromark/tools/blob/master/Model/Behavior/PasswordableBehavior.php

The error:

Strict (2048): Declaration of PasswordableBehavior::beforeValidate() should be compatible with ModelBehavior::beforeValidate(Model $model, $options = Array) [APP/Plugin/Tools/Model/Behavior/PasswordableBehavior.php, line 338]
Strict (2048): Declaration of PasswordableBehavior::beforeSave() should be compatible with ModelBehavior::beforeSave(Model $model, $options = Array) [APP/Plugin/Tools/Model/Behavior/PasswordableBehavior.php, line 338]

Edit: User Model:

<?php
App::uses('AppModel', 'Model');
App::uses('AuthComponent', 'Controller/Component');
App::uses('PasswordableBehavior', 'Tools.Model/Behavior');
/**
 * User Model
 *
 * @property Group $Group
 * @property Post $Post
 */
class User extends AppModel {

    //simplified per-group only permissions- tell ACL to skip checking user AROs and only check group AROs
    public function bindNode($user) {
    return array('model' => 'Group', 'foreign_key' => $user['User']['group_id']);
}

/**
 * Validation rules
 *
 * @var array
 */
public $validate = array(
    'username' => array(
        'notEmpty' => array(
            'rule' => array('notEmpty'),
            //'message' => 'Your custom message here',
            //'allowEmpty' => false,
            //'required' => false,
                //'last' => false, // Stop validation after this rule
                //'on' => 'create', // Limit validation to 'create' or 'update' operations
            ),

                    'username' => array(
            'rule' => 'isUnique',
            'required' => true,
            'allowEmpty' => false,
            'on' => 'create',
            'last' => false,
            'message' => 'That username has already been taken'
    ),
        ),


        'email' => array(
            'email' => array(
                'rule' => array('email'),
                //'message' => 'Your custom message here',
                //'allowEmpty' => false,
                //'required' => false,
                //'last' => false, // Stop validation after this rule
                //'on' => 'create', // Limit validation to 'create' or 'update' operations
            ),
        ),
        'password' => array(
            'notEmpty' => array(
                'rule' => array('notEmpty'),
                //'message' => 'Your custom message here',
                //'allowEmpty' => false,
                //'required' => false,
                //'last' => false, // Stop validation after this rule
                //'on' => 'create', // Limit validation to 'create' or     'update' operations
            ),
        ),
        'group_id' => array(
            'numeric' => array(
                'rule' => array('numeric'),
                //'message' => 'Your custom message here',
                //'allowEmpty' => false,
                //'required' => false,
                //'last' => false, // Stop validation after this rule
            //'on' => 'create', // Limit validation to 'create' or 'update' operations
        ),
    ),
);

//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(
        'Group' => array(
            'className' => 'Group',
            'foreignKey' => 'group_id',
            'conditions' => '',
            'fields' => '',
            'order' => ''
        )
    );

    public $actsAs = array('Acl' => array('type' => 'requester'));

    public function parentNode() {
        if (!$this->id && empty($this->data)) {
            return null;
        }
        if (isset($this->data['User']['group_id'])) {
            $groupId = $this->data['User']['group_id'];
        } else {
            $groupId = $this->field('group_id');
        }
        if (!$groupId) {
            return null;
        } else {
            return array('Group' => array('id' => $groupId));
        }
    }

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

    public function beforeValidate($options = array()) {

    }   


public function beforeSave($options = array()) {

} 

}
caitlin
  • 2,769
  • 4
  • 29
  • 65
  • Please update your question with the code of your `User` model. – Jan Jan 05 '14 at 23:16
  • I added the model. I've got dummy functions set up for BeforeValidate and BeforeSave, but they don't do anything yet. As I understand it, PasswordableBehavior is supposed to take pwd and pwd_repeat, compare them, and hash them if they match- is this right? Is there something else I need to do to route these variables properly? – caitlin Jan 05 '14 at 23:31

3 Answers3

1

The error already tells you already pretty precisely what you have to do: Make the method signature of the behavior match the signature of the ModelBehavior methods signature.

Looks like the plugin was not updated for reflect the changes in the latest CakePHP releases. The options array was added.

floriank
  • 25,546
  • 9
  • 42
  • 66
  • Thanks- I was assuming that variables/arrays weren't being passed correctly, but I couldn't tell from looking at the behavior how I was supposed to set up BeforeValidate and BeforeSave. Since CakePHP aims for DRY i had hoped that I could just use stubs, but that doesn't seem to be the case. I'm rather new at this and have been teaching myself by taking apart and modifying example code. :) – caitlin Jan 05 '14 at 23:36
  • That's not really a CakePHP issue but a PHP 5.4 change. You can disable it but I would recommend you to update the behavior and inform the author to fix it. See http://stackoverflow.com/questions/12229113/how-to-eliminate-php5-strict-standards-errors as well. – floriank Jan 05 '14 at 23:48
1

Be sure that the method signature matches. Parameters of the method have to be the same as the parameters of the parent class' method.

You probably forgot them in your User model.

If you are really using the code you posted the link to, the method signatures are correct. Maybe you are using an older version or have a mistake in your User model.

You also have to update the $actsAs property in order to use the behavior.

public $actsAs = array(
    'Acl' => array('type' => 'requester'),
    'Passwordable',
);

Also, beforeSave and beforeValidate must return true in order to proceed to the saving process. Otherwise, it aborts. See http://book.cakephp.org/2.0/en/models/callback-methods.html.

Jan
  • 1,231
  • 2
  • 13
  • 19
  • Are you sure you need to add `$actsAs`? When I do that it suddenly says "Behavior Not Found"- even though the plugin is installed and added to the bootstrap. – caitlin Jan 06 '14 at 01:28
  • 1
    Oh, you use Passwordable as a plugin's behavior. Use `$actsAs` with `'Tools.Passwordable'` (prefix the plugin name using dot syntax) instead of `'Passwordable'`. You have to use `actsAs` because otherwise, your behavior is not attatched to your model. – Jan Jan 07 '14 at 10:51
0

in you PasswordableBehavior do this for both your methods (beforeValidate , beforeSave )

public function beforeValidate ($options=array()) {
   ...
   ...
}

//or try this if it didn't work
public function beforeValidate (Model $model, $options=array()) {
   ...
   ...
}
Fury
  • 4,643
  • 5
  • 50
  • 80