Skip to content

How Phalcon Kit Organizes Your App

Phalcon Kit gives a Phalcon application a repeatable shape. It does not hide Phalcon; it makes recurring ownership decisions explicit so projects can focus on models, APIs, workflows, and permissions.

The Mental Model

  • Bootstrap composes

    It loads app config, creates the DI container, registers providers, and starts the selected runtime.

  • The schema describes data

    Migrations and the live database drive generated model structure.

  • Application code owns behavior

    Concrete models and services hold invariants, workflows, and integrations.

  • Controllers define HTTP policy

    Controllers choose fields, filters, relationships, permissions, and response behavior.

Official Phalcon references:

HTTP Request Flow

HTTP request
  → public/index.php
  → project entrypoint
  → loader.php
  → App\Bootstrap
  → App\Config
  → service providers / DI
  → module and router
  → dispatcher
  → controller action
  → Phalcon response

The steps have distinct failure modes. A web-server 404 occurs before bootstrap. A missing DI service occurs during composition or controller use. A REST policy error occurs after routing and dispatch.

CLI and WebSocket entrypoints reuse the same composition root with another mode:

new Bootstrap('cli');
new Bootstrap('ws');

That lets controllers, CLI tasks, and WebSocket tasks share database services, model aliases, logging, identity rules, and application configuration.

Ownership By Directory

Path Owner Typical contents
app/Bootstrap.php Application Small composition overrides
app/Config/ Application Modules, providers, aliases, permissions, integrations
app/Models/Abstracts/ Generator Columns, relationships, validation, metadata
app/Models/ Application Domain behavior and custom relationships
app/Modules/Api/Controllers/ Application REST/query policy and workflow actions
app/Modules/Cli/Tasks/ Application Imports, exports, maintenance, scheduled work
app/Modules/Ws/Tasks/ Application WebSocket task handlers
resources/migrations/ Application Ordered schema history
vendor/phalcon-kit/core/ Package manager Framework code; never edit in an app

The most important rule is: generated code mirrors the database; app-owned code owns behavior.

If the project table gains a status column, regenerate the abstract model so accessors and validation match the schema. If a project needs an archive() transition, implement that in the concrete Project model.

Decide Where New Code Belongs

Requirement Best starting point
Validate one model’s state transition Concrete model
Coordinate several models in a transaction Application/domain service
Call an external API from several workflows Service plus DI provider
Restrict client-visible or writable fields REST controller policy
Restrict which rows an identity can query Permission conditions
Produce a stable public JSON shape Transformer
Run an operational batch CLI task calling a service
React to a reusable lifecycle event Listener or model behavior

Avoid large controllers that perform persistence, integration calls, and output formatting inline. Controllers should adapt transport intent to application operations.

Extend Through Providers

Providers are the boundary between configuration and constructed services. A provider registers a stable service name in the Phalcon Kit DI container:

use App\Service\ReportExporter;
use Phalcon\Contracts\Db\Adapter\Adapter as AdapterContract;
use Phalcon\Contracts\Logger\Logger as LoggerContract;
use PhalconKit\Di\DiInterface;
use PhalconKit\Provider\AbstractServiceProvider;

final class ServiceProvider extends AbstractServiceProvider
{
    protected string $serviceName = 'reportExporter';

    public function register(DiInterface $di): void
    {
        $di->setShared($this->getName(), static function () use ($di) {
            return new ReportExporter(
                $di->getTyped('db', AdapterContract::class),
                $di->getTyped('logger', LoggerContract::class)
            );
        });
    }
}

Register app services in app config. Override a core provider only when the app intentionally replaces that service contract.

Generated Versus Concrete Models

ProjectAbstract      ← regenerated from the schema
      ↑
Project              ← app-owned behavior
      ↑
controllers/services ← use the concrete model

Never place durable business logic in a generated abstract. Regeneration should be routine and reviewable, not dangerous.

Common Extension Points

Most applications customize:

  • config classes extending PhalconKit\Bootstrap\Config;
  • providers extending PhalconKit\Provider\AbstractServiceProvider;
  • concrete models extending generated abstract models;
  • API controllers extending the app API base controller;
  • permission config and controller attributes;
  • transformers for stable API representations;
  • behaviors and listeners for reusable lifecycle logic.

Prefer these app-owned extension points over vendor patches. When the same missing capability affects several applications, contribute it to core with tests and documentation.

Still Normal Phalcon

  • DI services are Phalcon DI services.
  • Models are Phalcon ORM models.
  • Controllers run through the Phalcon dispatcher.
  • Validation uses Phalcon validation primitives.
  • Routing follows Phalcon routing and dispatcher semantics.
  • Responses implement Phalcon response contracts.

Phalcon Kit adds conventions, generators, typed helpers, and defaults around those components. Native Phalcon documentation remains relevant.

Continue Building