Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Mvc Tools Laravel Package

zetacomponents/mvc-tools

Zeta Components MVC Tools offers a lightweight MVC layer for PHP, with dispatchers, controllers, request/response objects, routing, and filters to structure web apps cleanly and flexibly.

View on GitHub
Deep Wiki
Context7

Getting Started

MvcTools is the routing/controller/view layer of Apache Zeta Components: a small pipeline you assemble yourself, not a framework that discovers your code. The mental model is fixed and easy to hold in your head:

  1. a request parser turns superglobals into an ezcMvcRequest
  2. a router produces ezcMvcRoutingInformation (controller class + action + captures)
  3. a controller returns an ezcMvcResult (status, variables, headers, cookies, cache)
  4. a view turns that result into an ezcMvcResponse
  5. a response writer emits it

Every one of those is an interface, so day-to-day work is mostly writing five small classes and wiring them in one configuration object.

Install:

composer require zetacomponents/mvc-tools

It pulls zetacomponents/base. Before investing, run it on your target PHP version — the code predates PHP 7 and Zeta Components is archived, so expect deprecation fixes on PHP 8.

Where to look first, in this order:

  • src/interfaces/ — ezcMvcDispatcherConfiguration, ezcMvcRouter, ezcMvcController, ezcMvcView, ezcMvcRequestParser, ezcMvcResponseWriter, ezcMvcFilter. These are the contracts you implement.
  • src/ — the HTTP defaults: ezcMvcHttpRequestParser, ezcMvcHttpResponseWriter, ezcMvcConfigurableDispatcher, ezcMvcRegexpRoute.
  • Classes are un-namespaced (ezcMvc*), so grep is your navigation tool; there is no generated API index you can trust across versions.

First use case — GET /hello/World returning HTML. Front controller only:

// public/index.php
require __DIR__ . '/../vendor/autoload.php';

$dispatcher = new ezcMvcConfigurableDispatcher( new App\DispatcherConfiguration() );
$dispatcher->run();

The composition root is a single class implementing ezcMvcDispatcherConfiguration:

class DispatcherConfiguration implements ezcMvcDispatcherConfiguration
{
    public function createRequestParser()
    {
        return new ezcMvcHttpRequestParser();
    }

    public function createRouter( ezcMvcRequest $request )
    {
        return new App\Router( $request );
    }

    public function createController( ezcMvcRequest $request, ezcMvcRoutingInformation $info )
    {
        $class = $info->controllerClass;
        return new $class( $info->action, $request );
    }

    public function createView( ezcMvcRoutingInformation $info, ezcMvcRequest $request, ezcMvcResult $result )
    {
        return new App\HtmlView( $request, $result );
    }

    public function createResponseWriter( ezcMvcRequest $request )
    {
        return new ezcMvcHttpResponseWriter();
    }

    public function createFatalResponse( ezcMvcRequest $request )
    {
        // return an error response/view — and log here
    }
}

Copy the interface out of vendor/zetacomponents/mvc-tools/src/interfaces/ rather than any tutorial: method signatures drift between releases, and a missing method is a fatal error at boot.

Implementation Patterns

The configuration class is the composition root. Keep it boring. If controllers need a repository or logger, instantiate them in createController() (or inject a small factory). There is no container, so the config doubles as your service locator — resist letting it grow into business logic.

Routing. Subclass ezcMvcRouter and return route objects from createRoutes(), or implement createRoutingInformation() by hand when you need HTTP-method, subdomain, or header-based routing. MvcTools does not care about verbs by default; check $request->method yourself. Regex captures typically land in $request->variables.

// inside a controller action
$id = (int) $this->request->variables['id'];

Controllers. Public methods named after the action, one controller per resource, constructor gets ($action, ezcMvcRequest $request). Return an ezcMvcResult and set status, variables, headers, cache, cookies on it — never echo.

Redirects. ezcMvcInternalRedirect re-enters the dispatcher without a browser round trip (post/redirect/get, or fallback handling); ezcMvcExternalRedirect sends the browser elsewhere.

public function create()
{
    $id = $this->repository->insert( $this->request->variables );
    return new ezcMvcInternalRedirect( '/user/' . $id );
}

Views. One view class per output format is the cleanest split. A shared base class that copies result fields into the response saves you from silent dropped headers.

class JsonView extends ezcMvcView
{
    public function createResponse( ezcMvcRoutingInformation $info, ezcMvcRequest $request )
    {
        $response = new ezcMvcResponse();
        $response->headers['Content-Type'] = 'application/json';
        $response->body = json_encode( $this->result->variables );
        return $response;
    }
}

For HTML, render PHP templates with output buffering, or use the built-in zone mechanism (createZone) if you want layout/partial composition without a template engine.

Filters for cross-cutting concerns. Auth, locale/translation, request logging, CORS, ETag/cache headers — register them in the configuration and keep them stateless. They run on every request, including redirects, so order matters and they should be cheap.

Testing is the real win. Skip the HTTP layer entirely: construct ezcMvcRequest and ezcMvcResult by hand, call the controller action, then call the view. Only ezcMvcHttpRequestParser and ezcMvcHttpResponseWriter need integration tests.

Running outside Apache/FPM. Swap the parser for one fed by a PSR-7 request (or a long-running worker's request object) and swap the writer for one that returns a PSR-7 response. Nothing else changes — this is the seam that makes the package usable in a modern stack.

Sizing. A handful of routes and hand-rolled templates: good fit. Anything larger: keep business logic out of controllers from day one, because there is no auto-wiring to bail you out later.

Gotchas and Tips

  • Maintenance risk is the headline. Apache Zeta Components is archived; 9 stars and 0 dependents means no community, no security feed, no fixes. Pin the version, and budget for PHP 8 cleanup (dynamic properties, removed functions, interpolation deprecations). Treat it as vendored infrastructure, not a dependency you can lean on.
  • No namespaces / autoloader confusion. Classes are ezcMvc*. Composer autoloading works through the package's own config, but mixing in the bundled ezcBase autoloader manually causes "class not found" surprises. Never require_once individual classes.
  • Superglobal coupling. ezcMvcHttpRequestParser reads $_SERVER, $_GET, $_POST, $_FILES, and headers directly. It is awkward to test and unsafe under long-running workers where globals go stale — write your own parser for those environments.
  • Interface drift. Hook names and signatures differ across releases, and createFatalResponse / redirect handling is easy to misread. Always copy from the installed src/interfaces/.
  • Action whitelisting is a security boundary. The action name comes from the URL and is invoked directly on the controller. Validate $info->action against a per-controller whitelist in createController() so public helper methods can't be reached.
  • Result vs response duplication. Headers, cookies, cache, and status live on ezcMvcResult; the view must copy them onto ezcMvcResponse. Forget one and it silently vanishes. Centralize the mapping in a base view.
  • Filters: order and contract. Filters run in array order; check whether filter() mutates and returns, or returns a new object, for your version. An exception inside a filter will typically fall through to the fatal-response path — log inside filters rather than relying on the error handler.
  • Debugging is manual. There is no toolbar. Temporarily log the parsed ezcMvcRequest, the ezcMvcRoutingInformation, and the final response status/body length from inside the configuration's factory methods. Log $e in createFatalResponse or you get a blank 500 with no trace.
  • Performance. Every request re-runs regex route matching and re-instantiates controllers — no route cache, no container. Fine at small scale; cache compiled routes yourself if traffic grows.
  • Best extension points: custom ezcMvcRequestParser (CLI/tests/PSR-7), custom ezcMvcResponseWriter (streaming, JSON, PSR-7), custom router (verbs, subdomains), and filters (auth, i18n). Those are the seams worth building on; everything else you replace wholesale.
  • Greenfield caveat. Treat MvcTools as a teaching-grade MVC kernel and a design reference (result/view separation, filter stages). For shipping, pick Slim, Laravel, or Symfony unless you are already maintaining an MvcTools codebase.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle