Answers.Body: <p>If you take a look at the <code>formRule()</code> method, you will notice that it is static:</p>
  
  <pre><code>public static function formRule($params) {
  ...
  </code></pre>
  
  <p>When methods are invoked statically, you don't have access to $this. There is a similar construct to <code>$this-&gt;</code>, which is <code>self::</code> (see <a href="http://php.net/manual/en/language.oop5.static.php" rel="nofollow noreferrer">http://php.net/manual/en/language.oop5.static.php</a>) for more info, but I don't think it will help in your case as assign is expecting a form object  to work with.</p>
  
  <p>If you want to add validation to a form, you probably want to use the <code>addRules()</code> method. You can define a custom function (callback) that will accept the values submitted into the form and expects you to return an array of errors.</p>
  
  <pre><code>/**
  * If your form requires special validation, add one or more callbacks here
  */
  function addRules() {
    $this-&gt;addFormRule(array('CRM_Example_Form', 'myRules'));
  }
  /**
  * Here's our custom validation callback
  */
  static function myRules($values) {
    $errors = array();
    if ($values['foo'] != 'abc') {
      $errors['foo'] = ts('You entered the wrong text!');
    }
    return empty($errors) ? TRUE : $errors;
  }
  </code></pre>
  
  <p>see <a href="https://wiki.civicrm.org/confluence/display/CRMDOC/QuickForm+Reference" rel="nofollow noreferrer">https://wiki.civicrm.org/confluence/display/CRMDOC/QuickForm+Reference</a> for more details.</p>
  
  <p>Another method I have used is</p>
  
  <pre><code>public function validate() {
    $this-&gt;setElementError(); // &lt;-- more details here...
    return parent::validate();
  }
  </code></pre>
  
  <p>See <a href="https://pear.php.net/manual/en/package.html.html-quickform.html-quickform.setelementerror.php" rel="nofollow noreferrer">https://pear.php.net/manual/en/package.html.html-quickform.html-quickform.setelementerror.php</a> for more info, though I think the above method is a little off piste.</p>
  
  <p>Though having said that, the correct method really depends on why you are modifying the MembershipRenewal.php form.</p>
  
  <p>If you are <strong><em>making a modification for your local site</em></strong>, you should really create an extension and use the <a href="https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_validateForm/" rel="nofollow noreferrer">https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_validateForm/</a> hook.</p>
  
  <p>If you are looking to make <strong><em>a more generic improvement and submit it to core</em></strong>, then the approach described above is the way to go, but you'll want to discuss your planned modifications with others before doing too much work somewhere like <a href="https://chat.civicrm.org/civicrm/channels/dev" rel="nofollow noreferrer">https://chat.civicrm.org/civicrm/channels/dev</a>.</p>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2017-08-03T09:42:38.677Z
Answers.Text: Thanks for your detailed reply. I am trying to work on a reported bug that is why looking at modifying the core. Just doing some homework before I can submit any request to resolve it. I checked most of the documentation you mentioned. Can't find the documentation on how to create complex rule using addRule, i.e. like comparing two dates. Will self:: work - I can then use a variable instead of assign().
Answers.UserDisplayName: Amal
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2017-08-03T09:52:16.960Z
Answers.Text: Can you, @ErikH or someone suggest a solution also - last part of my question. Right now I got it working using a hidden field. Is that the right approach?
Answers.UserDisplayName: Amal
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2017-08-03T11:29:54.940Z
Answers.Text: @amal, i added some more detail on how you can/should use the addRules function. I'm not sure what you are using ->assign for, but if you are performing validation, then the typical approach is to use the $values and return an invalid message as part of the $errors array. If you want to reference the issue number, I might be able to give you a bit more help.
Answers.UserDisplayName: michaelmcandrew
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2017-08-03T15:09:34.560Z
Answers.Text: The issue #CRM-20571 @michaelmcandrew [link]( https://issues.civicrm.org/jira/browse/CRM-20571). I understood how `$values` works but it doesn't contain the `join_date`. I am new to CiviCRM so still trying to understand how it all works. I have to compare `join_date` and `renewal_date`. I wasn't planning to use `assign`, just using it as an example to understand how to get values not available on the form. Thanks for your help.
Answers.UserDisplayName: Amal
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2017-08-03T15:40:36.400Z
Answers.Text: hmm, i am guessing join_date is not in the form because this is a membership renewal?  is the membership ID passed into values? If so, then one option would be to look up the join date in your validation callback. Else you could also overwrite the validate function (I added a stub above). Feel free to join https://chat.civicrm.org/civicrm/channels/dev and we can chat in real time if you like.
Answers.UserDisplayName: michaelmcandrew
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2017-08-03T08:17:17.113Z
Answers.LastActivityDate: 2017-08-03T15:58:20.153Z
Answers.LastEditDate: 2017-08-03T15:58:20.153Z
Answers.UserDisplayName: michaelmcandrew
Answers.Body: <p>First of all, I get the idea that you are actually modifying CiviCRM core code in your installation? If so, I would sincerely advise you NOT to do this but create an extension to customize what you need.</p>
  
  <p>AFAIK formRule will be a static function, so will indeed not recognize your <code>$this</code>.</p>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2017-08-03T09:45:10.660Z
Answers.Text: Trying to work on a bug @ErikH.
Answers.UserDisplayName: Amal
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2017-08-03T10:41:01.637Z
Answers.Text: Good job @Amal!
Answers.UserDisplayName: ErikH - CiviCooP
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2017-08-03T08:11:39.690Z
Answers.LastActivityDate: 2017-08-03T08:11:39.690Z
Answers.UserDisplayName: ErikH - CiviCooP
Body: <p>I am using CiviCRM 4.7.22 with Drupal 7 on Windows. I have a basic question.  In the <code>formRule()</code> function inside the <code>MembershipRenewal.php</code> containing Membership Renewal Form if I use $this as below</p>
  
  <pre><code>$this-&gt;assign('endDate', CRM_Utils_Date::customFormat(CRM_Core_DAO::getFieldValue('CRM_Member_DAO_Membership', $this-&gt;_id, 'end_date')));
  </code></pre>
  
  <p>I get a PHP error:</p>
  
  <pre><code>PHP Fatal error: Using $this when not in object context in ...\MembershipRenewal.php on line xxx
  </code></pre>
  
  <p>Although this code works in <code>preProcess()</code> and <code>buildQuickForm()</code> without any issues. If its part of the same class then why the issue.</p>
  
  <p>What is the alternative for me get the value of <code>end_date</code> or <code>join_date</code> in <code>formRule()</code> to perform some validition. In general, how do I get any value which is NOT part of a form in <code>formRule()</code>.</p>
  
Tags: <civimember><forms><quickform>
Title: Adding validation: cannot use $this in formRule() of Form
ThreadText: # Adding validation: cannot use $this in formRule() of Form
  
  (Asked by: username_0 on 2017-08-03)
  
  I am using CiviCRM 4.7.22 with Drupal 7 on Windows. I have a basic question. In the `formRule()` function inside the `MembershipRenewal.php` containing Membership Renewal Form if I use $this as below
  
  ```
  $this->assign('endDate', CRM_Utils_Date::customFormat(CRM_Core_DAO::getFieldValue('CRM_Member_DAO_Membership', $this->_id, 'end_date')));
  
  ```
  
  I get a PHP error:
  
  ```
  PHP Fatal error: Using $this when not in object context in ...\MembershipRenewal.php on line xxx
  
  ```
  
  Although this code works in `preProcess()` and `buildQuickForm()` without any issues. If its part of the same class then why the issue.
  
  What is the alternative for me get the value of `end_date` or `join_date` in `formRule()` to perform some validition. In general, how do I get any value which is NOT part of a form in `formRule()`.
  
  **Tags:** civimember, forms, quickform
  
  
  ---
  
  ## 2 answers
  
  ### Answer by username_1 on 2017-08-03. Score: 2 | Accepted answer
  
  If you take a look at the `formRule()` method, you will notice that it is static:
  
  ```
  public static function formRule($params) {
  ...
  
  ```
  
  When methods are invoked statically, you don't have access to $this. There is a similar construct to `$this->`, which is `self::` (see <http://php.net/manual/en/language.oop5.static.php>) for more info, but I don't think it will help in your case as assign is expecting a form object to work with.
  
  If you want to add validation to a form, you probably want to use the `addRules()` method. You can define a custom function (callback) that will accept the values submitted into the form and expects you to return an array of errors.
  
  ```
  /**
  * If your form requires special validation, add one or more callbacks here
  */
  function addRules() {
    $this->addFormRule(array('CRM_Example_Form', 'myRules'));
  }
  /**
  * Here's our custom validation callback
  */
  static function myRules($values) {
    $errors = array();
    if ($values['foo'] != 'abc') {
      $errors['foo'] = ts('You entered the wrong text!');
    }
    return empty($errors) ? TRUE : $errors;
  }
  
  ```
  
  see <https://wiki.civicrm.org/confluence/display/CRMDOC/QuickForm+Reference> for more details.
  
  Another method I have used is
  
  ```
  public function validate() {
    $this->setElementError(); // <-- more details here...
    return parent::validate();
  }
  
  ```
  
  See <https://pear.php.net/manual/en/package.html.html-quickform.html-quickform.setelementerror.php> for more info, though I think the above method is a little off piste.
  
  Though having said that, the correct method really depends on why you are modifying the MembershipRenewal.php form.
  
  If you are ***making a modification for your local site***, you should really create an extension and use the <https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_validateForm/> hook.
  
  If you are looking to make ***a more generic improvement and submit it to core***, then the approach described above is the way to go, but you'll want to discuss your planned modifications with others before doing too much work somewhere like <https://chat.civicrm.org/civicrm/channels/dev>.
  
  > **Comments:**
  > **username_0**: Thanks for your detailed reply. I am trying to work on a reported bug that is why looking at modifying the core. Just doing some homework before I can submit any request to resolve it. I checked most of the documentation you mentioned. Can't find the documentation on how to create complex rule using addRule, i.e. like comparing two dates. Will self:: work - I can then use a variable instead of assign().  
  > **username_0**: Can you, @username_2 or someone suggest a solution also - last part of my question. Right now I got it working using a hidden field. Is that the right approach?  
  > **username_1**: @username_0, i added some more detail on how you can/should use the addRules function. I'm not sure what you are using ->assign for, but if you are performing validation, then the typical approach is to use the $values and return an invalid message as part of the $errors array. If you want to reference the issue number, I might be able to give you a bit more help.  
  > **username_0**: The issue #CRM-20571 @username_1 [link]( https://issues.civicrm.org/jira/browse/CRM-20571). I understood how `$values` works but it doesn't contain the `join_date`. I am new to CiviCRM so still trying to understand how it all works. I have to compare `join_date` and `renewal_date`. I wasn't planning to use `assign`, just using it as an example to understand how to get values not available on the form. Thanks for your help.  
  > **username_1**: hmm, i am guessing join_date is not in the form because this is a membership renewal?  is the membership ID passed into values? If so, then one option would be to look up the join date in your validation callback. Else you could also overwrite the validate function (I added a stub above). Feel free to join https://chat.civicrm.org/civicrm/channels/dev and we can chat in real time if you like.  
  
  ---
  
  ### Answer by username_2 on 2017-08-03. Score: 0
  
  First of all, I get the idea that you are actually modifying CiviCRM core code in your installation? If so, I would sincerely advise you NOT to do this but create an extension to customize what you need.
  
  AFAIK formRule will be a static function, so will indeed not recognize your `$this`.
  
  > **Comments:**
  > **username_0**: Trying to work on a bug @username_2.  
  > **username_2**: Good job @username_0!  
  
  ---
  
  