Hani Posted April 11, 2012 Share Posted April 11, 2012 I'd like to add some functions to $user. For example I'd like to be able to do the following: $user->sendThankYou(); I tried creating the following module: class UserExtended extends User implements Module{ public static function getModuleInfo() { return array( 'title' => 'Extended User Module', 'version' => 100, 'summary' => 'Extends Processwire\'s Core User Module', 'singular' => true, 'autoload' => true ); } public function sendThankYou() { // Do something } } But I get the following error: Class UserExtended contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (Module::init) (line 18 of /home/hani/public_html/site/modules/UserExtended.module) At that point, I thought, "Of course. "User" isn't a really a module. It's not in the Modules list. It extends Page." I'd really appreciate any direction on how to do this. Link to comment Share on other sites More sharing options...
netcarver Posted April 11, 2012 Share Posted April 11, 2012 If you are implementing a module you need to provide a method called "init". If you take a look at an existing module, you should see what arguments are needed for that function. Link to comment Share on other sites More sharing options...
apeisa Posted April 11, 2012 Share Posted April 11, 2012 /site/modules/UserExtension.module <?php class UserExtension extends WireData implements Module { public static function getModuleInfo() { return array( 'title' => 'User Extension', 'version' => 101, 'summary' => 'Extends $user object.', 'singular' => true, 'autoload' => true, ); } public function init() { $this->addHook('User::sendThankYou', $this, 'sendThankYou'); } public function sendThankYou($event) { $user = $event->data['object']; $event->return = "Thank you, $user->name"; } } Usage is dead simple: <?php echo $user->sendThankYou() ?> 3 1 Link to comment Share on other sites More sharing options...
ryan Posted April 11, 2012 Share Posted April 11, 2012 I suggest not extending the User class, and instead plugin to it with a module class UserExtended extends WireData implements Module { public static function getModuleInfo() { /* return your array here */ } public function init() { $this->addHook('User::sendThankYou', $this, 'sendThankYou'); public function sendThankYou($event) { /* do something */ } } The above would add a sendThankYou method to all User instances. Your sendThankYou method can gain access to the $user the method was called on like this: $user = $event->object; Your sendThankYou method can also have one or more arguments if you want it to: $arg = $event->arguments[0]; If you want your sendThankYou method to return a value, do it like this: $event->return = 'value you want to return'; Looks like Antti beat me to it. 5 Link to comment Share on other sites More sharing options...
apeisa Posted April 11, 2012 Share Posted April 11, 2012 Looks like Antti beat me to it. Haha, I knew I had to be fast, this was such a great question. I don't want anyone to believe building modules for PW is hard, it's not. 3 Link to comment Share on other sites More sharing options...
Hani Posted April 11, 2012 Author Share Posted April 11, 2012 Ah ha! Thanks guys! This is fantastic and really helps me to make better modules with better integration. Thanks, again. 1 Link to comment Share on other sites More sharing options...
Soma Posted April 11, 2012 Share Posted April 11, 2012 And I was not here! Very nice example of usage of ProcessWire modules. Even after months, I love it! 2 1 Link to comment Share on other sites More sharing options...
Martin Muzatko Posted September 11, 2017 Share Posted September 11, 2017 Hello! I started to extend my user using a new class. All works fine, I am a little unfamiliar with the $event system, (Why can't we just have usual return values? This would make exiting a function at the right time a lot easier. Also plain function arguments would let me allow to better understand how to pass the $event to other functions) but it works. Now I want to re-use existing functions in other functions of the same class and it just does not work. The other functions in the same class are not callable and have - you guessed it - no return values. public function init() { $this->addHook('User::getMessages', $this, 'getMessages'); $this->addHook('User::getMessagesBySender', $this, 'getMessagesBySender'); } public function getMessages($event) { $user = $event->object; $event->return = $this->pages->find('template=message, receiver='.$user); } public function getMessagesBySender($event) { $user = $event->object; $sender = $event->arguments[0]; $event->return = $this->getMessages($event)->find('sender='.$sender); } What can I do to get the return values of other hooked methods? If I var_dump($this->getMessages($event)); I get NULL. How should I go about this? Are there maybe better methods of extending the user class in 2017? As you can see, getMessages is both a function I want to re-use, but also a hooked function. Thank you in advance! Link to comment Share on other sites More sharing options...
bernhard Posted September 11, 2017 Share Posted September 11, 2017 hi @Martin Muzatko i would recommend you read the docs about hooks carefully: https://processwire.com/api/hooks (especially here: https://processwire.com/api/hooks/#add_new_method ) to your problem: try this: public function getMessagesBySender($event) { $user = $event->object; $sender = $event->arguments[0]; $event->return = $user->getMessages()->find('sender='.$sender); } you could also modify your getMessages method to take an argument as selector and then use it like this: $user->getMessages("sender=$user"); // additional tip: double quotes makes it easier to read sometimes ;) regarding the "event system": $event in the hooks is the hookevent object. you could call it whatever you want, but as it's called $event everywhere in PW it's good to stay with this naming. the object is needed by PW and it's hook system so you cannot just "return" from inside the method. or to be more clear: you can just return but then it will not change anything. thats the way how you can do early exits: $wire->addHookAfter('Pages::added', function($myHookEvent) { $page = $myHookEvent->arguments(0); if($page->template != 'mytemplate') return; // example of early exit [...] } here i named $event differently just as a showcase. the $event->return property holds the "value" of the hooked method. this can be different things, for example a PageArray if you hook a page find operation or a simple string if you hook a field's value. This value is only one thing that is needed by processwire to fully execute the request. For example there is also the $event->replace property that would tell PW to completely replace the hooked method if it was set to TRUE - so pw would not call the original method after the hook was executed (this only works on before-hooks, of course). https://processwire.com/api/hooks/#replace_method hope this makes sense for you. i would also recommend using tracy debugger - it's a lot more powerful and easier to read than var_dump 5 Link to comment Share on other sites More sharing options...
Martin Muzatko Posted September 13, 2017 Share Posted September 13, 2017 Hi there @bernhard. This totally makes sense I didn't think about that I can already use the $user-> methods in this context. Awesome! I got tracy debugger installed, I just have to bring myself to use it more often Thank you a lot for the help, it is very much appreciated. 2 Link to comment Share on other sites More sharing options...
froot Posted February 25 Share Posted February 25 Though this is very helpful, I am still not sure how this works. I can do stuff like this: On 9/11/2017 at 8:48 AM, Martin Muzatko said: public function init() { $this->addHook('User::getMessages', $this, 'getMessages'); $this->addHook('User::getMessagesBySender', $this, 'getMessagesBySender'); } public function getMessages($event) { $user = $event->object; $event->return = $this->pages->find('template=message, receiver='.$user); } public function getMessagesBySender($event) { $user = $event->object; $sender = $event->arguments[0]; $event->return = $this->getMessages($event)->find('sender='.$sender); } i.e. access the custom public methods of the user object from outside the class. I have also of course no problem accessing private classes within the here discussed user extension class. However, how does the code change when I define and use a public method from inside and from outside the class. Do I need to pass it the $event? Link to comment Share on other sites More sharing options...
da² Posted February 26 Share Posted February 26 @fruid Use custom page classes. In site/classes: <?php namespace ProcessWire; class UserPage extends User { public function getMessages(): PageArray { return wire()->pages->find('template=message, receiver=' . $this->id); } } Be sure to enable it in site/config.php: $config->usePageClasses = true; 4 Link to comment Share on other sites More sharing options...
froot Posted February 27 Share Posted February 27 19 hours ago, da² said: Use custom page classes. I thought extending the user class was not possible since it's a special case and I should use the module approach instead. Has that change in the meantime? Link to comment Share on other sites More sharing options...
da² Posted February 27 Share Posted February 27 Looks like it's a feature since a few years. 1 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