Jump to content

[SOLVED] Module error (first steps) - what's wrong?


Gadgetto
 Share

Recommended Posts

I followed some sample modules to start my first project. The module installs/uninstalls fine but when I click the module's page I get the following error:

Fatal Error: Uncaught TypeError: Argument 1 passed to ProcessWire\ProcessController::getProcessMethodName() must be an instance of ProcessWire\Process, instance of ProcessWire\GoodNews given, called in /Users/mgartner/ProjekteWEB/processwire/wire/core/ProcessController.php on line 324 and defined in /Users/mgartner/ProjekteWEB/processwire/wire/core/ProcessController.php:260
Stack trace:
#0 /Users/mgartner/ProjekteWEB/processwire/wire/core/ProcessController.php(324): ProcessWire\ProcessController->getProcessMethodName(Object(ProcessWire\GoodNews))
#1 /Users/mgartner/ProjekteWEB/processwire/wire/core/Wire.php(380): ProcessWire\ProcessController->___execute()
#2 /Users/mgartner/ProjekteWEB/processwire/wire/core/WireHooks.php(723): ProcessWire\Wire->_callMethod('___execute', Array)
#3 /Users/mgartner/ProjekteWEB/processwire/wire/core/Wire.php(442): ProcessWire\WireHooks->runHooks(Object(ProcessWire\ProcessController), 'execute', Array)
#4 /Users/mgartner/ProjekteWEB/processwire/wire/core/admin.php(135): ProcessWire\Wire->__ca (line 260 of /Users/mgartner/ProjekteWEB/processwire/wire/core/ProcessController.php) 

This error message was shown because: you are logged in as a Superuser. Error has been logged.

Here is the full source:

<?php namespace ProcessWire;

/**
 * GoodNews module
 *
 * An integrated group and newsletter mailing system for Processwire.
 * 
 * This file is licensed under the MIT license
 * https://processwire.com/about/license/mit/
 * 
 * ProcessWire 3.x, Copyright 2016 by Ryan Cramer
 * https://processwire.com
 *
 */

class GoodNews extends WireData implements Module {
    
	const debug = false; 
	const pageName = 'goodnews';
	const minVersionPHP = '5.6.37';

	/**
	 * Required by all modules to tell ProcessWire about them
	 *
	 * @return array
	 */
    public static function getModuleinfo() {
        return array(
            
			// The module's title, typically a little more descriptive than the class name
            'title' => 'GoodNews',
        
			// A brief description of what this module is
            'summary' => 'An integrated group and newsletter mailing system.',
        
        	// Module version number: use 1 for 0.0.1 or 100 for 1.0.0, and so on
        	'version' => 1, 
        
        	// Name of module author
            'author'  => 'Martin Gartner, bitego',
        
			// Optional URL to more information about the module
        	'href' => 'http://modules.processwire.com/goodnews', 
        
			// singular=true: indicates that only one instance of the module is allowed.
			// This is usually what you want for modules that attach hooks. 
			//'singular' => true, 

			// autoload=true: indicates the module should be started with ProcessWire.
			// This is necessary for any modules that attach runtime hooks, otherwise those
			// hooks won't get attached unless some other code calls the module on it's own.
			// Note that autoload modules are almost always also 'singular' (seen above).
			//'autoload' => true, 
		        
        	// For more options that you may specify here, see the file: /wire/core/Process.php
        	// and the file: /wire/core/Module.php

        );
    }
    
    public function execute() {
        
		if (version_compare(PHP_VERSION, self::minVersionPHP) >= 0) {
			// good
		} else {
			$this->error("Please note that your current PHP version (" . PHP_VERSION . ") is not adequate to run this module."); 
        }
        
        $out = 'Test';

		return $out; 

    }

	/**
	 * Executed on install
	 */
	public function ___install() {

		// Create the page the module will be assigned to
		$page = new Page();
		$page->template = 'admin';
		$page->name = self::pageName; 

		// Installs to the admin main menu
		$page->parent = $this->pages->get($this->config->adminRootPageID);  //->child('name=setup');
		$page->process = $this; 

		// Page title is the same as our module title
		$info = self::getModuleInfo();
		$page->title = $info['title'];

		// Save the page
		$page->save();

		// Tell the user we created this page
		$this->message("Created Page: {$page->path}"); 
	}

	/**
	 * Executed on uninstall
	 */
	public function ___uninstall() {

		// Find the page we installed, locating it by the process field (which has the module ID)
		// It would probably be sufficient just to locate by name, but this is just to be extra sure.
		$moduleID = $this->modules->getModuleID($this); 
		$page = $this->pages->get("template=admin, process=$moduleID, name=" . self::pageName); 

		if($page->id) {
			// If we found the page, let the user know and delete it
			$this->message("Deleting Page: {$page->path}"); 
			$page->delete();
		}
	}

}

 

Any hints?

Thanks,
Martin

Link to comment
Share on other sites

I think you are mixing ProcessModules with Other modules.

The class skeleton of a process module has to look like this:

class ProcessGoodNews extends Process implements Module {
...

First add the prefix "Process" to your modules classname and also to the filename, and second you have to extend Process and not WireData.

 

PS: the title can stay as is, Good News, or GoodNews, but the class name and filename should be prefixed with Process.

PPS: I think you also have to prefix the execute() function name by three underscores: ___execute() < Thats wrong, as @teppo mentioned below. Sorry.

PPPS: maybe some interesting reads about ProcessModules and different possibilities:
https://processwire.com/blog/posts/building-custom-admin-pages-with-process-modules/
https://processwire.com/blog/posts/new-module-configuration-options/
https://processwire.com/talk/topic/13618-does-using-dedicated-module-files-help-a-lazy-programmer/

 

Edited by horst
add another hint and links
  • Like 4
Link to comment
Share on other sites

Also take a look at Ryan's helpful ProcessHello demo module: https://github.com/ryancramerdesign/ProcessHello

It's a lot simpler to use getModuleInfo() (or its equivalent if using the other module configuration options Horst linked to above) to specify the page used by the Process module because then it will be automatically created on module install and removed on module uninstall. See the ProcessHello example: https://github.com/ryancramerdesign/ProcessHello/blob/9c1aa18eb40d069c7fb227f09badddc90f0b3276/ProcessHello.info.php#L41-L46

  • Like 3
Link to comment
Share on other sites

31 minutes ago, horst said:

PPS: I think you also have to prefix the execute() function name by three underscores: ___execute()

That isn't actually necessary; Process module execute methods don't have to be hookable.

(Gadgetto, in case you haven't yet looked into the hook system, three underscores are only required if you want to make the function hookable – i.e. allow code in template files, modules, init.php / ready.php files within site directory, etc. to "hook" into their execution. Otherwise it's fine to leave them out.)

On a loosely related note, you also don't have to set up your own PHP version comparison. You can define required PHP version with the "requires" setting ?

  • Like 3
Link to comment
Share on other sites

Below is part of the source from the pre-installed Helloworld module which comes with Processwire 3.x:

It has no prefixed class name and no prefixed file name. It also extends WireData and implements Module. I built my module exactly like this but it won't work.

 

<?php namespace ProcessWire;

/**
 * ProcessWire 'Hello world' demonstration module
 *
 * Demonstrates the Module interface and how to add hooks.
 * 
 * See README file for further links regarding module development.
 * 
 * This file is licensed under the MIT license
 * https://processwire.com/about/license/mit/
 * 
 * ProcessWire 3.x, Copyright 2016 by Ryan Cramer
 * https://processwire.com
 *
 */

class Helloworld extends WireData implements Module {

	/**
	 * getModuleInfo is a module required by all modules to tell ProcessWire about them
	 *
	 * @return array
	 *
	 */
	public static function getModuleInfo() {

		return array(

			// The module's title, typically a little more descriptive than the class name
			'title' => 'Hello World', 

			// version number 
			'version' => 3, 

			// summary is brief description of what this module is
			'summary' => 'An example module used for demonstration purposes.',
			
			// Optional URL to more information about the module
			'href' => 'https://processwire.com',

			// singular=true: indicates that only one instance of the module is allowed.
			// This is usually what you want for modules that attach hooks. 
			'singular' => true, 

			// autoload=true: indicates the module should be started with ProcessWire.
			// This is necessary for any modules that attach runtime hooks, otherwise those
			// hooks won't get attached unless some other code calls the module on it's own.
			// Note that autoload modules are almost always also 'singular' (seen above).
			'autoload' => true, 
		
			// Optional font-awesome icon name, minus the 'fa-' part
			'icon' => 'smile-o', 
			);
	}

	/**
	 * Initialize the module
	 *
	 * ProcessWire calls this when the module is loaded. For 'autoload' modules, this will be called
	 * when ProcessWire's API is ready. As a result, this is a good place to attach hooks. 
	 *
	 */
	public function init() {

		// add a hook after the $pages->save, to issue a notice every time a page is saved
		$this->pages->addHookAfter('save', $this, 'example1'); 

		// add a hook after each page is rendered and modify the output
		$this->addHookAfter('Page::render', $this, 'example2'); 

		// add a 'hello' method to every page that returns "Hello World"
		// use "echo $page->hello();" in your template file to display output
		$this->addHook('Page::hello', $this, 'example3'); 

		// add a 'hello_world' property to every page that returns "Hello [user]"
		// use "echo $page->hello_world;" in your template file to display output
		$this->addHookProperty('Page::hello_world', $this, 'example4'); 
	}

	.....
	...
	.
}

 

Link to comment
Share on other sites

14 hours ago, horst said:

I think you are mixing ProcessModules with Other modules.

Agree

@Gadgetto what is your goal? What do you want to build? If we knew that it would be easier to help you.

 

You have 3 main options to customize ProcessWire:

 

  • Like 1
Link to comment
Share on other sites

Is there an overview in which case a module should use which class and which implementation model?

Samples:

class ProcessWireUpgrade extends Process { // extends Process

class Helloworld extends WireData implements Module { // extends WireDate

class CustomAdminPage extends Process { // without prefix "Process"

class ProcessCustomAdminPage extends Process { // prefixed with "Process"

 

 

Link to comment
Share on other sites

6 minutes ago, bernhard said:

Agree

@Gadgetto what is your goal? What do you want to build? If we knew that it would be easier to help you.

 

You have 3 main options to customize ProcessWire:

 

Hello @bernhard

ragarding my other post: 

I'm starting the port of my MODX add-on GoodNews - a integrated group and newsletter mailing system - to Processwire.

The add-on will be a full featured app which willl have custom admin pages, modules for sending mails, and so on ...

As I'm just scratching the surface of Processwire, I can't say which module types I will need.

 

Link to comment
Share on other sites

I have now tried to get more information about different module types and when to use what.

So, I try to port my MODX add-on - a complete newsletter system with subscriber management and registration.

As far as I understand, ProcessWire has "Regular" modules and "Process" modules. Process modules, if I understand correctly, are used to create custom admin areas in the backend. "Regular" modules for all other things, like output in frontend, hooks, services, mail dispatch etc.

Therefore I will probably need several different modules to implement my project:

1) Process module for the admin part of the newsletter add-ons (newsletter creation, mailing, subscriber management etc.)

2) Regular modules for mail handling / sending engine etc.

3) Regular modules for subscription forms and user profile editing by subscribers

Am I right about that? @bernhard, @teppo, @horst

Link to comment
Share on other sites

4 minutes ago, Gadgetto said:

Regular modules for subscription forms and user profile editing by subscribers

1 + 2 yes, but this one sounds strange. But it depends a lot on how you plan everything.

I'd start with a simpler module first to get familiar with module development. This one would be a nice project to start with:

You'd have some user input (teaser: image uploads can be tricky), some methods to generate markup, http requests via the API, but not all the complexity that you have in your full blown module.

I'd always be available for help on the road ?

 

  • Like 1
Link to comment
Share on other sites

Thanks a lot, @bernhard I'll have a look at your hints + I'll for sure come back with more questions. ?

As I wrote my GoodNews add-on for MODX I also jumped into cold water and started development immediately. The problem is not so much in the API as in how to do things in ProcessWire.  

Link to comment
Share on other sites

15 minutes ago, Gadgetto said:

Thanks a lot, @bernhard I'll have a look at your hints + I'll for sure come back with more questions. ?

As I wrote my GoodNews add-on for MODX I also jumped into cold water and started development immediately. The problem is not so much in the API as in how to do things in ProcessWire.  

That's exactly the point. You might regret it. Doing such a complex project without experience is never a good idea.

  • Like 3
Link to comment
Share on other sites

  • 3 years later...

I stumbled across this post searching for the reason why my module won't create the process page under setup. I tried some suggestions from this threat, but eventually found another solution. I just wanted to share this in case someone needed it.

I used the getModuleInfo() function to add a page. I did not prefix my modules name with "Process" but only extended it with the Progress class. The only thing I had to do was calling the parents install() method in my modules install() method. That`s it. Now the setup page is created automatically on install.

<?php namespace ProcessWire;

class MyModule extends Process implements ConfigurableModule {
    public static function getModuleInfo() {
        return [
        'title' => 'My Module',
        'summary' => 'A module',
        'version' => 1,
                'page' => array(
                    'name' => 'mymodule',
                    'parent' => 'setup',
                    'title' => 'My Module',
                )
        ];
    }

    public function install() {
		parent::___install();
    }

    public function uninstall() {
		parent::___uninstall();
    }
}

 

  • Like 2
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...