Martijn Geerts Posted September 4, 2012 Share Posted September 4, 2012 (edited) 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 September 4, 2012 by Martijn Geerts Link to comment Share on other sites More sharing options...
Soma Posted September 4, 2012 Share Posted September 4, 2012 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 More sharing options...
Martijn Geerts Posted September 4, 2012 Author Share Posted September 4, 2012 (edited) 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 September 4, 2012 by Martijn Geerts Link to comment Share on other sites More sharing options...
Soma Posted September 4, 2012 Share Posted September 4, 2012 OOOOOps... quite the opposite, quite a beast! Still way to go. I don't think I will install this though. 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 More sharing options...
Martijn Geerts Posted September 4, 2012 Author Share Posted September 4, 2012 NO errors in debug mode, no notices. Don't know, gonna try the public function ( thought I don't like to have it public, cause it needs init to initialize first ) lol, you're right about error , gonna fix those install errors first Link to comment Share on other sites More sharing options...
Martijn Geerts Posted September 4, 2012 Author Share Posted September 4, 2012 After watching the formbuilder video, I get the idea of putting the error messages in a "hidden" inputField. Gonna try that later... Link to comment Share on other sites More sharing options...
Soma Posted September 4, 2012 Share Posted September 4, 2012 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 More sharing options...
Martijn Geerts Posted September 4, 2012 Author Share Posted September 4, 2012 $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' => 1 Link to comment Share on other sites More sharing options...
Martijn Geerts Posted September 5, 2012 Author Share Posted September 5, 2012 oké, I think (not able to test now) that the problem lays in: $this->addHookAfter('Page::render', $this, $this->used_methode); Maybe need the addHookBefore. Link to comment Share on other sites More sharing options...
Soma Posted September 5, 2012 Share Posted September 5, 2012 Ah there's a hookAfter Page::render!? 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 More sharing options...
Martijn Geerts Posted September 5, 2012 Author Share Posted September 5, 2012 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 More sharing options...
Soma Posted September 5, 2012 Share Posted September 5, 2012 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 2 Link to comment Share on other sites More sharing options...
Martijn Geerts Posted September 5, 2012 Author Share Posted September 5, 2012 This is very very good info... pity that i have to work now, gonna figure it out later... tnx Link to comment Share on other sites More sharing options...
Soma Posted September 5, 2012 Share Posted September 5, 2012 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. 1 Link to comment Share on other sites More sharing options...
Martijn Geerts Posted September 6, 2012 Author Share Posted September 6, 2012 Had no time till now to check it all out... It was indeed the wrong hook i Had... Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now