Skip to content
This repository has been archived by the owner on Jan 29, 2020. It is now read-only.

Commit

Permalink
Merge branch 'hotfix/38'
Browse files Browse the repository at this point in the history
Close #38
  • Loading branch information
weierophinney committed May 9, 2016
2 parents 26e727e + 26cdc6d commit 0fdef35
Show file tree
Hide file tree
Showing 16 changed files with 609 additions and 517 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
.*.un~
nbproject
tmp/
doc/html/
zf-mkdoc-theme/

clover.xml
composer.lock
Expand Down
13 changes: 13 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,18 @@ branches:
cache:
directories:
- $HOME/.composer/cache
- $HOME/.local
- zf-mkdoc-theme

env:
global:
- EVENT_MANAGER_VERSION="^3.0"
- SERVICE_MANAGER_VERSION="^3.0.3"
- SITE_URL: https://zendframework.github.io/zend-modulemanager
- GH_USER_NAME: "Matthew Weier O'Phinney"
- GH_USER_EMAIL: [email protected]
- GH_REF: github.com/zendframework/zend-modulemanager.git
- secure: ""

matrix:
fast_finish: true
Expand All @@ -29,6 +36,8 @@ matrix:
- php: 5.6
env:
- EXECUTE_TEST_COVERALLS=true
- DEPLOY_DOCS="$(if [[ $TRAVIS_BRANCH == 'master' && $TRAVIS_PULL_REQUEST == 'false' ]]; then echo -n 'true' ; else echo -n 'false' ; fi)"
- PATH="$HOME/.local/bin:$PATH"
- php: 5.6
env:
- EVENT_MANAGER_VERSION="^2.6.2"
Expand Down Expand Up @@ -64,6 +73,10 @@ script:
- if [[ $EXECUTE_TEST_COVERALLS == 'true' ]]; then ./vendor/bin/phpunit --coverage-clover clover.xml ; fi
- if [[ $EXECUTE_TEST_COVERALLS != 'true' ]]; then ./vendor/bin/phpunit ; fi
- if [[ $EXECUTE_CS_CHECK == 'true' ]]; then ./vendor/bin/php-cs-fixer fix -v --diff --dry-run ; fi
- if [[ $DEPLOY_DOCS == "true" && "$TRAVIS_TEST_RESULT" == "0" ]]; then travis_retry curl -sSL https://raw.githubusercontent.com/zendframework/zf-mkdoc-theme/master/theme-installer.sh | bash ; fi

after_success:
- if [[ $DEPLOY_DOCS == "true" ]]; then echo "Preparing to build and deploy documentation" ; ./zf-mkdoc-theme/deploy.sh ; echo "Completed deploying documentation" ; fi

after_script:
- if [[ $EXECUTE_TEST_COVERALLS == 'true' ]]; then ./vendor/bin/coveralls ; fi
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ All notable changes to this project will be documented in this file, in reverse

### Added

- Nothing.
- [#38](https://github.com/zendframework/zend-modulemanager/pull/38) prepares
and publishes the documentation to https://zendframework.github.io/zend-modulemanager/

### Deprecated

Expand Down
53 changes: 53 additions & 0 deletions doc/book/best-practices.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Best Practices when Creating Modules

When creating a ZF2 module, there are some best practices you should keep in mind.

## Keep the `init()` and `onBootstrap()` methods lightweight

Be conservative with the actions you perform in the `init()` and `onBootstrap()`
methods of your `Module` class. These methods are run for **every** page
request, and should not perform anything heavy. As a rule of thumb, registering
event listeners is an appropriate task to perform in these methods. Such
lightweight tasks will generally not have a measurable impact on the performance
of your application, even with many modules enabled. It is considered bad
practice to utilize these methods for setting up or configuring instances of
application resources such as a database connection, application logger, or
mailer. Tasks such as these are better served through the `ServiceManager`
capabilities.

## Do not perform writes within a module

You should **never** code your module to perform or expect any writes within the
module's directory. Once installed, the files within a module's directory
should always match the distribution verbatim. Any user-provided configuration
should be performed via overrides in the `Application` module or via
application-level configuration files. Any other required filesystem writes
should be performed in some writeable path that is outside of the module's
directory.

There are two primary advantages to following this rule. First, any modules
which attempt to write within themselves will not be compatible with phar
packaging. Second, by keeping the module in sync with the upstream distribution,
updates via mechanisms such as git will be simple and trouble-free. Of course,
the `Application` module is a special exception to this rule, as there is
typically no upstream distribution for this module, and it's unlikely you would
want to run this package from within a phar archive.

## Utilize a vendor prefix for module names

To avoid module naming conflicts, you are encouraged to prefix your module
namespace with a vendor prefix. As an example, the developer tools module
distributed by Zend is named "ZendDeveloperTools" instead of simply
"DeveloperTools".

## Utilize a module prefix for service names

If you define services in the top-level service manager, you are encouraged to
prefix these services with the name of your module to avoid conflicts with other
modules' services. For example, the database adapter used by MyModule should be
called "MyModuleDbAdapter" rather than simply "DbAdapter." If you need to share
a service with other modules, remember that the Service Manager "alias" feature
can be used in a merged configuration to override factories defined by
individual modules. Ideally, modules should define their own service
dependencies, but aliases can be configured at the application level to ensure
that common services in individual modules all refer to the same instance.
11 changes: 11 additions & 0 deletions doc/book/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<div class="container">
<div class="jumbotron">
<h1>zend-modulemanager</h1>

<p>
Modular application system for zend-mvc applications.
</p>

<pre><code class="language-bash">$ composer require zendframework/zend-modulemanager</code></pre>
</div>
</div>
1 change: 1 addition & 0 deletions doc/book/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
../../README.md
80 changes: 80 additions & 0 deletions doc/book/intro.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# Introduction to the Module System

Zend Framework 2.0 introduced a new and powerful approach to modules. This new
module system is designed with flexibility, simplicity, and re-usability in
mind. A module may contain just about anything: PHP code, including MVC
functionality; library code; view scripts; and/or public assets such as images,
CSS, and JavaScript. The possibilities are endless.

> ### Event-based system
>
> The module system in ZF2 has been designed to be a generic and powerful foundation from which
> developers and other projects can build their own module or plugin systems.
> For a better understanding of the event-driven concepts behind the ZF2 module system, it may be
> helpful to read the [EventManager documentation](https://zendframework.github.io/zend-eventmanager/).
The module system is made up of the following:

- [The Module Autoloader](https://zendframework.github.io/zend-loader/module-autoloader/) -
`Zend\Loader\ModuleAutoloader` is a specialized autoloader that is responsible
for the locating and loading of modules' `Module` classes from a variety of
sources.
- [The Module Manager](module-manager.md) - `Zend\ModuleManager\ModuleManager`
takes an array of module names and fires a sequence of events for each one,
allowing the behavior of the module system to be defined entirely by the
listeners which are attached to the module manager.
- **ModuleManager Listeners** - Event listeners can be attached to the module
manager's various events. These listeners can do everything from resolving and
loading modules to performing complex initialization tasks and introspection
into each returned module object.

> ### Modules are PHP namespaces
>
> The name of a module in a Zend Framework application is a
> [PHP namespace](http://php.net/namespaces), and must follow all of the same
> rules for naming.
The recommended structure for an MVC-oriented ZF2 module is as follows:

```text
module_root/
Module.php
autoload_classmap.php
autoload_function.php
autoload_register.php
config/
module.config.php
public/
images/
css/
js/
src/
<module_namespace>/
<code files>
test/
phpunit.xml
bootstrap.php
<module_namespace>/
<test code files>
view/
<dir-named-after-module-namespace>/
<dir-named-after-a-controller>/
<.phtml files>
```

## The autoload\_\*.php Files

The three `autoload_*.php` files are not required, but recommended. They provide the following:

- `autoload_classmap.php` should return an array classmap of class name/filename
pairs (with the filenames resolved via the `__DIR__` magic constant).
- `autoload_function.php` should return a PHP callback that can be passed to
`spl_autoload_register()`. Typically, this callback should utilize the map
returned by `autoload_classmap.php`.
- `autoload_register.php` should register a PHP callback (typically that
returned by `autoload_function.php` with `spl_autoload_register()`.

The purpose of these three files is to provide reasonable default mechanisms for
autoloading the classes contained in the module, thus providing a trivial way to
consume the module without requiring zend-modulemanager` (e.g., for use outside
a ZF2 application).
Original file line number Diff line number Diff line change
@@ -1,25 +1,28 @@
# The Module Autoloader

Zend Framework 2 ships with the default module autoloader `Zend\Loader\ModuleAutoloader`. It is a
specialized autoloader responsible for locating and on-demand loading of, the `Module` classes from
a variety of sources.
zend-modulemanager ships with the default module autoloader
`Zend\Loader\ModuleAutoloader`. It is a specialized autoloader responsible for
locating and on-demand loading of, the `Module` classes from a variety of
sources.

## Module Autoloader Usage

By default, the provided `Zend\ModuleManager\Listener\DefaultListenerAggregate` sets up the
`ModuleAutoloader`; as a developer, you need only provide an array of module paths, either absolute
or relative to the application's root, for the `ModuleAutoloader` to check when loading modules. The
`DefaultListenerAggregate` will take care of instantiating and registering the `ModuleAutoloader`
for you.
By default, the provided `Zend\ModuleManager\Listener\DefaultListenerAggregate`
sets up the `ModuleAutoloader`; as a developer, you need only provide an array
of module paths, either absolute or relative to the application's root, for the
`ModuleAutoloader` to check when loading modules. The `DefaultListenerAggregate`
will take care of instantiating and registering the `ModuleAutoloader` for you.

> ## Note
In order for paths relative to your application directory to work, you must have the directive
`chdir(dirname(__DIR__));` in your `public/index.php` file.
> ### Must be in application root
>
> In order for paths relative to your application directory to work, you must
> have the directive `chdir(dirname(__DIR__));` in your `public/index.php` file.
### Registering module paths with the `DefaultListenerAggregate`

The following example will search for modules in three different `module_paths`. Two are local
directories of this application and the third is a system-wide shared directory.
The following example will search for modules in three different `module_paths`.
Two are local directories of this application and the third is a system-wide
shared directory.

```php
// public/index.php
Expand All @@ -29,31 +32,33 @@ use Zend\ModuleManager\ModuleManager;
chdir(dirname(__DIR__));

// Instantiate and configure the default listener aggregate
$listenerOptions = new Listener\ListenerOptions(array(
'module_paths' => array(
$listenerOptions = new Listener\ListenerOptions([
'module_paths' => [
'./module',
'./vendor',
'/usr/share/zfmodules',
)
));
]
]);
$defaultListeners = new Listener\DefaultListenerAggregate($listenerOptions);

// Instantiate the module manager
$moduleManager = new ModuleManager(array(
$moduleManager = new ModuleManager([
'Application',
'FooModule',
'BarModule',
));
]);

// Attach the default listener aggregate and load the modules
$moduleManager->getEventManager()->attachAggregate($defaultListeners);
$moduleManager->loadModules();
```

> ## Note
Module paths behave very similar to PHP's `include_path` and are searched in the order they are
defined. If you have modules with the same name in more than one registered module path, the module
autoloader will return the first one it finds.
> ### Module paths are FIFO
>
> Module paths behave very similar to PHP's `include_path` and are searched in
> the order they are defined. If you have modules with the same name in more
> than one registered module path, the module autoloader will return the first
> one it finds.
## Non-Standard / Explicit Module Paths

Expand All @@ -63,8 +68,8 @@ Sometimes you may want to specify exactly where a module is instead of having
### Registering a Non-Standard / Explicit Module Path

In this example, the autoloader will first check for `MyModule\Module` in
`/path/to/mymoduledir-v1.2/Module.php`. If it's not found, then it will fall back to searching any
other registered module paths.
`/path/to/mymoduledir-v1.2/Module.php`. If it's not found, then it will fall
back to searching any other registered module paths.

```php
// ./public/index.php
Expand All @@ -75,35 +80,35 @@ use Zend\ModuleManager\ModuleManager;
chdir(dirname(__DIR__));

// Instantiate and configure the default listener aggregate
$listenerOptions = new Listener\ListenerOptions(array(
'module_paths' => array(
$listenerOptions = new Listener\ListenerOptions([
'module_paths' => [
'./module',
'./vendor',
'/usr/share/zfmodules',
'MyModule' => '/path/to/mymoduledir-v1.2',
)
));
]
]);
$defaultListeners = new Listener\DefaultListenerAggregate($listenerOptions);

/**
* Without DefaultListenerAggregate:
*
* $moduleAutoloader = new ModuleAutoloader(array(
* $moduleAutoloader = new ModuleAutoloader([
* './module',
* './vendor',
* '/usr/share/zfmodules',
* 'MyModule' => '/path/to/mymoduledir-v1.2',
* ));
* ]);
* $moduleAutoloader->register();
*
*/

// Instantiate the module manager
$moduleManager = new ModuleManager(array(
$moduleManager = new ModuleManager([
'MyModule',
'FooModule',
'BarModule',
));
]);

// Attach the default listener aggregate and load the modules
$moduleManager->getEventManager()->attachAggregate($defaultListeners);
Expand All @@ -114,14 +119,16 @@ This same method works if you provide the path to a phar archive.

## Packaging Modules with Phar

If you prefer, you may easily package your module as a [phar archive](http://php.net/phar). The
module autoloader is able to autoload modules in the following archive formats: .phar, .phar.gz,
.phar.bz2, .phar.tar, .phar.tar.gz, .phar.tar.bz2, .phar.zip, .tar, .tar.gz, .tar.bz2, and .zip.
If you prefer, you may easily package your module as a
[phar archive](http://php.net/phar). The module autoloader is able to autoload
modules in the following archive formats: .phar, .phar.gz, .phar.bz2, .phar.tar,
.phar.tar.gz, .phar.tar.bz2, .phar.zip, .tar, .tar.gz, .tar.bz2, and .zip.

The easiest way to package your module is to simply tar the module directory. You can then replace
the `MyModule/` directory with `MyModule.tar`, and it should still be autoloaded without any
additional changes!
Package your module by performing a tar the module directory. You can then
replace the `MyModule/` directory with `MyModule.tar`, and it should still be
autoloaded without any additional changes!

> ## Note
If possible, avoid using any type of compression (bz2, gz, zip) on your phar archives, as it
introduces unnecessary CPU overhead to each request.
> ### Avoid compression
>
> If possible, avoid using any type of compression (bz2, gz, zip) on your phar
> archives, as it introduces unnecessary CPU overhead to each request.
Loading

0 comments on commit 0fdef35

Please sign in to comment.