# Starting a new application
An application built on MMOFramework is a folder of its own with a manifest, a bootstrap and an entry point. It
is not a composer package: nothing is installed with `composer require`, and no PSR-4 autoloader looks for its
classes.
## The one command
From a checkout of the framework (the hub, the clone that holds `libs/`):
```sh
php tools/mmo.php project ../acme.portal --name=acme.portal --namespace=AcmePortal
php tools/mmo.php project ../acme.portal --dry-run # say what it would write, write nothing
```
It writes the whole tree below, ready to run and ready to deploy with mmo.admin. The parent folder has to exist
already. What follows is what it writes, and why — write it by hand only if you cannot run the command.
## The tree
```
acme.portal/
bootstrap.php shared by the web entry point, the scripts and the tests
mmo.json the manifest
configs/
config.json every mode
dev.json a checkout only (never in a release)
prod.json read from the target's shared/ folder
local.json this machine's own values -- gitignored, never committed, never shipped
src/
bootstrap.php requires every class file, and registers the namespace as a path
pages/ styles/
www/
index.php the web entry point; www/ is a release's document root
tests/
bootstrap.php
unit/
phpunit.xml
.htaccess rewrites every request that is not a file to www/index.php
```
## The root `bootstrap.php`
It decides the **mode**, then loads the framework, then the configuration.
**The mode follows the tree, not the host name.** A release is a `git archive` of one commit, and never contains
`src/` — `.gitattributes` export-ignores it — because it runs from the `.phar` packages built into `packages/`.
So `src/` exists in a developer's checkout and nowhere else, which holds on a laptop, on a server, and on the
command line where there is no host name to ask anyway.
```php fragment
if (!defined('MMO_MODE')) {define('MMO_MODE', is_dir(__DIR__ . '/src')? 'dev' : 'prod');}
//a checkout runs on the libraries' sources (`libs` links to the `libs/` folder of an MMOFramework clone); a
//release runs on the packages mmo.admin built into it, and core, loaded from its phar, finds the others beside it
if (MMO_MODE === 'dev') {require(__DIR__ . '/libs/core/src/bootstrap.php');}
else {require(__DIR__ . '/packages/mmo.core.phar');}
```
Then the configuration, layered — each file overriding the one before:
```php fragment
\MMO\config(
[
//both are otherwise derived from the running script, which phpunit, or a script outside this folder, is not
\MMO\core\Application::class => ['paths' => ['root' => __DIR__]],
\MMO\core\PackageManager::class => ['project' => __DIR__ . '/mmo.json'],
],
__DIR__ . '/configs/config.json',
__DIR__ . '/configs/' . MMO_MODE . '.json'
);
//this machine's own values (a local database password): gitignored, so never committed, and never shipped
if (is_file(__DIR__ . '/configs/local.json')) {\MMO\config(__DIR__ . '/configs/local.json');}
```
## `src/bootstrap.php`
The package bootstrap, run by <@\MMO\core\PackageManager::inc> when the project is loaded. **Nothing autoloads on
its own**: every class file of `src/` is required here, after whatever it extends or uses. Registering the
namespace as a path is what makes the namespace an alias of this folder — `src/` in a checkout, and the same
folder inside `packages/.phar` in a release, which has no `src/` at all.
```php fragment
namespace AcmePortal;
require(__DIR__ . '/entities/Article.php'); //before whatever extends or uses it
require(__DIR__ . '/controllers/ArticlesController.php');
return [
\MMO\core\Application::class => ['paths' => [__NAMESPACE__ => __DIR__]],
];
```
That alias is why a configuration says `{AcmePortal}/pages` and **never** `{root}/src/pages`: the second one
resolves to nothing in a release: `.gitattributes` export-ignores `src/`, and mmo.admin refuses an artifact
that contains one.
## `www/index.php`
Everything is set up by `../bootstrap.php`, so the entry point only starts the application:
```php fragment
require(__DIR__ . '/../bootstrap.php');
\MMO\run();
```
`.htaccess` sends every request that is not a file there. A controller is reached because it is listed under the
Application's `routes` configuration (or connected with `connectRoutes()`), not because it was found by scanning.
## `mmo.json`
@see <@\MMO\core\PackageManager> for every key. The minimum:
```json
{
"name": "acme.portal",
"version": "1.0.0",
"namespace": "AcmePortal",
"sources": ["src"],
"dependencies": {"mmo.core": "20.*"},
"bootstrap": "src/bootstrap.php"
}
```
## Next
- Tests: @see Testing.md
- Deploying: mmo.admin's `deploy.json`, `php scripts/admin.php plan` then `release`.
- A new `mmo.*` library rather than an application: @see NewLibrary.md