📦 Marketplace⭐ GitHub
Guidesv2.0

Your First Application

Build your first MonkeysLegion v2 application from scratch.


Table of Contents


Prerequisites

RequirementVersionCheck
PHP8.4+php -v
Composer2.xcomposer --version
MySQL8.4+mysql --version
Redis7+redis-cli ping

Note: Redis is optional for development. File-based drivers work for cache, session, and queue.


Installation

1. Create the Project

composer create-project monkeyscloud/monkeyslegion-skeleton my-app
cd my-app

2. Configure Environment

cp .env.example .env
php vendor/bin/ml key:generate

Edit .env with your database credentials:

APP_NAME="My App"
APP_ENV=dev
APP_DEBUG=true
APP_URL=http://localhost:8000
APP_KEY=           # Auto-filled by key:generate

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=my_app
DB_USERNAME=root
DB_PASSWORD=secret

3. Create the Database Schema

php vendor/bin/ml schema:update

4. Start the Server

composer serve
# → http://localhost:8000

Or use the simple dev server:

composer dev
# → http://localhost:8080

Project Structure

my-app/
├── app/                        ← Your application code
│   ├── Controller/             ← HTTP controllers (auto-discovered)
│   │   └── Api/                ← API controllers
│   ├── Dto/                    ← Request DTOs with validation
│   ├── Entity/                 ← Database entities
│   ├── Enum/                   ← PHP enums
│   ├── Event/                  ← Domain events
│   ├── Job/                    ← Queue jobs
│   ├── Listener/               ← Event listeners
│   ├── Middleware/              ← Custom middleware
│   ├── Policy/                 ← Authorization policies
│   ├── Providers/              ← Service providers
│   ├── Repository/             ← Data access layer
│   ├── Resource/               ← API response transformers
│   └── Service/                ← Business logic
├── config/                     ← .mlc configuration files
├── database/migrations/        ← SQL migration files
├── public/                     ← Web root (index.php, assets)
├── resources/views/            ← Templates (.ml.php)
│   └── layouts/                ← Layout templates
├── tests/                      ← PHPUnit tests
├── .env                        ← Environment variables
└── composer.json               ← Dependencies

Key convention: Controllers in app/Controller/ are auto-discovered. No registration needed.


Your First Controller

Create app/Controller/HelloController.php:

<?php
declare(strict_types=1);

namespace App\Controller;

use MonkeysLegion\Router\Attributes\Route;
use MonkeysLegion\Http\Message\Response;

final class HelloController
{
    #[Route('GET', '/hello', name: 'hello')]
    public function index(): Response
    {
        return Response::text('Hello, MonkeysLegion!');
    }

    #[Route('GET', '/hello/{name}', name: 'hello.name')]
    public function greet(string $name): Response
    {
        return Response::text("Hello, {$name}!");
    }
}

Visit http://localhost:8000/hello — that's it. No route files, no registration.


Returning JSON

#[Route('GET', '/api/status', name: 'api.status')]
public function status(): Response
{
    return Response::json([
        'status' => 'ok',
        'version' => '2.0',
        'timestamp' => time(),
    ]);
}

With Status Codes

return Response::json(['data' => $user], 201);         // Created
return Response::json(['error' => 'Not found'], 404);  // Not Found
return Response::noContent();                           // 204

Returning HTML

Option A: Inline HTML

#[Route('GET', '/about', name: 'about')]
public function about(): Response
{
    return Response::html('<h1>About Us</h1><p>We build cool stuff.</p>');
}

Inject the Renderer and render a .ml.php template:

<?php
declare(strict_types=1);

namespace App\Controller;

use MonkeysLegion\Router\Attributes\Route;
use MonkeysLegion\Http\Message\Response;
use MonkeysLegion\Template\Renderer;

final class PageController
{
    public function __construct(
        private readonly Renderer $renderer,
    ) {}

    #[Route('GET', '/about', name: 'about')]
    public function about(): Response
    {
        return Response::html(
            $this->renderer->render('pages.about', [
                'title' => 'About Us',
                'team' => ['Jorge', 'Marouane', 'Team'],
            ])
        );
    }
}

Create resources/views/pages/about.ml.php:

@extends('layouts.app')

@section('title', '{{ $title }}')

@section('content')
<h1>{{ $title }}</h1>

<h2>Our Team</h2>
<ul>
    @foreach($team as $member)
        <li>{{ $member }}</li>
    @endforeach
</ul>
@endsection

Dot notation pages.about maps to resources/views/pages/about.ml.php.


Running the Dev Server

composer serve

This starts the dev server on port 8000 with file watching and automatic reload.

Simple Server

composer dev

Starts on port 8080 without hot-reload.

PHP Built-in Server

php -S localhost:8000 -t public server.php

Environment Configuration

MonkeysLegion uses two configuration systems:

1. .env File — Secrets & Environment

APP_KEY=base64:xxxx
DB_PASSWORD=secret
REDIS_HOST=127.0.0.1

2. .mlc Files — Application Config

Located in config/. Uses HOCON-like syntax with env variable interpolation:

# config/app.mlc
app {
    name     = ${APP_NAME:"My App"}
    env      = ${APP_ENV:production}
    debug    = ${APP_DEBUG:false}
    url      = ${APP_URL:http://localhost:8000}
    key      = ${APP_KEY}
    timezone = "UTC"
}

Accessing Config Values

$config = $container->get(MlcConfig::class);
$appName = $config->get('app.name');            // "My App"
$debug   = $config->get('app.debug', false);    // With default

Next Steps

GuideWhat You'll Learn
Building a REST API →Entity, Repository, Service, Controller, DTOs
Authentication & Authorization →JWT, Login, 2FA, RBAC, Policies
Templates & Views →Layouts, directives, components
Events, Queues & Background Jobs →Event dispatch, listeners, async jobs
Middleware, Caching & Advanced Patterns →Custom middleware, cache strategies, testing

MonkeysLegion v2 — Built with 🐵 by MonkeysCloud Team