iviphp/ivi

The official application skeleton for building modular web and console applications with IviPHP.

Maintainers

Package info

github.com/iviphp/ivi

Type:project

pkg:composer/iviphp/ivi

Transparency log

Statistics

Installs: 49

Dependents: 0

Suggesters: 0

Stars: 16

Open Issues: 10

v2.0.0 2026-07-21 17:55 UTC

README

The official application skeleton for building modular web and console applications with IviPHP.

iviphp/ivi provides a minimal project structure powered by iviphp/framework. It includes application bootstrapping, configuration, service providers, console commands and writable storage directories without imposing a large application architecture.

Requirements

  • PHP 8.2 or later
  • Composer
  • Required PHP extensions for the database driver used by the application

Installation

Create a new IviPHP application:

composer create-project iviphp/ivi my-application

Enter the project directory:

cd my-application

Create the local environment file:

cp .env.example .env

Make the console executable:

chmod +x bin/console

Display the available commands:

php bin/console

or:

./bin/console

Project structure

.
├── bin/
│   └── console
├── bootstrap/
│   └── app.php
├── config/
│   ├── app.php
│   └── database.php
├── public/
│   └── index.php
├── src/
│   ├── Console/
│   │   └── Commands/
│   │       └── AboutCommand.php
│   ├── Http/
│   │   └── Controllers/
│   └── Providers/
│       └── AppServiceProvider.php
├── storage/
│   ├── cache/
│   ├── logs/
│   └── views/
├── .env.example
├── composer.json
├── LICENSE
└── README.md

Application bootstrap

The application is created in:

bootstrap/app.php

This file:

  • loads Composer;
  • reads the local .env file;
  • loads application configuration;
  • creates the framework instance;
  • registers application service providers;
  • registers console commands;
  • returns the configured framework.

Example:

<?php

declare(strict_types=1);

use App\Console\Commands\AboutCommand;
use App\Providers\AppServiceProvider;
use Ivi\Config\Config;
use Ivi\Framework\Framework;

$basePath = dirname(__DIR__);

require_once $basePath
    . '/vendor/autoload.php';

$config = Config::load(
    $basePath . '/config'
);

$framework = Framework::create(
    basePath: $basePath,
    config: $config,
    environment: (string) $config->get(
        'app.environment',
        'production'
    ),
    consoleName: (string) $config->get(
        'app.name',
        'Ivi Application'
    ),
    consoleVersion: (string) $config->get(
        'app.version',
        '0.1.0'
    )
);

$framework->provider(
    AppServiceProvider::class
);

$framework->registerCommand(
    new AboutCommand()
);

return $framework;

The bootstrap file may be reused by console and web entry points.

Environment configuration

Create .env from the example file:

cp .env.example .env

Default values:

APP_NAME="Ivi Application"
APP_ENV=development
APP_DEBUG=true
APP_URL=http://localhost:8000

DB_DRIVER=sqlite
DB_DATABASE=storage/database.sqlite
DB_HOST=127.0.0.1
DB_PORT=3306
DB_NAME=ivi
DB_USERNAME=root
DB_PASSWORD=

CACHE_DRIVER=file
CACHE_PATH=storage/cache

LOG_CHANNEL=file
LOG_LEVEL=debug
LOG_PATH=storage/logs/app.log

The .env file is ignored by Git and should contain machine-specific or private configuration.

Do not commit production credentials.

Application configuration

Application configuration is stored in:

config/app.php

Available settings include:

return [
    'name' => 'Ivi Application',
    'version' => '0.1.0',
    'environment' => 'production',
    'debug' => false,
    'url' => 'http://localhost:8000',
    'timezone' => 'UTC',
    'locale' => 'en',
];

Retrieve configuration through the framework:

$name = $framework
    ->config()
    ->get(
        'app.name',
        'Ivi Application'
    );

Check the current environment:

if ($framework->isEnvironment('production')) {
    // Production behavior.
}

Check several environments:

if (
    $framework->isEnvironment(
        'development',
        'testing'
    )
) {
    // Development or testing behavior.
}

Database configuration

Database configuration is stored in:

config/database.php

The default driver is SQLite:

DB_DRIVER=sqlite
DB_DATABASE=storage/database.sqlite

Create the SQLite database file:

touch storage/database.sqlite

MySQL

DB_DRIVER=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_NAME=ivi
DB_USERNAME=root
DB_PASSWORD=

PostgreSQL

DB_DRIVER=pgsql
DB_HOST=127.0.0.1
DB_PORT=5432
DB_NAME=ivi
DB_USERNAME=postgres
DB_PASSWORD=

The selected database package or provider is responsible for consuming this configuration and establishing connections.

Service providers

Application services are registered through service providers.

The default provider is:

src/Providers/AppServiceProvider.php

It registers application metadata and common paths in the service container.

Available services include:

app.name
app.version
app.environment
app.debug
app.url

path.base
path.bootstrap
path.config
path.public
path.storage
path.cache
path.logs
path.views

Resolve a service:

$name = $framework->make('app.name');

$storagePath = $framework->make(
    'path.storage'
);

Check whether a service exists:

if ($framework->has('path.logs')) {
    $logs = $framework->make(
        'path.logs'
    );
}

Creating a service provider

Create a provider in:

src/Providers

Example:

<?php

declare(strict_types=1);

namespace App\Providers;

use App\Services\Mailer;
use Ivi\Framework\Contracts\ApplicationInterface;
use Ivi\Framework\Providers\ServiceProvider;

final class MailServiceProvider extends ServiceProvider
{
    public function __construct(
        ApplicationInterface $application
    ) {
        parent::__construct(
            $application,
            [
                Mailer::class,
                'mailer',
            ]
        );
    }

    protected function registerServices(): void
    {
        $mailer = new Mailer();

        $this->container()->instance(
            Mailer::class,
            $mailer
        );

        $this->container()->instance(
            'mailer',
            $mailer
        );
    }

    protected function bootServices(): void
    {
        $mailer = $this->make(
            Mailer::class
        );

        $mailer->initialize();
    }
}

Register it in bootstrap/app.php:

use App\Providers\MailServiceProvider;

$framework->provider(
    MailServiceProvider::class
);

Register several providers:

$framework->providers([
    App\Providers\DatabaseServiceProvider::class,
    App\Providers\MailServiceProvider::class,
]);

Provider lifecycle

Service providers have two lifecycle stages.

Registration

protected function registerServices(): void
{
    // Register container services.
}

Registration happens when the provider is added to the framework.

Use this stage for:

  • service instances;
  • factories;
  • aliases;
  • configuration defaults;
  • dependency bindings.

Booting

protected function bootServices(): void
{
    // Complete application initialization.
}

Booting happens after application bootstrap completes.

Use this stage for:

  • resolving services;
  • initializing components;
  • registering listeners;
  • preparing directories;
  • connecting framework modules.

Console commands

Console commands are stored in:

src/Console/Commands

The default application contains:

AboutCommand

Run it with:

php bin/console about

or through its alias:

php bin/console info

Example output:

IviPHP
A modular PHP framework for web and console applications.

Application:
  Name: Ivi Application
  Version: 0.1.0
  Environment: development

Runtime:
  PHP: 8.2.x
  SAPI: cli
  Operating system: Linux

Creating a command

Create a command class:

<?php

declare(strict_types=1);

namespace App\Console\Commands;

use Ivi\Console\Contracts\CommandInterface;
use Ivi\Console\Contracts\InputInterface;
use Ivi\Console\Contracts\OutputInterface;

final class HelloCommand implements CommandInterface
{
    public function name(): string
    {
        return 'hello';
    }

    public function description(): string
    {
        return 'Display a greeting.';
    }

    public function aliases(): array
    {
        return [];
    }

    public function usage(): string
    {
        return 'hello [name]';
    }

    public function isHidden(): bool
    {
        return false;
    }

    public function execute(
        InputInterface $input,
        OutputInterface $output
    ): int {
        $name = $input->argument(
            0,
            'Developer'
        );

        $output->success(
            "Hello, {$name}."
        );

        return 0;
    }
}

Register it in bootstrap/app.php:

use App\Console\Commands\HelloCommand;

$framework->registerCommand(
    new HelloCommand()
);

Run it:

php bin/console hello Gaspard

Closure-backed commands

Commands may also be registered directly:

use Ivi\Console\Contracts\InputInterface;
use Ivi\Console\Contracts\OutputInterface;

$framework->command(
    name: 'app:environment',
    handler: static function (
        InputInterface $input,
        OutputInterface $output
    ) use ($framework): int {
        $output->info(
            'Environment: '
            . $framework->environment()
        );

        return 0;
    },
    description: 'Display the application environment.',
    aliases: [
        'env',
    ]
);

Run it:

php bin/console app:environment

or:

php bin/console env

Console help

Display all commands:

php bin/console

or:

php bin/console list

Display help for one command:

php bin/console help about

Command help is also available with:

php bin/console about --help

Display the application version:

php bin/console --version

Console entry point

The executable console file is:

bin/console

It:

  • loads the application bootstrap;
  • validates the returned framework instance;
  • starts the framework;
  • executes the requested command;
  • returns the command exit code;
  • displays startup failures safely.

Run it through PHP:

php bin/console

Make it directly executable:

chmod +x bin/console

Then run:

./bin/console

Debug mode

Enable debug mode in .env:

APP_DEBUG=true

When console startup fails, debug mode displays:

  • exception class;
  • source file;
  • source line;
  • stack trace.

Disable it in production:

APP_DEBUG=false

Storage directories

Writable application files are stored in:

storage/

The default directories are:

storage/cache
storage/logs
storage/views

They are automatically created by Composer and by the default application service provider.

Create them manually when necessary:

mkdir -p \
  storage/cache \
  storage/logs \
  storage/views

The contents of these directories are ignored by Git.

Resolving application paths

The framework safely resolves paths relative to the project root.

$configPath = $framework->path(
    'config/app.php'
);

$storagePath = $framework->path(
    'storage'
);

$logsPath = $framework->path(
    'storage/logs'
);

Absolute paths and parent-directory traversal are rejected.

Accessing framework services

Retrieve the application:

$application = $framework->application();

Retrieve the service container:

$container = $framework->container();

Retrieve configuration:

$config = $framework->config();

Retrieve the console:

$console = $framework->console();

Retrieve the framework manager:

$manager = $framework->manager();

Application startup

Start the application manually:

$framework->start();

This performs:

Bootstrap application
Boot service providers

The lifecycle is idempotent. Completed stages are not executed again.

Bootstrap without booting providers:

$framework->bootstrap();

Boot registered providers:

$framework->boot();

Check the lifecycle state:

if ($framework->isBootstrapped()) {
    // Bootstrap operations completed.
}

if ($framework->isBooted()) {
    // Providers completed booting.
}

if ($framework->isStarted()) {
    // Application is fully started.
}

Custom bootstrap operations

Register application initialization logic:

use Ivi\Framework\Contracts\ApplicationInterface;

$framework->bootstrapWith(
    'prepare.uploads',
    static function (
        ApplicationInterface $application
    ): void {
        $path = $application->path(
            'storage/uploads'
        );

        if (!is_dir($path)) {
            mkdir(
                $path,
                0775,
                true
            );
        }
    }
);

Bootstrap operations execute in registration order.

Development server

Once the public HTTP entry point is configured, start PHP's built-in development server:

php -S 127.0.0.1:8000 -t public

Open:

http://127.0.0.1:8000

The built-in PHP server is intended for local development only.

Composer commands

Install dependencies:

composer install

Update dependencies:

composer update

Refresh autoload files:

composer dump-autoload

Validate the project configuration:

composer validate --strict

Production preparation

Before deploying:

composer install \
  --no-dev \
  --optimize-autoloader

Use production environment settings:

APP_ENV=production
APP_DEBUG=false

Ensure the storage directories are writable by the application process:

chmod -R 775 storage

Deployment permissions should be adapted to the server and user configuration.

Extending the application

Application code belongs under:

src/

Recommended namespaces:

App\Console\Commands
App\Http\Controllers
App\Providers
App\Services
App\Repositories
App\Models

Composer maps the App namespace to src:

{
  "autoload": {
    "psr-4": {
      "App\\": "src/"
    }
  }
}

After adding or moving classes, regenerate Composer autoload files:

composer dump-autoload

Design principles

The Ivi application skeleton follows these principles:

  • minimal initial structure;
  • modular framework packages;
  • explicit application bootstrapping;
  • service-provider based composition;
  • dependency-container integration;
  • console-first developer tooling;
  • environment-based configuration;
  • replaceable application services;
  • predictable application lifecycle;
  • no unnecessary application abstractions.

License

Ivi is open-source software released under the MIT License.

Maintainer

Maintained by Gaspard Kirira and Softadastra.