11# Middle Framework
22
3- [ ![ Scrutinizer Code Quality ] ( https://scrutinizer-ci .com/g/ jschreuder/Middle/badges/quality-score.png?b=master )] ( https://scrutinizer- ci.com/g/jschreuder/Middle/?branch=master )
4- [ ![ Code Coverage ] ( https://scrutinizer-ci.com/g/jschreuder/Middle/badges/coverage.png?b=master )] ( https://scrutinizer-ci.com/g/jschreuder/Middle/?branch=master )
5- [ ![ Build Status ] ( https://scrutinizer-ci.com/g/jschreuder/Middle/badges/build.png?b=master )] ( https://scrutinizer-ci.com/g/jschreuder/Middle/?branch=master )
3+ ![ Build ] ( https://github .com/jschreuder/middle/actions/workflows/ ci.yml/badge.svg )
4+ [ ![ Quality Gate ] ( https://sonarcloud.io/api/project_badges/measure?project=jschreuder_Middle&metric=alert_status )] ( https://sonarcloud.io/dashboard?id=jschreuder_Middle )
5+ [ ![ Coverage ] ( https://sonarcloud.io/api/project_badges/measure?project=jschreuder_Middle&metric=coverage )] ( https://sonarcloud.io/dashboard?id=jschreuder_Middle )
66
77** A micro-framework built around one simple principle: everything should be explicit, replaceable, and safe to change.**
88
@@ -26,7 +26,7 @@ Interface-driven design means every component can be easily mocked, tested in is
2626
2727Like other micro-frameworks, Middle is for composing applications. Unlike them, Middle nudges towards architectural boundaries through interfaces, making SOLID principles and domain-driven design the path of least resistance.
2828
29- ** Choose Middle when:** You want simplicity with architecture meant for SOLID and Domain Driven Development.
29+ ** Choose Middle when:** You want simplicity with architecture meant for SOLID and Domain Driven Development.
3030** Choose Others when:** You disagree with the philosophy or convention- or configuration-driven frameworks.
3131
3232## Core Philosophy
@@ -85,42 +85,42 @@ Middle doesn't compete with mature frameworks - it lets you **compose their prov
8585
8686``` php
8787// Your domain interface - exactly what your application needs
88- interface UserRepositoryInterface
88+ interface UserRepositoryInterface
8989{
9090 public function findByEmail(string $email): ?User;
9191 public function save(User $user): void;
9292 public function findActiveUsers(): array;
9393}
9494
9595// Adapter that wraps Doctrine behind your interface
96- class DoctrineUserRepository implements UserRepositoryInterface
96+ class DoctrineUserRepository implements UserRepositoryInterface
9797{
9898 public function __construct(private EntityManagerInterface $em) {}
99-
100- public function findByEmail(string $email): ?User
99+
100+ public function findByEmail(string $email): ?User
101101 {
102102 return $this->em->getRepository(User::class)->findOneBy(['email' => $email]);
103103 }
104-
105- public function save(User $user): void
104+
105+ public function save(User $user): void
106106 {
107107 $this->em->persist($user);
108108 $this->em->flush();
109109 }
110-
111- public function findActiveUsers(): array
110+
111+ public function findActiveUsers(): array
112112 {
113113 return $this->em->createQuery('SELECT u FROM User u WHERE u.active = true')
114114 ->getResult();
115115 }
116116}
117117
118118// Your controllers depend on YOUR interface, not Doctrine's
119- class UserController implements ControllerInterface
119+ class UserController implements ControllerInterface
120120{
121121 public function __construct(private UserRepositoryInterface $repository) {}
122-
123- public function execute(ServerRequestInterface $request): ResponseInterface
122+
123+ public function execute(ServerRequestInterface $request): ResponseInterface
124124 {
125125 // Clean, domain-focused code
126126 $users = $this->repository->findActiveUsers();
@@ -132,7 +132,7 @@ class UserController implements ControllerInterface
132132This approach delivers:
133133
134134- ** Library Independence** : Replace Doctrine with another ORM by implementing your interface
135- - ** Domain Clarity** : Your interfaces reflect business needs, not library abstractions
135+ - ** Domain Clarity** : Your interfaces reflect business needs, not library abstractions
136136- ** Future-Proof Evolution** : Library updates only require adapter changes, not application rewrites
137137- ** Focused Testing** : Mock exactly what your application needs, not complex library interfaces
138138
@@ -190,7 +190,7 @@ $app = new Middle\ApplicationStack(
190190);
191191
192192// Add a route
193- $router->get('home', '/',
193+ $router->get('home', '/',
194194 Middle\Controller\CallableController::factoryFromCallable(function () {
195195 return new Laminas\Diactoros\Response\JsonResponse([
196196 'message' => 'Welcome to Middle Framework'
@@ -228,7 +228,7 @@ Routes are added directly to the router instance using HTTP method helpers:
228228
229229``` php
230230// Simple routes with closures
231- $router->get('home', '/',
231+ $router->get('home', '/',
232232 Middle\Controller\CallableController::factoryFromCallable(function () {
233233 return new Laminas\Diactoros\Response\JsonResponse(['message' => 'Hello World']);
234234 })
@@ -284,20 +284,20 @@ $app = $app->withMiddleware(
284284Controllers can implement ` RequestFilterInterface ` and ` RequestValidatorInterface ` to handle input filtering and validation automatically:
285285
286286``` php
287- class CreateUserController implements ControllerInterface, RequestFilterInterface, RequestValidatorInterface
287+ class CreateUserController implements ControllerInterface, RequestFilterInterface, RequestValidatorInterface
288288{
289- public function filterRequest(ServerRequestInterface $request): ServerRequestInterface
289+ public function filterRequest(ServerRequestInterface $request): ServerRequestInterface
290290 {
291291 $data = $request->getParsedBody();
292292 if (is_array($data)) {
293293 $data['textfield'] = strip_tags(trim($data['textfield']));
294294 $request = $request->withParsedBody($data);
295295 }
296-
296+
297297 return $request;
298298 }
299-
300- public function validateRequest(ServerRequestInterface $request): void
299+
300+ public function validateRequest(ServerRequestInterface $request): void
301301 {
302302 $data = $request->getParsedBody();
303303 if (empty($data['email'])) {
@@ -307,8 +307,8 @@ class CreateUserController implements ControllerInterface, RequestFilterInterfac
307307 throw new ValidationFailedException(['email' => 'Invalid email format']);
308308 }
309309 }
310-
311- public function execute(ServerRequestInterface $request): ResponseInterface
310+
311+ public function execute(ServerRequestInterface $request): ResponseInterface
312312 {
313313 // Request is guaranteed to be filtered and valid
314314 $data = $request->getParsedBody();
@@ -376,7 +376,7 @@ class RedisSessionProcessor implements SessionProcessorInterface {
376376 public function processRequest(ServerRequestInterface $request): ServerRequestInterface {
377377 // Add session to request attributes
378378 }
379-
379+
380380 public function processResponse(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface {
381381 // Handle session persistence, cookies, etc.
382382 }
@@ -442,7 +442,7 @@ $app = $app->withMiddleware(
442442 new Middle\ServerMiddleware\RequestValidatorMiddleware($validationErrorHandler)
443443);
444444
445- // Automatically filter requests if controller implements RequestFilterInterface
445+ // Automatically filter requests if controller implements RequestFilterInterface
446446$app = $app->withMiddleware(
447447 new Middle\ServerMiddleware\RequestFilterMiddleware()
448448);
0 commit comments