Skip to content

Releases: vortexphp/framework

v0.12.0: Release 0.12.0

05 Apr 10:17

Choose a tag to compare

Added

  • Vortex\Package\Package — extend and list FQCNs under packages in config/app.php (read as app.packages). register() runs right after the config repository is bound (before most core singletons resolve). boot() runs after routes/*.php HTTP routes load (use Route:: for extra endpoints). console() runs while the CLI registers commands (before routes/console.php / routes/*Console.php), suitable for Vortex::command(...).
  • ConsoleApplication::boot() loads .env and initializes Repository so config-backed CLI behavior and package console() hooks align with HTTP.
  • Package::publicAssets() — map package-relative paths to paths under public/; publish:assets copies files for all configured packages.

v0.11.1

04 Apr 23:45

Choose a tag to compare

Fixed

  • Translator: loads lang/{locale}.php (if present) and merges every lang/{locale}/*.php file (sorted by path). Fixes apps that only ship lang/en/app.php (dot keys were previously shown verbatim).

Release v0.11.0: routes/, AppPaths defaults, resources/views

04 Apr 23:36

Choose a tag to compare

Breaking

  • HTTP routes: route files load from routes/*.php (project root), not app/Routes/. Files named console.php or ending in *Console.php are excluded from HTTP discovery and used for CLI registration only.
  • Console routes: routes/console.php (if present) and routes/*Console.php are loaded for Vortex::command(...) (in addition to the previous *Console.php-only pattern under the old directory).
  • AppPaths defaults: database/migrations, app/Controllers, app/Commands (replacing db/migrations, app/Http/Controllers, app/Console/Commands).
  • CommandDiscovery resolves command classes using a PSR-4 namespace derived from the configured commands path under app/ (e.g. App\Commands\). Paths not under app/ cannot be used for auto-discovery namespaces.
  • AppPaths: controllersNamespace() and commandsNamespace(); make:controller, make:command, and stubs follow these namespaces.
  • Twig: default template root is resources/views (was ui/views). Override with config/view.phppath (or view.path in the merged config).

Changed

  • Application: reads view.path with default resources/views.

v0.10.0: Release 0.10.0

04 Apr 12:33

Choose a tag to compare

Changed

  • Breaking: app/Routes/*Console.php files are **require**d like HTTP route files; they must call Vortex::command(...) instead of returning callable(ConsoleApplication): void.

Added

  • CommandDiscovery::registerAppCommands() — registers concrete Command classes under AppPaths commands (default app/Console/Commands), recursively. ConsoleApplication::boot() runs it before RouteDiscovery::loadConsoleRoutes().
  • AppPaths: commands / commandsDirectory() / commandsRelative() (config/paths.php key commands).
  • Vortex::command() on Vortex\Vortex — application facade for app/Routes/*Console.php (same role as Route for HTTP route files). bindConsoleApplication() is @internal for RouteDiscovery.

v0.9.0: Release 0.9.0

04 Apr 12:14

Choose a tag to compare

Changed

  • Command: no constructor argument; ConsoleApplication::register() calls setBasePath() so custom commands use $app->register(new MyCommand()). Invoke setBasePath() yourself when constructing commands outside the console app.

Added

  • Input: arguments(), argument(), options(), option(), hasOption(), flag() — POSIX-style long/short options, --, while tokens() remains the raw argv[2..] slice.
  • Console codegen stubs: Vortex\Console\Stub renders src/Console/stubs/*.stub with {{PLACEHOLDER}} substitution. make:command, make:migration, make:model, and make:controller (invokable App\Http\Controllers\*, stub controller.stub) use stubs. make:model writes App\Models\* (optional --table=, -m / --migration for migration_model.stub create-table migration); AppPaths adds models (default app/Models) and controllers (default app/Http/Controllers) alongside migrations.

v0.8.0: Release 0.8.0.

04 Apr 11:42

Choose a tag to compare

Added

  • ORM persistence helpers: Model::refresh() (re-load by id; withTrashed when soft deletes), firstOrCreate(), updateOrCreate() (lookup via AND where on the first array).
  • ORM morph map: MorphMap::register() (alias → Model class), resolveClass(), Model::getMorphClass(); morphTo / eager morphTo resolve aliases; morphMany / morphOne and their eager loads use getMorphClass() for the _type filter. FQCNs in the database remain valid when no alias is registered.
  • Real-time (thin layer): Broadcasting\Contracts\Broadcaster, SyncBroadcaster (in-process listen / publish), RedisBroadcaster (broadcasting.driver redis, Redis::publish after local fan-out; SyncBroadcaster is a separate singleton for listeners); Application registers Broadcaster and SyncBroadcaster. Response::serverSentEvents(), SseEmitter (message, json, comment), and Response::isStreamResponse() for text/event-stream.
  • Container: Container::call() invokes callables with auto-wired parameters and named overrides; variadic parameters accept a single array under that argument name. Constructor injection gains union type resolution (first succeeding make() wins), self / parent normalization, nullable fallback, and explicit RuntimeException when resolving unbound interfaces / abstract classes (instead of a raw PHP error). tag() / tagged() for grouped service lists; bindFor($consumerClass, $abstract, $concrete) for per-consumer (“contextual”) dependency overrides.
  • JSON Schema (request bodies): dependency justinrainbow/json-schema; Vortex\Support\JsonSchemaValidator::validateArray(); Request::bodyJsonSchemaResponse() returns validation_failed like bodyShapeResponse(). Empty PHP array [] is treated as JSON {} when the schema root is object-shaped (PHP cannot distinguish them after json_decode(..., true)). Draft 3–7 as supported by the library.
  • JSON Schema (responses): JsonSchemaValidator::validateDecoded() for any JSON-encodable value (lists and nested structures from JsonResource::resolve(), etc.). Response::apiOkValidated() / jsonValidated(); JsonResource::toValidatedResponse() / collectionValidatedResponse(). Schema mismatch → 500 response_schema_mismatch with errors (server contract).
  • JsonResource pipeline: ordered pushResponseTransform() callables (after toArray()), then transformResponse(); withResponseTransforms() returns a clone with extra stages. resolve() runs the full chain; toResponse(), toValidatedResponse(), and collect() use resolve().
  • Polymorphic ORM: Model::morphTo(), morphMany(), morphOne(); Relation::morphTo(), morphMany(), morphOne() for eagerRelations(). Eager loads batch on {name}_type + {name}_id; nested paths after morphTo run per concrete Model class.
  • Cursor pagination (API): Vortex\Pagination\Cursor (encode/decode opaque token), CursorPaginator, InvalidCursorException, QueryBuilder::cursorPaginate() (next_cursor, has_more, per_page; ASC / DESC on a single column). CursorPaginator::toApiData() for Response::apiOk() payloads.
  • ORM hasOne: Model::hasOne(), Relation::hasOne() eager spec, batched with() (first related row per parent by id when duplicates). hasMany-compatible FK layout on the child.
  • PSR-16 cache: dependency psr/simple-cache; Vortex\Cache\Psr16Cache implements Psr\SimpleCache\CacheInterface over Vortex\Contracts\Cache; SimpleCacheInvalidArgumentException for illegal keys. Application registers CacheInterface against the default cache store.
  • CLI codegen: make:migration (timestamped file + anonymous Migration class stub) and make:command (App\Console\Commands\*Command skeleton + registration hint). repl command — interactive eval() with $app, $c, $container; gated by app.debug or --force. Command::run() stores the booted application once when shouldBootApplication() is true (no double Application::boot()).
  • HTTP / routing conventions: abstract Vortex\Http\Controller with small Response helpers; invokable controllers (Route::get('/path', MyController::class)__invoke); Router::middleware() / Route::middleware() to attach middleware to the route registered immediately before (class names; de-duplicated).
  • Schema builder: Blueprint additions — bigInteger, smallInteger, decimal, floatType, date, dateTime, json, char; ColumnDefinition::unsigned() (MySQL integer family); foreign key onUpdate actions (cascadeOnUpdate, restrictOnUpdate, nullOnUpdate, noActionOnUpdate). Schema::hasTable() for SQLite / MySQL / PostgreSQL.
  • Testing: Vortex\Testing\KernelBrowserboot(), get() / post() / postJson() / request(), decodeJson(), resetRequestContext() for in-process kernel tests. Container::has() reports explicit bindings or instances.
  • ORM relation polish: Vortex\Database\RelationbelongsTo(), hasMany(), belongsToMany() return eagerRelations() spec arrays. Model::load() eager-loads relations on an already-fetched instance (dot paths supported). QueryBuilder::eagerLoadOnto() runs the same batched loader on a list of models using the builder’s with() paths.
  • JSON body shape validation: JsonShape::validate() for structural/type checks; JsonShape::object() for nested objects (errors parent.child); JsonShape::listOf() / listOfObjects() for lists of objects (errors parent.index.field); JsonShape::listOfPrimitive() for typed primitive lists (errors parent.index; element spec ?type allows null entries). Request::bodyShapeResponse() returns 422 via validationFailed() when the body does not match. Breaking: only JsonShape::object([...]) defines nesting; raw associative arrays as specs are rejected. Not JSON Schema; supports optional fields (?type) and types string, int, float, bool, number, array, list, object.
  • REST resource routing: Router::resource() / Route::resource() — registers index, store, show, update, destroy; default except create / edit. Named routes (photos.index, …); optional name prefix; shared middleware. parameter overrides singular placeholder (e.g. categories{category}).
  • HTTP JSON API helpers: Response::apiOk() / Response::apiError() for stable success and error envelopes; abstract JsonResource with toArray(), toResponse(), collect(), and collectionResponse(); Response::validationFailed() maps ValidationResult to 422 / validation_failed plus errors. Request::validationResponse() / bodyValidationResponse() run Validator::make and return that response when invalid. Request::splitVersionedPath(), apiVersionFromHeaders(), resolvedApiVersion(), matchesApiVersion(), withPath() for /v1/... and header-based versions. ErrorRenderer JSON notFound uses Response::notFound(); 500 JSON uses apiError().
  • ORM eager loading: Model::eagerRelations() maps relation method names to belongsTo, hasMany, or belongsToMany specs so QueryBuilder::with() batches related queries. Nested relations use dot paths (e.g. author.country). Without a map entry, with() still resolves by calling the relation method on each model. Invalid spec entries throw InvalidArgumentException.
  • Route model binding: Router::model($parameter, $modelClass, $column = 'id') and Router::bind($parameter, Closure $resolver); Route::model / Route::bind delegate to the active router. Resolvers run before the action; missing model or resolver returning null yields ErrorRenderer::notFound() (404). Model class must extend Model.
  • Model global scopes: Model::addGlobalScope() registers named callbacks applied when building query(); QueryBuilder::withoutGlobalScope() / withoutGlobalScopes(); all() and find() use query() so scopes apply (breaking if you relied on unscoped direct SQL).
  • Model soft deletes: $softDeletes, $deletedAtColumn; find() / all() / QueryBuilder exclude trashed by default; withTrashed(), onlyTrashed(); instance delete() / restore() / forceDelete(); mass soft delete via query delete(); onlyTrashed()->delete() hard-deletes. updateRecord() adds deleted_at IS NULL when soft deletes are enabled.
  • Model casts: protected static array $casts on Model (int, float, bool, string, json/array, datetime); applied in fromRow() and when persisting via gatherFillableFromInstance() / updateRecord().
  • Model observers: Model::observe() registers handlers per model class; lifecycle hooks saving, creating, updating, deleting, saved, created, updated, deleted run around create(), save(), and delete(). **`Model::forgetRegisteredObs...
Read more

v0.7.0

03 Apr 23:24

Choose a tag to compare

Added

  • Fluent validation rule builder Vortex\Validation\Rule with inline per-rule message support; Validator::make() now accepts rule objects.
  • Fluent response/session flash helpers: Response::with(), withMany(), withErrors(), withInput(), and session batch helpers Session::flashMany() / flashPutMany().
  • Request-aware response shortcuts: Response::error(), notFound(), forbidden(), and unauthorized() that auto-select HTML or JSON output.

Changed

  • Request::wantsJson() now treats X-Requested-With: XMLHttpRequest as JSON-preferring requests.
  • Breaking: composer.lock is no longer tracked in the repository and is now ignored.

v0.6.0

03 Apr 22:37

Choose a tag to compare

Added

  • Model relation helpers in Vortex\Database\Model: belongsTo, hasMany, and belongsToMany.
  • Query builder feature expansion in Vortex\Database\QueryBuilder: select, with (eager loading), joins, grouped/or where clauses, pluck, value, bulk update, delete, and raw result methods.
  • Configurable Twig extension registration via app.twig_extensions in app config; extensions are injected through Vortex\View\Factory.
  • Twig function benchmark_ms() for reading named benchmark timings in views.

Changed

  • Breaking: Migration classes now extend abstract Vortex\Database\Schema\Migration and implement parameterless up()/down() methods.
  • Breaking: Migration IDs are now resolved from migration filenames instead of Migration::id().
  • Schema builder now exposes static entrypoints (Schema::create, Schema::table, Schema::dropIfExists) with connection scoping handled by the migrator.
  • Console command execution flow is unified under the base Vortex\Console\Command lifecycle.
  • Default model table-name resolution now pluralizes snake_case model names; explicit protected static ?string $table overrides are supported.

v0.5.0: Release 0.5.0.

03 Apr 19:26

Choose a tag to compare

Added

  • Optional config/paths.php — configure migrations (migration class directory) relative to the project root. Vortex\Support\AppPaths resolves it and CLI commands use the same rules.

Changed

  • Breaking: Console commands (migrate, migrate:down, db-check) now boot the app container directly via Application::boot(); startup container files are no longer required.

v0.3.0: Release 0.3.0

03 Apr 18:05

Choose a tag to compare

Added

  • Class-based database migrationsdatabase/migrations/*.php classes with id(), up(), and down(); SchemaMigrator and Vortex\Database\Schema (Schema, Blueprint, ColumnDefinition, Migration); php vortex migrate and migrate:down (rollback last batch); state in vortex_migrations.
  • Database\Schema\Schema fluent builder with Laravel-like columns (id, string, text, integer, boolean, timestamp, timestamps, foreignId, index, unique).
  • mockery/mockery as a dev dependency; MockeryIntegrationTest exercises container wiring with mocks.
  • Application::boot() loads .env via Env::load, registers Csrf, LocalPublicStorage, Translator, and ErrorRenderer, shares appName into Twig, and accepts an optional ?callable $configure(Container, string $basePath) after defaults (before route discovery).

Changed

  • Breaking: Database migrations are class-based (see Added). Older ad-hoc migration formats are not supported by migrate.