views:

65

answers:

3

I wrote a D6 module which provide user with the ability to communicate, config params and test a 3rdparty API service.
The module works as intended but I want to separate the communicator class and bundle it as foo module. Then pack the rest (admin page) as the foo-ui module. Just like views and views-ui.
I have no idea about what's the best-practices / design patterns to do so. Any idea?

+1  A: 

There is no easy answer. You need to enforce the separation of functionality from the User interface yourself. So you need to put all the APIs of your program in one module and the user interface in another. Write test cases for your API -- using the simpletest module. By writing test cases you are becoming the "consumer" of your APIs. In fact, you can delay the implementation of your UI long enough that you are sure that you have the correct set of functions/classes in the module responsible for "core" functionality.

Also you should explore the CTools module. It gives some useful tools like being able to make exportables and so on.

Drupal does not have a wealth of literature in book form like Java or C# for instance. But PHP does. Check out books on design patterns in PHP. Though I haven't read it, "PHP in action" by Manning seems to have a lot of stuff on precisely the things you're asking.

Another way to do such things is to see how others have done it. The imagecache module is small enough and it separates the UI from functionality (there is a separate Imagecache UI module you need to enable). Why not actually explore the source code of imagecache? [Views is 1 MB+ of source code so its probably not a good idea to explore that just yet :-)]

Sid NoParrots
thank you, I've wrote test cases already for the API and its wrapper which are the core functionality of the module. I thought that there is a specific pattern to separate logic and ui for Drupal modules. thank you again.
Tyla M.
+1 on the answer and +1 on "PHP in Action" by Manning. I also suggest PHP Objects, Patterns, and Practice, Second Edition by Zandra
Mike Munroe
+2  A: 

As I know, there is no specific pattern, but there's always a question:

-- Why should I separate my module's logic and UI into multiple modules? Is that really needed?

It's needed, only if you have developed a module which might accept different UIs just like views and simple views. IMO there is no other reason to do so.

Ok, assuming that our module needs the _ui thing. Here I try to separate the core functionality of a module and its configuration UI as an example. Take a look at Unfuddle API module, it's a pretty tiny and simple module which fits our case. Here is the $ tree ./unfuddle_api:

unfuddle_api/
|-- LICENSE.txt
|-- README.txt
|-- unfuddle_api.classes.inc
|-- unfuddle_api.info
|-- unfuddle_api.install
|-- unfuddle_api.module

0 directories, 6 files

Read its code! The unfuddle_api.install is installing no schema but implementing the hook_uninstall() to delete a few variables using variable_del() on module uninstall. These variables are actually the API connection parameters which will be set in admin page of the module, you might have a few of them in your module, too.
IMO this is a part to be migrated to unfuddle_api_ui module.

The file unfuddle_api.classes.inc is the API wrapper class for unfuddle, it's somehow 3rdparty code wrapped in a class which will be used to instantiate an object.
IMO this should be remained in the core module. But for the sake of design we have to change the constructor method by removing variable_get() calls and setting passed parameters straight to class properties. We'll add them later in .module file.

The file unfuddle_api.module contains the main module code, An implementation of hook_perm() plus one for hook_menu() to create the admin page and a helper function named unfuddle_api_create() which is somehow a Factory helper to create an object from Unfuddle class coded in unfuddle_api.classes.inc.
IMO both hook implementations should be ported to the _ui module. Also the removed variable_get() part of the unfuddle_api.classes.inc discussed above, should be added here in the unfuddle_api_create() function.

So, As an outline: We have a unfuddle_api module which acts as a wrapper for the Unfuddle API class. It provide us all the functionality but no configuration UI. All the configs should be set through the unfuddle_api_create() module in code.
Also we got a unfuddle_api_ui module which depends on unfuddle_api module and if enabled will provide us with the core module configuration in UI.

Hope it helps.

Sepehr Lajevardi
+2  A: 

Also it is usefull for modules that does not use UI offten. Disabling UI saves some resources. I suggest you to check imagecache module as an example. http://drupal.org/project/imagecache

Igor Rodinov
Good example here!
Sepehr Lajevardi