Jump to content

problem with $this->set('$key', $value); in own methode


Recommended Posts

In a module i'm writing I want to use the data array to store data. This data I can pick up in the module & in the template.

$this->set($key, $value); works fine in the init(), but in other methodes I create I can't get it working.

* Or can I use an other way to set data available voor the template.

Wished I know a way to put "error" & "succes" messages in a variable for later output in the template.

Edited by Martijn Geerts
Link to comment
Share on other sites

I'm not sure without looking at examples and hard to say if there's maybe alternative or better/right ways.

My guess is that the class method is static and can't use $this. Like in the getModuleConfigInputfields().

*

That's what $this->message("You message"); and $this->error("Error message"); would be. This will display the messages above the content after the page is being rendered.

Link to comment
Share on other sites

Oké, i'll drop the whole code. Code is not nearly finished. But you get a clue, when you see. It's all about the echo "messages"in login() methode for example. It's installable/uninstallable,


<?php

class FrontMembers extends WireData implements Module, ConfigurableModule {

   /**
    * Return general info about the module for ProcessWire
    *
    */
   public static function getModuleInfo() {
       return array(
           'title' => 'FrontMembers',
           'summary' => 'front-end member management',
           'version' => 1,
           'href' => 'http://processwire.com/talk/index.php/topic,56.0.html',
           'author' => 'Martijn Geerts',
           'autoload' => true,
           'singular' => true
       );
   }

   /**
    * Defining defaults
    *
    */
    protected static $defaultSettings = array(
        'controller' => 'controller',
       'email' => '',
       'f_submit' => 'fm_submit',
       'loggedin' => false,
       'used_methode' => false,
       'all_methodes' => array(
           'changePassword',
           'confirmRegister',
           'forgotPassword',
           'login',
           'logout',
           'profile',
           'register',
           'resetPassword',
           'updateProfile'
           ),
       'postData' => array(),
       'getData' => array(),
       'requestData' => array(),
       'messages' => array(
               'succes' => array(),
               'error' => array()
           ),
       'seconds' => 10,
       'maxSeconds' => 300,
       'attempts' => 5
       );

   /**
    * set our default values before ProcessWire configures the module
    * __construct() is the first call within this Class
    *
    */

   public function __construct() {
       foreach(self::$defaultSettings as $key => $value) $this->set($key, $value);
   }

   /**
    * Initialize the module and setup hooks
    *
    * The init method of a module is called right after ProcessWire is bootstrapped, when all
    * API vars are ready. Whereas the __construct() is called DURING bootstrap, so the init()
    * method is a better place to attach hooks to API vars.
    *
    * In this method, we'll use an 'after' hook since we want to modify the output of the
    * rendered page template.
    *
    * Note also that the 'Class::method' syntax means it hooks into ALL Page instances.
    * The syntax for hooking to a single instance would be:
    * $page->addHookAfter('render', $this, 'pageRender');
    *
    * Also note that there isn't actually a Page::render method, it was instead added by
    * another module (wire/modules/PageRender.module). Not that it matters here, but just
    * wanted to mention in case you look in the Page class and don't see a render method.
    *
    * text by: apeisa, thanks
    *
    */

   public function ready() {

       if( $this->loggedin && $this->page->template == 'admin') $this->session->redirect('/');

       if($this->input->urlSegment(1) == 'logout') $this->logout();
       if($this->input->urlSegment(2) == 'logout') $this->logout();
       if($this->input->urlSegment(3) == 'logout') $this->logout();
   }

   public function init() {

       // check if user is logged in as member
       if($this->user->hasRole('front-member')) $this->set('loggedin', true);

       // no get or post, nothing to do
       if (!isset($_REQUEST[$this->controller])) return false;

       // create empty array
       $init = array();

       $key = array_search($_REQUEST[$this->controller], $this->all_methodes);
       $init['used_methode'] = is_int($key) ? $this->all_methodes[$key] : false;

       // populate the postData & getData arrays
       if($init['used_methode']) {

           // post exists, but could be blank;
           if ($this->input->post) {
               foreach($this->input->post as $key => $val) {
                   $key = strtolower($this->sanitizer->fieldName($key));
                   $val = $this->sanitizer->text($val);
                   $init['postData'][$key] = $val;
                   $init['requestData'][$key] = $val;
               }
           }

           // get exists, but could be blank;
           if ($this->input->get) {
               foreach($this->input->get as $key => $val) {
                   $key = strtolower($this->sanitizer->fieldName($key));
                   $val = $this->sanitizer->text($val);
                   $init['getData'][$key] = $val;
                   $init['requestData'][$key] = $val;
               }
           }
       }

       // set & overwrite (manipulated) defaults to $this
       foreach($init as $key => $value) $this->set($key, $value);

       // when nothing todo $controller = "nothingToDo".
       if($this->used_methode) {
           $this->addHookAfter('Page::render', $this, $this->used_methode);
       } else {
           $text['error'] = "{$_REQUEST[$this->controller]} is not a usable methode in {$this->config->urls->modules}{$this->className}.module";
           $this->set('messages', $text);
           return false;
       }
   }

   /**
    * controller value has past the test, so now we know what to handle.
    *
    */

   protected function changePassword($event) {
       echo 'changePassword';
   }

   // listen to get
   protected function confirmRegister() {
       echo 'confirmRegister';
   }

   protected function forgotPassword() {
       echo 'forgotPassword';
   }

   /**
    *
    * Login
    *
    * --------------------------------------------------------------------------------- *
    *     *name="username" may have the value of the members email address
    *
    *     <form action="./" method="POST">
    *         <input type="text" name="username" /> *
    *         <input type="text" name="password" />
    *         <input type="hidden" name="controller" value="login" />
    *         <button type="submit">submit</button />
    *     </form>
    *
    */

   protected function login() {

       // exit when already loggedin
       if ($this->loggedin) return true;

       // clean it again with username sanitizer / don't know if needed
       $name = $this->sanitizer->username($this->postData['username']);
       $pass = $this->postData['password'];

       if (empty($name) || empty($pass)) {

// this here is not working:

           $error = $this->_('One or more fields are empty');
           $text['error'] = $this->_('One or more fields are empty');
           $this->set('messages', $text);

           return false;
       }

       // check if user logging in with email
       $u =  $this->users->get("email=$name");
       if($u->get('id') > 0) {
           if( $u->hasRole('front-member')) {
               $name = $u->name;
           }
       }

       $u = $this->users->get("name=$name");
       // returns 0 or the ID ( 0 means false )
       if(!$u->get('id')) {
           echo $this->_('I think you made a typo');
           return false;
       }

       if(!$u->hasRole('front-member')) {
           echo $this->_('Your account is non active');
           return false;
       }

       $now = time();
       $database = $this->fuel('db');
       $name = $database->escape_string($name);
       $result = $database->query("SELECT attempts, last_attempt FROM session_login_throttle WHERE name='$name'");

       $allowAccess = ($result->num_rows == 0) ? true : false;
       $blocked = $u->hasRole("blocked") ? true : false;

       if(!$allowAccess && !$blocked) {

           list($attempts, $lastAttempt) = $result->fetch_row();
           if($attempts > $this->attempts) {
               $u->setOutputFormatting(false);
               $u->removeRole("front-member");
               $u->addRole("blocked");
               $u->save();
               $u->setOutputFormatting(true);
               $database->query("DELETE FROM session_login_throttle WHERE name='$name'");
               if(!empty($this->email)) $this->sendNotificationEmail($u);
               echo $this->_('Your account is set to non active');
               return false;
           }

           $elapsedSeconds = $now - $lastAttempt;
           $requireSeconds = ($attempts * $attempts) * $this->seconds ;
           $allowAccess = $elapsedSeconds < $requireSeconds ? false : true;
           $attempts++;

           if(!$allowAccess) {
               $database->query("UPDATE session_login_throttle SET attempts=$attempts, last_attempt=$now WHERE name='$name'");
               echo sprintf($this->_("Please wait at least %d seconds before attempting another login."), $requireSeconds);
           } else {
               // session_login_throttle won't delete entries on it's own ( is this intended ? )
               $database->query("DELETE FROM session_login_throttle WHERE name='$name'");
           }

       }

       if ($allowAccess) {
           $u = $this->session->login($name, $pass);
           if($u !== null) $this->session->redirect($this->page->url);
       }

   }

   /**
    * 3 ways to logout
    *
    * via get: ?controller=logout
    * via posts: <input type="hidden" name="controller" value="logout" />
    * via urlSegment: /logout/
    *
    */

   public function logout() {
       $this->session->logout();
       $this->session->redirect($this->page->url);
   }

   protected function register() {
       echo 'register';
   }

   protected function resetPassword() {
       echo 'resetPassword';
   }

   protected function updateProfile() {
       echo 'updateProfile';
   }

   // send notification email needs user object
   protected function sendNotificationEmail($user) {

       $headers = "From: ".get_class($this).".module <members@".$this->config->httpHost.">\n";
       $headers .= "MIME-Version: 1.0\n";
       $headers .= "Content-type: text/html; charset=UTF-8\n";
       $headers .= "Reply-To: info@".$this->config->httpHost."\n";
       $headers .= 'X-Mailer: PHP/' . phpversion();

       $subject = "Blocked: {$user->name} on " . $this->config->httpHost;
       $body = "<p>Member: <strong>{$user->name}</strong><br />";
       $body .= "Email: <strong>{$user->email}</strong><br />";
       $body .= "Status: <strong>blocked</strong></p>";
       $body .= "<p>Member {$user->name} blocked by ".get_class($this).".module<br />";
       $body .= "You can uncheck <strong>blocked</strong> and check <strong>front-member</strong> <a href=\"";
       $body .= $this->config->httpHost . $this->config->urls->admin ."access/users/edit/?id={$user->id}\">here</a><br />";
       $body .= "to enable the account again.</p>";

       return mail($this->email, $subject, $body, $headers);
   }

   /**
    * Provide fields for configuring this module
    *
    */

   static public function getModuleConfigInputfields(array $data) {

       /**
        * After install, the input fields in the admin/modules config are not set. So,
        * populate the fields with the data from self::$defaultSettings.
        *
        */

         foreach(self::$defaultSettings as $key => $value) {
             if(!isset($data[$key])) $data[$key] = $value;
         }

        $fields = new InputfieldWrapper();
        $modules = wire("modules");

        $field = $modules->get("InputfieldText");
        $field->attr('name', 'controller');
        $field->attr('size', 15);
        $field->attr('value', $data['controller']);
        $field->label = "input name attribute name (controller)";
        $field->description =
            "Front-Members listen to the specified name & uses it's value as method name. "
            . "example: <input type=\"hidden\" name=\"{$data['controller']}\" value=\"login\" />"
             . " available values: " . implode(', ', $data['all_methodes']) . ". ";
        $fields->append($field);

        $field = $modules->get("InputfieldEmail");
        $field->attr('name', 'email');
        $field->attr('size', 0);
        $field->attr('value', $data['email']);
        $field->label = "email";
        $field->description = 'send a "blocked user message" to this address or leave empty';
        $fields->append($field);

        $field = $modules->get("InputfieldText");
        $field->attr('name', 'f_submit');
        $field->attr('size', 15);
        $field->attr('value', $data['f_submit']);
        $field->label = "Label text for submit field, most likely empty.";
        $field->description = "Label value for label attached to password field";
        $fields->append($field);

        return $fields;
   }

   public function ___install() {

       // adding role
        $role = $this->roles->add('front-member');
        $role->title = "Members role";
        $role->save();

       // adding role
        $role = $this->roles->add('blocked');
        $role->title = "Members blocked role";
        $role->save();

       // create field
       $field = new Field();
       $field->type = $this->modules->get("FieldtypePassword");
       $field->name = 'tmp_pass';
       $field->label = 'temporary password field for front-members';
       $field->save();

       // assign field to user template
       $template = $this->templates->get("user");
       $template->fields->add("tmp_pass");
       $template->fields->save();

//      $sql =
//            "CREATE TABLE `front_members_ban` ( " .
//          "`name` varchar(128) NOT NULL, " .
//          "`ip` varchar(128) NOT NULL, " .
//          "`attempts` int(10) unsigned NOT NULL default '0'," .
//          "`last_attempt` int(10) unsigned NOT NULL," .
//          "PRIMARY KEY (`name`))";
//
//         $this->db->query($sql);
   }

   public function ___uninstall() {

       // delete the role
        $role = $this->roles->get('front-member');
        if ($role->id > 0) $this->roles->delete($role);

       // delete the role
        $role = $this->roles->get('blocked');
        if ($role->id > 0) $this->roles->delete($role);

       // delete field from field group
       $user_tpl = $this->templates->get("user");
       $user_tpl->fields->remove("tmp_pass");
       $user_tpl->fields->save();

       // get rid of tmp_pass field
       $tmp_pass = $this->fields->get("tmp_pass");
        if($tmp_pass->name) $this->fields->delete($tmp_pass);

//       $this->db->query("DROP TABLE IF EXISTS front_members_ban");

   }
}



to try it:

// suppress notices
$output = '';
$username = false;
$password = false;
$controller = false;
// create variable
if($_REQUEST) foreach($_REQUEST as $key => $value) $$key = $value;
// set module data to variable
$data = $modules->get("FrontMembers")->data;
$output .= "<form action='./' method='POST'>\n";
$output .= " <fieldset>\n";
$output .= " <label for='username'>username:</label>\n";
$output .= " <input type='text' id='username' name='username' value='{$username}'>\n";
$output .= " <br />\n";
$output .= " <label for='password'>password:</label>\n";
$output .= " <input type='password' id='password' name='password' value='{$password}'>\n";
$output .= " <br />\n";
$output .= " <select name='controller'>\n";
 foreach($data['all_methodes'] as $methode) {
 $selected = $input->post('controller') == $methode ? " selected='selected'" : '';
 $output .= " <option value='{$methode}'{$selected}>{$methode}</option>\n";
 }
$output .= " <option value='DoingTheDishes'{$selected}>DoingTheDishes</option>";
$output .= " </select>\n";
$output .= " </fieldset>\n";
$output .= " <button type='submit'>submit</button>\n";
$output .= "</form>\n";
$output .= "<hr />";
// see if logged in
foreach($session as $name => $value) $output .= "<p>$name = $value</p>";
$output .= "<hr />";
echo $output;
// just to see what info is available
var_dump($data);

fixed the notices when instal / uninstall

Edited by Martijn Geerts
Link to comment
Share on other sites

OOOOOps... quite the opposite, quite a beast! Still way to go. ;)

I don't think I will install this though. :D

Do you get any errors when using this? Debug mode?

Not sure really. My bet would be to try make the login method "public function login()"?

Link to comment
Share on other sites

Have a look at the templates-admin/default.php and notices.inc $notices are the messages set with $this->message(str) and $this->error(str) I think you could use this session flash of PW for throwing messages.

Link to comment
Share on other sites

$this->message('thank you Soma');
object(Notices)[8]
 protected 'data' =>
   array
  0 =>
    object(NoticeMessage)[168]
	  protected 'data' =>
	    array
		  'text' => string 'thank you Soma' (length=14)
		  'class' => string 'FrontMembers' (length=12)
		  'timestamp' => int 1346793966
		  'flags' => int 0
	  protected 'localHooks' =>
  • Like 1
Link to comment
Share on other sites

Ah there's a hookAfter Page::render!? :D

I think you could be right. This would return the rendered page code with the hook $event. I see you're not using it at all.

If a hook like this it should be

protected function login(HookEvent $event) {
 // $event->return would be the html string rendered
 return $event->return;
}

You have to try if addHookBefore("Page::render", $this, ... ); would work in that case. Not sure what would be best in your case here.

protected function login(HookEvent $event) {
 // $event->object would be the page object getting rendered
 $page = $event->object;
   ...do you stuff...
}
Link to comment
Share on other sites

from text apeisa wrote, There's no methode render in the class Page, but there is sucha thing though, he said... ( I don't know cause this is my first OOP project ever ) But I think he is right. And I learned alot from his code, some of it should go in the wiki I think. :-)

About the hooks, it's still a bit tenuous for me what it does. And how to handle with it.

your example:

protected function login(HookEvent $event) {
 // $event->return would be the html string rendered
 return $event->return;
}

HookEvent is that a static somewhere divined, or is it a class.... & $event, is that the $this... ???

Man, lack of knowledge here...

Big thanks Soma for all your help....

Link to comment
Share on other sites

I think apeisa or maybe it was originally from Ryan meant

$page->addHookAfter("render", $this, 'myFunc');

Will add a hook to the one $page render method.

$this->addHookAfter("Page::render", $this,'myFunc');

Does add a hook to the render to ALL pages (admin, frontend...). So you would want to limit it to the context you want, using either what Page or template or path or whatever.

protected function login(HookEvent $event) { ... }

HookEvent is the type of the event (it's good pratice to add it) it will make sure the $event argument is of the right type.

However what you get with $event depends on what you are hooking actually and how and where. What class and what method.

So in this case hook after Page::render, $event->return will hold a string with the html being rendered. $event->object will be the page object that is rendered.

In case of Inputfield::render, $event->return would be the string of an inputfield's html that is being rendered (all Inputfields that's gonna render in the admin for example will call render, thus also your hook). $event->object would be the current Inputfield object.

There's many more but would go to far to write and list all, actually I don't know them all out of my head.

EDIT: Somebody correct me if I'm wrong please ;)

  • Like 2
Link to comment
Share on other sites

Also wanted to add that..

When hooking after a render method of some class, $event->return returns the markup string that's getting rendered. You then can modify it in some way using string functions. But you actually don't need to do a "return $event->return;" at the end. Simply adding or modifying $event->return will do the magic.

$event->return .= "som code"; 
//or
$event->return = str_replace("</body>","<p>Hello</p></body>",$event->return);

Hooking before a Page::render will give you chance to get the page object and do modifications, whatever.. but it will not have the markup yet. So $event->return is not of much use there as it will get overwritten.

  • Like 1
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...