ryancramerdesign / ProcessWire

Our repository has moved to https://github.com/processwire – please head there for the latest version.
https://processwire.com
Other
728 stars 201 forks source link

$modules->find() throws an exception because of module permissions #1071

Closed apeisa closed 9 years ago

apeisa commented 9 years ago

It seems I cannot do simple find for modules. I am trying to list all inputfields there are available, but this code throws errors for all other's but superuser:

foreach ($modules->find("name^=Inputfield") as $inputfield) {
  // nothing here yet
}

The error I get is this:

#0 /wire/core/Modules.php(919): Modules->getModule('ProcessPageList')
#1 /wire/modules/Inputfield/InputfieldPageListSelect/InputfieldPageListSelect.module(19): Modules->get('ProcessPageList')
#2 /wire/core/Modules.php(441): InputfieldPageListSelect->init()
#3 /wire/core/Modules.php(1012): Modules->initModule(Object(InputfieldPageListSelect), false)
#4 /wire/core/Modules.php(919): Modules->getModule('InputfieldPageL...')
#5 /wire/core/Modules.php(1128): Modules->get('InputfieldPageL...')
#6 /commonsense/sensesite/templates/ui/index.php(11): Modules->find('name^=Inputfiel...')
#7 /wire/core/TemplateFile.php(169): require('/commonsense/se...')
#8 [internal function]: TemplateFile->___render()
#9 /var/www/htm in <b>/index.php</b> on line <b>252</b><br />

So it seems that InputfieldPageListSelect loads the ProcessPageList module, which has page-edit permission set.

In this case I think it's fine to whitelist/blacklist inputfields I am looking, but I find it little problematic, that simple find for modules can throw an exception.

ryancramerdesign commented 9 years ago

Looks like the InputfieldPageListSelect modules are calling ProcessPageList in their init() method, when they should instead do it in their render() method. I have fixed that locally and it'll be in this weeks commits. Thanks.

Depending on the scenario, it's not great to use $modules->find(), especially for something like Inputfield or Process modules, because it instantiates all the modules it returns. It's better to iterate $modules directly, because any modules that aren't already loaded will be ModulePlaceholder classes, which don't consume any overhead, load other modules, or populate styles/scripts, etc. So in your case you'd want to do this, to list out all Inputfield modules, for example:

foreach($modules as $module) {
  if(strpos($module->className(), 'Inputfield') === 0) {
    echo "<li>" . $module->className() . "</li>";
  }
}

Also, this is good timing because just last week I added a new method to $modules that probably suits your needs well:

foreach($modules->findByPrefix('Inputfield') as $name) {
  echo $name;
}

It returns an array of strings of module class names, unless you specify a second argument of true, in which case it returns instantiated modules (which you probably don't want).

apeisa commented 9 years ago

Thanks Ryan, findByPrefix works great!