[RFC] - Separate Module Display Function

[RFC] - Separate Module Display Function

by Mike Churchward -
Number of replies: 39
Picture of Core developers Picture of Plugin developers Picture of Testers
Further Separation of module 'view' function:
Provide a new API function [modulename]_view() that returns the display code for the specific module. This display code is HTML in-line code that is included within the body of a page display. It assumes that the HTTP
headers, and the HTML page information (headers, body tags) will be created by the calling chain that calls it.

The benefits of this is that new functionality, such as custom course formats, can include a module display within its own pages. Currently, the only "standard" way of displaying a module is through its 'view.php' stand-alone file, whic displays and entire page.

Function Spec:

 /**
 * Module display function
 *
 * Function to provide the HTML output for displaying this module. The output is assumed to used
 * within a page being constructed elesewhere.
 *
 * @param cmid integer, the current course module id
 * @param [module] object, usually null, but if we have it we pass it to save db access
 * @param cm object, usually null, but if we have it we pass it to save db access
 * @param course object, usually null, but if we have it we pass it to save db access
 */
 function [module]_view($cmid=0, $[module]=NULL, $cm=NULL, $course=NULL) 
Changes:
Every module that wishes to take advantage of this will provide a 'view' function that provided all of the logic the current 'view.php' does, minus the header and footer output. The 'view.php' will then be modified to use this function. Modules that don't have this function will continue to work in the standard way.

Plan:
Modify all standard Moodle modules to use this method.
Post new function spec in developers forum for third party module maintainers.
Release new code into HEAD.

If agreed, we will undertake this immediately.
Average of ratings: -
In reply to Mike Churchward

Re: [RFC] - Separate Module Display Function

by Jeff Graham -
Hi Mike,

This looks like a great start; just a couple comments

  • This should have a $return value that is similar to other moodle functions that outputs the module content directly or returns it as a string depending on the setting so that the course format has more flexibility and can avoid output buffering for more advanced techniques.
  • Optional redirect url that manages where the user is directed after completing any action. Currently I think most go back to the module view or to course/view.php?id=courseid it is reasonable that a course format would need more parameters than just the course id, it would be nice if the course format had more control of the user navigation. default to '' and if empty use existing redirect methods.
  • Form names and html element id names should be unique to the module instance so that multiple modules of the same type (or different) could be displayed on the same page.
  • This should have an optional parameters object that the module can choose to expose for managing the rendering method for multiple different view types. For instance the forum module has 3 or 4 different display modes it would be cool if the code asking for the display could potentially control how the module was displayed as one display method may be more or less appropriate depending on the context it is used in.

Other areas that need consideration, and are marginally related:
  • Course sections: all across the board many different moodle functions are dependant upon the concept of course sections. This is currently limiting the modularity of the course format system. This works great for the existing course formats, but is rather limited in scope.
    • Module creation: currently this is tied to a course section paradigm. This is an issue with course/modedit.php not being modular enough to understand/respect the course formats or only respecting those with the builtin sections.
    • Backup/restore: has course sections built into core backup/restore rather than moved to the course formats that happen to use course sections.
    • course/modedit.php should include hooks into the course format to do whatever the current course format wants to with newly created modules. This is where formats using sections would place the newly created module to the appropriate section.
I bring these points up as they should be included on the roadmap for greater modularity, and because they are related to custom course formats, and you mentioned those wink

Please point out any items I have not clearly described, or need further discussion.

Thanks for jumping in on this. big grin

regards,
Jeff
In reply to Jeff Graham

Re: [RFC] - Separate Module Display Function

by Mike Churchward -
Picture of Core developers Picture of Plugin developers Picture of Testers
Hi Jeff -

You are correct. The intent was to return the display code from the function. I will update the description.

For now, this is just a first step / simple step to separate the view code. The other elements you've discussed really need a broader scope around making course formats more modular and expandable. I think we should set up a page on the dev wiki for this. I will get that started.

mike
In reply to Jeff Graham

Re: [RFC] - Separate Module Display Function

by Mark Nielsen -
Hi Jeff and Mike,

I would just like to add a vote for a way to get the current URL of where the module is being printed. Either pass it as a parameter or ensure that the $PAGE object is set (I think the standard page object has base URL and a way to add parameters? Not entirely sure). This way modules can submit to the same page or go off, do something great and come back.

Anyhoo, looking forward to this new API smile

Cheers,
Mark
In reply to Mike Churchward

Re: [RFC] - Separate Module Display Function

by Tim Hunt -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers
Martin D is currently at the Moodle Moot in Canada, so you may need to wait a day or two for a reply from him.
In reply to Mike Churchward

Re: [RFC] - Separate Module Display Function

by Mike Churchward -
Picture of Core developers Picture of Plugin developers Picture of Testers
Entered into tracker as MDL-9725. Further discussion should be done there.

mike
In reply to Mike Churchward

Re: [RFC] - Separate Module Display Function

by Martín Langhoff -
Is it not a good idea to keep discussion about the API here?

It's not a bug wink, it's of general interest, and you want it searchable as part of developer's design discussions.
In reply to Martín Langhoff

Re: [RFC] - Separate Module Display Function

by Mike Churchward -
Picture of Core developers Picture of Plugin developers Picture of Testers
Hmm... Well, Martin D. indicated to me that he wanted new functionality to be part of the tracker. I'm not sure where the best place is for discussion.

Martin?

mike
In reply to Mike Churchward

Re: [RFC] - Separate Module Display Function

by Mike Churchward -
Picture of Core developers Picture of Plugin developers Picture of Testers
(duplicating this in MDL-9725 as well... still not clear on where the best place is to carry on discussion about this)

Well, after going through every module, I have come to the conclusion that my proposal was far too over-simplified...

There are almost no two modules that handle view.php in the same way. Some such as resource and assignment, use classes to define their display logic. The resource module further complicates it by placing the actual display of the page (header, content, footer) into each extension of the class in a 'display' method. Assignment splits up the display methods into pieces making it easier and uses a 'view' method.

At a very basic level, I think what I need to change is the plan. Originally, I had intended to go into each module and create a [module]_view function that would return the display code, cut what was in 'view.php' and paste it into the new function. While this would work in a few cases, for most it would not achieve the goal, which was to be able to have a module's display code be part of another page.

So, I now think the correct thing to do is to instead create a new function called [module]_get_content (like blocks). No, its not just a name change. This function will have to be custom created for each module to do what the view function does, minus the page setup and close. But, I won't go through and replace the 'view.php' code with this function call. So, this will be available to be used where it exists, but won't impact any existing functions. We can work towards replacing it further on.

Now, that brings up some new considerations...

Should the '_get_content' function handle whether or not the viewer has the right to do this, or should that be left up to whatever's calling it? I'm leaning towards making the '_get_content' low-level, meaning it doesn't care. It just returns what should be displayed regardless of context or capability. Opinions?

I'm also wondering if we shouldn't use this opportunity to create a standard module class with some base methods that need to be present (similar to blocks) instead of adding a new function. Since the proposed function will only be used by new customizations, we can allow any new functions to use the module class instead. We could even duplicate the standard API functions with methods that could be used by new functions. What are the reasons not to do this?

Need some feedback...

mike

In reply to Mike Churchward

Re: [RFC] - Separate Module Display Function

by Michael Penney -
I'm also wondering if we shouldn't use this opportunity to create a standard module class...

YES! plus one from mesmile.
In reply to Mike Churchward

Re: [RFC] - Separate Module Display Function

by Martín Langhoff -

I had intended to go into each module and create a [module]_view function that would return the display code,

Do you mean "return php code to be evaluated"? I don't think that's a good idea -- we'll have to start coding "in strings" which is horrid.

At a very basic level, I think what I need to change is the plan.

Watching the process -- yep, I agree.

So, I now think the correct thing to do is to instead create a new function called [module]_get_content (like blocks).

The blocks approach is very problematic WRT performance.

I'd suggest using functions or a light OOP approach that follows roughly the pattern we have in the "good" pages. If right now we have

  • mod/bla/foo.php -- stuff that needs to happen before we print any HTML, then prints header, foo.html, footer
  • mod/bla/foo.html

We could move to having * $mod->page_foo_prepare() -- stuff that needs to happen before we print html * $mod->page_foo_display() -- returns html * mod/bla/foo.php instantiates the object, calls _prepare(), prints header, prints the output of _display(), prints footer.

A couple of notes...

This won't be trivial because the way we are doing it right now we are counting on foo.php and foo.html to be in the same (global) scope. If we do this with a light OOP approach, we can store var we want to set in _prepare() and use in _display() as an object property. This will lead to better (and safer!) code, but takes a lot fo work!

I really like the idea of moving to OOP modules (w00t!) with one important caveat: let's have the object be the 'module library', able to handle many 'module instances' without making them object instances. This is what we have now in the function-oriented code and it allows us to optimise performance a lot. A purist OOP would instantiate one object per-module-instance but it would lose the scalability we have now. We need to retain the ability to deal with many mod instances with one call that does smart SQL in the background. Otherwise we'll be in a lot of pain performance-wise...

In reply to Martín Langhoff

Re: [RFC] - Separate Module Display Function

by Martín Langhoff -

Part of my post above is messed up... it should say...

We could move to having

  • $mod->page_foo_prepare() -- stuff that needs to happen before we print html
  • $mod->page_foo_display() -- returns html
  • mod/bla/foo.php instantiates the object, calls $mod->page_foo_prepare(), prints header, prints the output of $mod->page_foo_display(), prints footer.
In reply to Martín Langhoff

Re: [RFC] - Separate Module Display Function

by Mark Nielsen -
Hi Martin,

The "good" pages that you are referring to were mostly necessary because Moodle did not have a form API so HTML templates were needed to create forms and the like. Now with the new formslib and methods like print_box() it is very easy to generate all your HTML with PHP.

Further, I think that the above example would still generate a lot of duplicated code and potentially files. The module class should handle all of the steps that foo.php does (EG: default method for printing module headers). It seems to me that with a class definition, you would really only need one file to handle requests and call module methods. This is very similar to Drupal's API where you register methods (AKA pages) and then a specific URL request would be handled by a registered method. I think that the end result would be a reduced and more sustainable code base.

Cheers,
Mark
In reply to Mark Nielsen

Re: [RFC] - Separate Module Display Function

by Martín Langhoff -

The "good" pages that you are referring to were mostly necessary because Moodle did not have a form API

Yes... and no. One of the reasons for the "split" was the forms API, but there is another very important reason that is not going away, and instead getting more important.

As PHP is not buffered one of the most important considerations is "have we sent any HTML yet"? All the cookie setting, redirects, and database work must be done before we show any HTML. Because once we are printing HTML we cannot set http headers, and we cannot call error() safely anymore.

Why can't we call error()? Right now we sometimes do, and it kind of works - but if you are already printing HTML, the partially printed page plus the error() HTML are a tagsoup really. The moment we switch to XHTML strict all those cases (of printing error() when HTML output has started) become bugs as the browser cannot display the error msg Moodle wants to show.

So, thinking about this a bit, you really need a prepare() method that does all the work that must happen before HTML display -- notably, _anything that may fail. And a _display() function that returns html. Probably both need a flag to indicate whether they are being called "alone" for a self-standing page, or in a page that is built from bits of many modules.

If a _prepare() statement is being called as part of a collaborative/mix-of-things page then it cannot set caching headers on its own for example. Or issue a redirect.

(An alternative to dealing with this complexity is to switch wholesale to buffered output, but that has a lot of problems of its own. I prefer this approach, though it's a bit harder.)

In reply to Martín Langhoff

Re: [RFC] - Separate Module Display Function

by Martín Langhoff -

A bit of pseudocode to illustrate.

Say, mod/forum/view.php

   $forum = new modforum;
   // _prepare will read parameters
   // directly from $_GET and $_POST
   // I'm not sure I'm happy with that
   // maybe we should hve a parameter 
   // to force it to read its parameters
   // from elsewhere for mix pages
   $forum->page_view_prepare();
   // _prepare should have set a page title
   // and other bits for the header
   print_headers($forum->page_title);
   print $forum->page_view_display();
   print_footer();

And a mix-modules page

   $modules = array(); 
   // magic here to fill $modules
   // with module class instances
   // and a modid
   // and then...
   foreach ($modules as $mod =>$id) {
        $mod->page_view_prepare($id);
   }
   print_header("mix page!");
   foreach ($modules as $mod =>$id) {
        print $mod->page_view_display($id);
   }
   print_footer();

There's a lot of detail missing -- but it helps me think of the issues that need to be addressed/resolved here...

In reply to Martín Langhoff

Re: [RFC] - Separate Module Display Function

by Mark Nielsen -
Hi Martin,

I'm starting to see some more of your reasoning with your mix-modules page, thanks for posting that.

I think that I would attempt to put everything in your first example into a single module method (EG: page_view_print) and handle it that way, but still leave the _prepare and _display methods for instances like your mix-modules page. It just seems to me that the class should be used as much as possible to do routine tasks (EG: I would think that the first example would be duplicated all throughout the module for the different pages).

Cheers,
Mark
In reply to Martín Langhoff

Re: [RFC] - Separate Module Display Function

by Mark Nielsen -
Hi Martin,

Please trust that I do understand the necessity for doing all of the processing and then output and the reasons for it. I was primarily pointing out that you don't necessarily need to split them in the class definition; just do one before the other.

Cheers,
Mark

EDIT:

Probably both need a flag to indicate whether they are being called "alone" for a self-standing page, or in a page that is built from bits of many modules.

This is a great idea. Perhaps if the flag is passed, things should fail gracefully so other modules get a chance to process any post data or what have you.
In reply to Mark Nielsen

Re: [RFC] - Separate Module Display Function

by Martín Langhoff -

I was primarily pointing out that you don't necessarily need to split them in the class definition; just do one before the other.

Look at my pseudocode examples. Mike wants this to mix stuff from different modules or pages in one page. You have to do all the prepare() part for all the modules/pages first, and only after all the processing is done and nothing has called error() you can do all the HTML printing.

And you want to be able to handle headers/footers yourself too...

How would you approach it with a single method?

Edit: I hadn't seen your other reply smile

In reply to Martín Langhoff

Re: [RFC] - Separate Module Display Function

by Mike Churchward -
Picture of Core developers Picture of Plugin developers Picture of Testers

I had intended to go into each module and create a [module]_view function that would return the display code,

Do you mean "return php code to be evaluated"? I don't think that's a good idea -- we'll have to start coding "in strings" which is horrid.

Sorry. By "display code" I meant the HTML that gets written out. So, HTML suitable for display.

The blocks approach is very problematic WRT performance.

I only mean that I would use a 'get_content' function that returns the displayable HTML. No extra performance hit.

I'd suggest using functions or a light OOP approach that follows roughly the pattern we have in the "good" pages.

What are the "good" pages?

I like the idea of the object being the module library. Now I just have to get that concept clear in my head. I'm assuming that you would see this object having the ability to have many object instances at once, rather than one at a time but reloadable?

mike
In reply to Mike Churchward

Re: [RFC] - Separate Module Display Function

by Mark Nielsen -
I like the idea of the object being the module library. Now I just have to get that concept clear in my head. I'm assuming that you would see this object having the ability to have many object instances at once, rather than one at a time but reloadable?

Hi Mike,

Basically, the class definition should be able to work on multiple module instances without having to instanciate each module instance. The end result is something like block_method_result() in lib/blocklib.php where it is the same as calling a regular function, but it is defined in a class.

So, it seems that the constructor of should have the option of being very light (EG: minimal setup so you can call worker functions) or to be able to create a full module instance with the course module, course, module instance and etc set for normal module use.

Cheers,
Mark

In reply to Mike Churchward

Re: [RFC] - Separate Module Display Function

by Martín Langhoff -
> I only mean that I would use a 'get_content' function that returns the displayable HTML. No extra performance hit.

I don't think you've worked with blocks performance wink

I just checked - the "good pages" are gone sad -- with the advent of formslib we've gained a few things, but lost the distinction of the 2 phases that we work in (see my response to Mark).

> I'm assuming that you would see this object having the ability to have many object instances at once

Well, a good start would be to have the same basic "API" as the modules do now, but with methods instead of functions. If you look at it this way, you get an _instance of the module class_. Terminology is confusing here, because you will use it to work on things we call _module instances_ that won't be of that class.

We'll probably benefit from _also_ having a class that maps directly to the _module instance_ to encapsulate things that you do to one module instance at a time. But we cannot lose the ability to work on module data in large chunks as we do now. And the way we are heading, working with module data in large chunks has to be the main way we do things, rather than an afterthought.
In reply to Martín Langhoff

Re: [RFC] - Separate Module Display Function

by Samuli Karevaara -

"We'll probably benefit from _also_ having a class that maps directly to the _module instance_ to encapsulate things that you do to one module instance at a time. But we cannot lose the ability to work on module data in large chunks as we do now."

True. The OO approach is ideal in the single object case, but all processing of large collections seem to require jumping through hoops (fly weight, iterators etc). In my a solution that is the least "too-abstract" is to have a class for the object ("Book") and another one to represent all of the objects ("Books"). Then the collection class can have things that touch all of the objects, like searches, lists etc.

This is abstract too, as the Books is not just a collection of all of the Book objects sad And it gets more messy with collections of collections smile

Illustration: Ideally a Book object is the only thing that knows about the books database table. But then listing the names of N books requires calling get_name() (or similar) of N objects... Thus a mixture, that OO purists would regard as something between a headache and a nightmare ( :- ) still seems to most efficient and in some way elegant way to go.

In reply to Mike Churchward

Re: [RFC] - Separate Module Display Function

by Martín Langhoff -

Should the '_get_content' function handle whether or not the viewer has the right to do this, or should that be left up to whatever's calling it?

The _prepare() part should do all the footwork of figuring out rights, retrieving the data that we are going to display. _view() should not need to call has_capability(), as _prepare() will have made those calles and set appropriate obj properties tracking that.

There are exceptions though wink

It all maps pretty closely to what we are doing now where we have the page.php and page.html split.

Edit: And yet, as Petr says - I don't think we can change the modules API in the 1.x series... sad unless we can come up with a smart way to make it backwards compatible... maybe?

In reply to Martín Langhoff

Re: [RFC] - Separate Module Display Function

by Mike Churchward -
Picture of Core developers Picture of Plugin developers Picture of Testers
I think we can make it backwards compatible though... We just need to provide the same API that exists now, co-existing with the new one. The API that exists now can just be modified slightly to call the new class methods. See the assignment module for examples (e.g. assignment_update_instance).


In reply to Mike Churchward

Re: [RFC] - Separate Module Display Function

by Mark Nielsen -
Hi All,

Since we are throwing around ideas for the module system API, I would just like to throw out another idea and see what happens. I think it would be nice to only have one Plugins directory. EG: all blocks, authentication types, formats, etc would be installed in one directory.

So, in this plugins directory, the module would somehow register that it would like to plug into the authentication system. Perhaps it sets a config variable or has a specific file defined (EG: the auth class file). Or, lets say it has a block, register that or have a file defined for its blocks. The end result would be a "one stop shopping" for developers and users. Developers can create one module that has a block, activity module and etc and users only have to learn how to install a plugin once because its the same for every kind.

Further, Moodle has a lot of code to manage all of its plugins and with each new plugin, it gets larger (from what I have seen). This would hopefully be a way to create a single plugin system.

Anyhoo, I'm just throwing this out there to see if anyone else has thought of this or if this is just a rash idea ;)

Cheers,
Mark
In reply to Mark Nielsen

Re: [RFC] - Separate Module Display Function

by Mark Nielsen -
Further, Moodle has a lot of code to manage all of its plugins and with each new plugin, it gets larger (from what I have seen). This would hopefully be a way to create a single plugin system.

Just an afterthought, this could basically be solved by providing a way to register a directory as a plugins directory and have admin/index.php call upgrade_plugins() for all registered plugin directories.

Cheers,
Mark
In reply to Mark Nielsen

Module display function: scope too small

by sam marshall -
Picture of Core developers Picture of Peer reviewers Picture of Plugin developers
This post is a bunch of my random thoughts. Sorry smile

I think the planned scope of this change is too small. If changing modules in 2.0 we should do it properly - which is to realise that modules are the same as blocks (they just happen to display differently - but that won't even be true after this change you're suggesting) and create a single interface for both.

I would recommend throwing away both existing interfaces, or keeping them as-is for legacy support but adding a completely new unified interface for all new development. This means all existing code can continue unmodified but core modules/blocks (the important ones) can be implemented using the new system, and obviously features that require the new system will only be available for those blodules (See what I did there?).

I think the idea of having a standard function that prints the 'module display' code is a good idea and leads in to potentially embedding modules within other modules (some teaching content followed by a quick quiz question) although that might be a long way off.

One thing to bear in mind is that the various modules need to have the capacity to create actions which 'know where they are'. For example, let's say I'm at a page using the new magic course view format that includes content from the resourcepage module (whoops, it's OU-specific, but never mind) and I click the eye icon next to an item to hide it.
  • The eye is a form, which posts to a (say) visibility.php in the resourcepage folder. It probably does this using a relative link. Whoops! That won't work any more because the PHP script is coming from /course/view.php. So all these links need to be changed to absolute.
  • Once you get to the form, it probably changes the object visibility in the database then redirects straight back... to resourcepage/view.php. Whoops! This won't work any more because it needs to go to course/view.php. (I trust nobody will suggest using REFERER headers - just don't go there.) There needs to be a standard Moodle way to specify the context (maybe just the part of the path following $CFG->wwwroot) as a form parameter so that we can safely return there.
  • If there is an error then ideally the Continue button would also return to the same context. If we used a standard parameter name for context, then perhaps it would be possible for error() to do this completely automatically.
One other thing is that in order to make a significant difference, modules using this function should receive standard stuff already done for them. For example it should contain parameters $course, $cm, $context (possibly $module but not sure about that) and at least the course access permissions of the user should have already been checked [as mentioned]. However the header should not have been printed, as noted by Martin L. What's more, I know that every time I call print_header I need to use some slightly weird variety of it... If we are making a function that returns stuff then it can simply return a $object like:

$object->content
$object->header->navigation
$object->header->buttons
etc.

(And if the header's already been printed then this is helpfully ignored. As somebody else noted there would need to be a $embedded parameter which told you whether to add your own buttons inside the content.)

By the way apart from using a new function to replace view.php, one possibility is to create a module-display.php script which would be included instead. (Include it, and capture output if needed.) This is a bit more ghetto Moodley but does have some advantages - in particular if it's ever important to display output progressively. (Obviously a function return will always buffer the module's output.)

--sam
In reply to sam marshall

Re: Module display function: scope too small

by Samuli Karevaara -
I think that more sophisticated (and complicated smile ) the proposed API gets, the more it is heading towards Front Controllers and Action Mappings.

To make things extremely interesting the basics could be re-written to use Symfony, for example. evil Now there is a SoC or two for someone smile

(I'm at home, sick and taking care of two sick kids, so use a filter to everything I say this week smile )
In reply to Mike Churchward

Re: [RFC] - Separate Module Display Function

by Mike Churchward -
Picture of Core developers Picture of Plugin developers Picture of Testers
So, just to reign in a bit...

All of these ideas and plans are definitely Moodle 2.0 ones. So, I'm just trying to see if there's anything that we can acheive in 1.x that would allow us to get some or all modules to provide their display content without all of the page goo.

I'm thinking, 'yes', but not in a way that will benefit any of the 2.0 plans. I'm thinking, as a gap solution, implement an optional function (non-OO) for each module (maybe I'll change the name to [module]_get_inline) that if it exists will provide the display output of the module's first page without the page header. This will only be for the first page - the one handled by the first call to view.php - as anything else will require more functionality, parameters, API and design.

As for the 2.0 stuff, I don't see page in the development wiki for this, so maybe we need one? I'll add one in the next little while...

mike

In reply to Mike Churchward

Re: [RFC] - Separate Module Display Function

by Martín Langhoff -

Mike - one thing I realised thinking about this is that the changes I outlined above can be made without OOP, and just on a per-page basis. They are good changes, and they'll make the subsequent change to OOP much easier. It would look like:

 $state = forum_page_bla_prepare();
 print_header();
 forum_page_bla_view($stage);
 print_footer();
In reply to Martín Langhoff

Re: [RFC] - Separate Module Display Function

by Martín Langhoff -
And -- one thing I had forgotten! -- the plan to pull everything into one class file is flawed -- the class file ends up being huge, and we have several code paths in Moodle that load mod/*/lib.php. Those codepaths already eat up a ton of memory - if we moved all the page code into a monolithic class/lib file it'd end up being... oh-yuck!
In reply to Martín Langhoff

Re: [RFC] - Separate Module Display Function

by Mike Churchward -
Picture of Core developers Picture of Plugin developers Picture of Testers
Not sure I follow you on this one...

Why would including a lot of class files be any worse than including the same number of 'lib' files? I don't think we'd want all of the modules in one class file... I would think we'd create one general class file that can be extended by each module. I'ms sure there are a number of functions that can be general enough to be used as is without extension, so wouldn't this actually be smaller in the long run?

mike
In reply to Mike Churchward

Re: [RFC] - Separate Module Display Function

by Martín Langhoff -
Waht I am saying is taht right now modules are relatively lightweight, because there is a good separation between shared "library" code, and specific page code.

So when you include mod/forum/lib.php, it doesn't include the code that is specific to mod/forum/edit.php -- and that's good because you don't need it and loading all the code for a module into memory is a lot wink
In reply to Martín Langhoff

Re: [RFC] - Separate Module Display Function

by Martín Langhoff -
Don't think the above is clear -- typed it heading for the door in a rush mixed So let's rephrase it:

Right now, mod/forum code is split between reusable code in lib.php and not-easily-reusable-code that is page-specific and sits in separate pages. In v1.8, it's 5180 lines in lib.php, 5651 lines in the rest of the files.

This is a good thing -- it keeps Moodle's memory usage reasonable. If we were to pull all that code into lib.php or into an all-encompassing class, we'd see significantly higher memory use (duplicate in this case!), higher costs compiling the shared code (for those not using precompilers), etc.

In reply to Martín Langhoff

Re: [RFC] - Separate Module Display Function

by Mike Churchward -
Picture of Core developers Picture of Plugin developers Picture of Testers
I understand what you're saying, but I suspect that the savings aren't quite as big as you're example... All of the separate forum functions (post.php, view.php, etc.) all include the lib.php file anyway, so there is some savings, but not quite as much as you imply.

It might even be possible for us to separate things into functional groupings... Certainly we might be able to separate into administrative functions, view and read functions, and post and submit functions. Even if we don't use classes, we may want to consider that.

mike
In reply to Mike Churchward

Re: [RFC] - Separate Module Display Function

by Martín Langhoff -

The savings are small if you look at mod/foo/view.php, but very significant when you look at code that walks all the modules. Which is on the rise sad

Off the top of my head - code loops that include all modules' lib.php:

  • cron
  • admin login and visits to /admin
  • course/view course/edit
  • enrol/unenrol
  • new events API can walk lots of modules

And the memory footprint of Moodle nowadays is quite a serious matter.

...Time to start measuring the memory and dbqueries impact of architectural changes if we care about Moodle scalability.

Edit: let's measure it - running

   php  -r 'include "config.php"; \
            print memory_get_usage() . "\n";\
            include "mod/forum/lib.php";\
            print memory_get_usage() . "\n";'

on v1.5 it prints

 5412032 -- getting through lib/setup.php takes 5.4M
 6443648 -- loading forum/lib.php takes an additional 1MB

on v1.8 it prints

 12769800 -- 12MB
 15497664 -- almost 3MB for forum/lib
In reply to Martín Langhoff

Re: [RFC] - Separate Module Display Function

by Martin Dougiamas -
Picture of Core developers Picture of Documentation writers Picture of Moodle HQ Picture of Particularly helpful Moodlers Picture of Plugin developers Picture of Testers
One correction, the new events API does not walk lots of modules (except during a normal Moodle upgrade) ... modules register their handlers in a central table explicitly.

About memory usage, that seems like an extreme increase for mod/forum/lib.php ... when I ran it got a result of 1.7Mb .... perhaps some of that needs to move to locallib.php as well.
In reply to Martin Dougiamas

Re: [RFC] - Separate Module Display Function

by Martín Langhoff -
Fair enough - if module writers get events-happy it will walk modules willy-nilly but that's up to us to behave wink

Re the memory footprint... strange! My test was on my laptop - PHP5.2.1 from ubuntu feisty package, PPC 32bits. Still, I got roughly half the mem footprint from 1.5... ahhh, the olden days of low memory usage, horse-drawn cars and pipe-smoking detectives... smile