diff --git a/docs/dependency-injection.md b/docs/dependency-injection.md index 364879f..f414540 100644 --- a/docs/dependency-injection.md +++ b/docs/dependency-injection.md @@ -5,8 +5,8 @@ codebases. Instead of leaving it up to each class to create and configure its dependencies, a service container _injects_ those dependencies into classes as they are being instantiated. -To demonstrate what we're talking about, consider a class that needs a database -connection to do something useful. +To demonstrate this concept, consider a class that needs a database connection to +do something useful. ```php db - ->insert('users', func_get_args()); + ->insert('users', [ + 'username' => $username, + 'pw_hash' => password_hash($password, PASSWORD_DEFAULT) + ]); } } ``` @@ -32,8 +35,9 @@ throughout the application, and allows different configurations of the class ## Literals and Factories In cases where Kick knows how to create all dependencies of a class, it will -automatically construct the class when requested. This is called auto-wiring, -and it enables quicker development while cutting down on configuration. +automatically construct the class when it needs to be resolved. This is called +auto-wiring, and it enables quicker development while cutting down on manual +configuration. In some cases however, Kick cannot determine all dependencies. Take the `Database` from the earlier example. We would typically require a host and some credentials @@ -56,18 +60,20 @@ $container->literal('apiKey', getenv('API_KEY')); A factory service definition on the other hand binds a service name to a `callable` that is responsible for building the service on demand. This is useful in situations -where the service isn't required on every request and you want it created on demand. +where the service isn't required on every request and you want it constructed lazily. ```php $container->factory(Database::class, fn () => new Database($container->resolve('dsn'))); ``` +Note that once resolved, an object created by a factory is cached and returned on +subsequent requests for that service. + ## Providers -A Kick application can be passed a service provider, which is simply a `callable` -that is passed the container as an argument. A service provider can be used to -define services that cannot be automatically resolved and perform other initialization -required at application boot. +A Kick application can be configured with any number of service providers, tasked +with defining base depenendencies and performing other initialization during boot. +A service provider is simply a `callable` that receives an instance of `Kick\Service\Container`. ```php withProvider(fn (Container $c) => - $c->literal(Database::class, new Database('sqlite::memory:')) + ->withProvider(fn (Container $c) => $c + ->literal('db_dsn', 'sqlite::memory:) + ->factory(Database::class, fn () => new Database($c->resolve('db_dsn'))) ); ``` @@ -87,14 +94,15 @@ To resolve a service, `Container::resolve()` can be called with the desired service name. This should only be necessary within a service provider, because Kick will automatically resolve dependencies when invoking route handlers and middleware. Any type-hinted parameter specified on a route handler or middleware -`callable` will be auto-injected by the service container. +closure will be auto-injected by the service container. ```php - +use Kick\Http\Request; + +return fn (Request $request, Database $db) => $db - ->query('select * from posts') + ->query('select * from posts where uid = ?', $request->get('uid')) ->fetchAll(); ``` diff --git a/docs/getting-started.md b/docs/getting-started.md index 611bb4a..f4a358b 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -38,8 +38,8 @@ use Kick\Http\Request; ## Defining a route In our example configuration, files found under the `pages/` directory will map -to URIs that are understood by the application. A route file must return a `callable` -which accepts the incoming request as an argument and returns a response. +to URIs that are available in the application. A route file must return a closure +that accepts the incoming request as an argument and returns a response. Let's create a file named `pages/greeting/_name.get.php`: @@ -52,7 +52,7 @@ use Kick\View\Element as e; return fn (Request $request) => e::html( e::body( - e::h1('Hello, ', $request->get('name'), '!'), + e::h1('Hello, ', ucfirst($request->get('name')), '!'), e::p('Welcome to Kick.') ) ); @@ -71,5 +71,5 @@ command: php -S 0.0.0.0:3000 -t public/ ``` -Navigate to `http://0.0.0.0:3000/greet/name` in the browser and replace `name` +Navigate to `http://0.0.0.0:3000/greeting/kick` in the browser and replace `kick` with different values to get different greetings. diff --git a/docs/routing.md b/docs/routing.md index c256d96..e80add8 100644 --- a/docs/routing.md +++ b/docs/routing.md @@ -11,10 +11,11 @@ for an example. ## Naming conventions -The names of route files and paths can alter their behaviour ways: +The names of route files and paths will alter their behaviour in different ways: - Files named `__middleware.php` specify middleware for the current and child paths. Middleware is discussed later in this section. +- Files named `index.php` map to the resource `/` in a given path. - Names prefixed with an underscore define dynamic URI segments. As an example, `/posts/_pid/comments.php` would expand to the URI `/posts/:pid/comments`. - Using a file extension prefixed with an HTTP method restricts that route to @@ -23,8 +24,8 @@ by an HTTP `GET` request. ## Handlers -Route handlers are simply `callables` that take a `Request` object and return -a primitive PHP type, view or `Response` object. Whatever the response, the +Route handlers are simply closures that take a `Request` object and return +a primitive PHP type, `Element` or `Response` object. Whatever the response, the application will automatically translate it into a `Request` with appropriate `Content-Type` header. Route files must return a handler. @@ -38,18 +39,18 @@ return fn (Request $request) => e::p('Hello, world!'); ``` The `Request` object will be injected automatically, and any other type-hinted -parameter will also be injected by the service container. To get the value of a +parameters will also be injected by the service container. To get the value of a dynamic path segment, the `Request::$segments` array can be used, or a call to `Request::get()` with the segment name will return its value. ## Middleware -A `__middleware.php` file must return a `callable` or an array of container -service names that resolve to `callables`. Middleware are very similar to route -handlers, but in addition to a `Request` object they are also passed a `callable` -to be invoked before or after the middleware has done its work. This `callable` -executes the next middleware in the stack, returning the resulting `Response`, -or the route handler if all middleware have been invoked. +A `__middleware.php` file must return a closure or an array of container service +names that resolve to `callable`. Middleware are very similar to route handlers, +but in addition to a `Request` object they are also passed a `callable` to be +invoked before or after the middleware has done its work. This `callable` executes +the next middleware in the stack, or the route handler if all middleware have been +invoked, returning the resulting `Response`, The following middleware uses a hypothetical `Auth` class to protect routes from unauthorized users. @@ -60,14 +61,14 @@ unauthorized users. use Kick\Http\Request; return function (Request $request, callable $next, Auth $auth) { - if (!$auth->hasActiveSession()) { + if (!$auth->hasActiveSession() && $request->path !== '/login') { return new Response(302, ['location' => '/login']); } return $next($request); }; ``` -Note that the result of the `$next` callable is returned. -Middleware can also modify responses by doing work after the callable is invoked. -Middleware encountered earlier in the path are executed before or "around" the -middleware encountered later in the path. + +Note that the result of the `$next` callable is returned. Middleware can also modify +responses by doing work after the callable is invoked. Middleware encountered earlier +in the path are executed before, or "around", middleware encountered later in the path. diff --git a/docs/views.md b/docs/views.md index 1143dd4..0787cf7 100644 --- a/docs/views.md +++ b/docs/views.md @@ -1,8 +1,8 @@ # Views The `Kick\View\Element` class is responsible for generating HTML directly from -PHP code. Instead of calling out to a separate templating language, views can -be composed through the use of PHP functions, classes, loops and conditionals. +PHP code. Instead of calling out to a separate templating language, views are +composed through the use of PHP functions, classes, loops and conditionals. ```php e::ul( array_map(($i) => e::li($i), $items) ); + +$list(['apple', 'bannana', 'carrot']); ``` ## Adding client-side functionality