All news

Build your first AML View application in five minutes

Create a reactive reading list, understand the generated structure, and learn how View, Engine, Framework and Data fit together.

A first AML View project should teach the framework by producing a useful result immediately. In this guide, you will create a small reactive reading list, understand every generated folder, and see which work happens on the server and which work continues in the browser.

1. Check the CLI

AML includes the runtime required to create and serve a PHPAML project. Confirm the installed version before starting.

phpaml — zsh
aml version

This guide targets PHPAML 1.7.0-beta.22 or a newer compatible build. If your version is older, update AML first so the generated application contains the current View structure and runtime.

2. Create the application

Move to the directory where you keep projects, then create a new AML View application.

phpaml — zsh
cd ~/Desktop
aml create-view-app reading-list
cd reading-list
aml serve

The development server starts at http://127.0.0.1:8910. If that port is already occupied, AML selects 8911, then 8912, without asking you to stop another project.

3. Read the generated structure

The generated project separates code you own from runtime code managed by AML.

phpaml — zsh
reading-list/
├── public/
│   └── index.php
├── routes/
├── src/
│   ├── controllers/
│   ├── models/
│   └── views/
│       ├── pages/
│       ├── components/
│       ├── layouts/
│       ├── stylesheets/
│       └── assets/
├── runtime/
├── .env
└── phpaml.json

public is the web entry point. Your declarative interface belongs in src/views. Controllers and models remain available when the frontend needs application logic or persistence. Generated caches, downloaded packages and internal configuration stay in runtime.

4. Build a reactive page

Open the home page in src/views/pages and replace its body with a small reading-list interface.

phpaml — zsh
final class Home extends Page
{
    #[State]
    public array $books = ['Clean Code', 'Refactoring'];

    #[State]
    public string $title = '';

    #[Computed]
    public function total(): int
    {
        return count($this->books);
    }

    public function body(): View
    {
        return VStack(
            Heading('My reading list')->size(44)->bold(),
            Text("{$this->total()} books ready to read"),
            TextField('Book title')
                ->value($this->title)
                ->onInput(fn (string $value) => $this->title = $value),
            Button('Add book')->onClick(function (): void {
                $title = trim($this->title);
                if ($title === '') return;

                $this->books[] = $title;
                $this->title = '';
            }),
            ForEach(
                $this->books,
                fn (string $book) => Text($book)->class('book-row')
            )
        )->gap(16)->padding(40);
    }
}

State holds values that can change. Computed derives information from that state. Button and TextField declare browser interactions. ForEach renders a collection without mixing HTML tags into the page.

5. Add styles without touching public

Create src/views/stylesheets/pages/home.css. AML View discovers stylesheets recursively, so you can organize them by page, component or feature.

phpaml — zsh
.book-row {
    padding: 14px 16px;
    background: #f4f3ee;
    color: #17181c;
    font-weight: 650;
}

Use classes explicitly with ->class(). Keep directly addressable files such as favicon, robots.txt and sitemap.xml in public. Interface styles and imported images belong under src/views.

6. Understand what happens after a click

PHP renders the first document on the server. AML Engine activates declared interactions in the browser. Adding a book updates the relevant interface state without requesting a complete page render from the server.

This boundary is deliberate: View describes the interface, Engine handles client reactivity, Framework can serve backend routes, and Data can persist entities when the project needs durable storage.

7. Verify the result

Try adding an empty title: nothing should be inserted. Add three books and confirm that the computed total changes each time. Reload the page and observe that the list returns to its initial value because this first example uses local state only.

That last observation gives you the next useful exercise: create a Book model with PHPAML Data, load books through a controller or API route, and keep the same declarative View.

In summary

In a few minutes, you created a structured PHP application, rendered a declarative page, handled input, updated a collection, used computed state and organized page-specific CSS. You also saw the central PHPAML principle: each package has a clear job, and an application adopts only the layers it needs.