[DOCUMENTATION] Added a code walkthrough document, which explains how the codebase works
This commit is contained in:
parent
0620d9a726
commit
bf88c97f4a
88
DOCUMENTATION/code_walkthrough.md
Normal file
88
DOCUMENTATION/code_walkthrough.md
Normal file
@ -0,0 +1,88 @@
|
||||
### Entrypoint
|
||||
|
||||
GNU social's entrypoint is the `public/index.php` script, which gets
|
||||
called by the webserver for all requests. This is handled by the
|
||||
webserver itself, which translates a `GET /foo` to `GET
|
||||
/index.php?p=foo`. This feature is called 'fancy URLs', as it was in V2.
|
||||
|
||||
The `index` script handles all the initialization of the Symfony
|
||||
framework and social itself. It reads configuration from `.env` or any
|
||||
`.env.*` file at the project root. The `index` script creates a
|
||||
`Kernel` object, which is defined on the `src/Kernel.php` file. This
|
||||
is the part where the code we control starts; the `Kernel` constructor
|
||||
creates the needed constants, sets the timezone to UTC and the string
|
||||
encoding to UTF8. The other functions in this class get called by the
|
||||
Symfony framework at the appropriate times. We will come back to this
|
||||
file.
|
||||
|
||||
### Registering services
|
||||
|
||||
Next, the `src/Util/GNUsocial.php` class is instantiated by the
|
||||
Symfony framework, on the `'onKernelRequest'` or `'onCommand'` events. The
|
||||
former event, as described in the docs:
|
||||
|
||||
> This event is dispatched very early in Symfony, before the
|
||||
> controller is determined. It's useful to add information to the
|
||||
> Request or return a Response early to stop the handling of the
|
||||
> request.
|
||||
|
||||
The latter, is launched on the `bin/console` script is used.
|
||||
|
||||
In both cases, these events call the `register` function, which
|
||||
creates static references for the logging, event and translation
|
||||
services. This is done so these services can be used via static
|
||||
function calls, which is much less verbose and more accessible than
|
||||
the way the framework recommends. This function also loads all the
|
||||
Modules and Plugins, which like in V2, are components that aren't
|
||||
directly connected to the core code, being used to implement internal
|
||||
and optional functionality respectively, by handling events launched
|
||||
by various parts of the code.
|
||||
|
||||
### Database definitions
|
||||
|
||||
Going back to the `Kernel`, the `build` function gets called by the
|
||||
Symfony framework and allows us to register a 'Compiler Pass'.
|
||||
Specifically, we register the `SchemaDefPass` from the
|
||||
`src/DependencyInjection/Compiler/SchemaDefPass.php` file, which adds
|
||||
a new 'metadata driver' to Doctrine. The metadata driver is
|
||||
responsible for loading database definitions. We keep the same method
|
||||
as in V2, which was that each 'Entity' has a `schemaDef` static
|
||||
function which returns an array describing the database.
|
||||
|
||||
This definition is handled by the `SchemaDefDriver` class from
|
||||
`src/Util/SchemaDefDriver.php` file, which extends `StaticPHPDriver`
|
||||
and replaces the methods `loadMetadata` with `schemaDef`. The function
|
||||
`loadMetadataForClass` function is called by the Symfony framework for
|
||||
each file in `src/Entity/`. It allows us to call the `schemaDef`
|
||||
function and translate the array definition to Doctrine's internal
|
||||
representation.
|
||||
|
||||
### Routing
|
||||
|
||||
Next, we'll look at the `RouteLoader`, defined in
|
||||
`src/Util/RoutLoader.php`, which loads all the files from
|
||||
`src/Routes/*.php` and calls the static `load` method, which defines
|
||||
routes with an interface similar to V2's `connect`, except it requires
|
||||
an extra identifier as the first argument. This identifier is used,
|
||||
for instance, to generate URLs for each route. Each route connects an
|
||||
URL path to a Controller, with the possibility of taking arguments,
|
||||
which are passed to the `__invoke` method of the respective
|
||||
controller. The controllers are defined in `src/Controller/` and are
|
||||
responsible for handling a request and return a Symfony `Response`
|
||||
object (subject to change, in order to abstract HTML vs JSON output).
|
||||
|
||||
### End to end
|
||||
|
||||
The next steps are handled by the Symfony framework which creates a
|
||||
`Request` object from the HTTP request, and then a corresponding
|
||||
`Response` is created by calling the `Kernel::handle` method, which
|
||||
matches the appropriate route and thus calls it's controller.
|
||||
|
||||
### Performance
|
||||
|
||||
All this happens on each request, which seems like a lot to handle,
|
||||
and would be too slow. Fortunately, Symfony has a 'compiler' which
|
||||
caches and optimizes the code paths. In production mode, this can be
|
||||
done through a command, while in development mode, it's handled on
|
||||
each request if the file changed, which has a performance impact, but
|
||||
obviously makes development easier.
|
Loading…
Reference in New Issue
Block a user