Skip to content

Framework architecture #1

@AlexandreGerault

Description

@AlexandreGerault

This is where I will discussed for myself of high level details on the framework architecture.

Introduction

This PHP framework is an objectif to practice OOP with PHP for my formation at OpenClassrooms. I want to write the code

  • respecting as much as possible the SOLID principles
  • taking into account static analysis with type hinting (typing the parameters, the class attributes, the function return type)
  • using less dependencies as possible
  • reducing code pairing as much as possible
  • getting the higer score possible on SymfonyInsight or Codacy

Parts of the framework

In order to reduce code pairing as much as possible, we'll design reusable classes that does not depend one on another on different parts of the framework (i.e. the router should not depend on the caching implementation for exemple), and we'll respect the dependency inversion principle and dependency injection.

Dependency injection

The dependency inversion principle is the process of injecting dependencies in the constructor instead of intantiating the dependency inside the constuctor. Doing that, we do not depend on the way we create the dependency inside the class which is great, allowing us, for example, to mock easily dependencies during the testing process.

We'll need a component that handle the responsability of instantianing my services and also to instantiate (if they do not exist yet)
its dependencies. This is the dependency injection container. They is a recommandation done by the PHP-FIG team, the PSR-11 that defines an interface and behavior of a container. We will use it to write our dependency injection container.

Caching

The cache is a place we store values that are often used in order to save calculation time or to avoid long I/O tasks. It has to store items kinda like a map, with a system of key designing a value. We also have to think of a TTL (Time-To-Live) system for items as a cache is not a definitive storing like a database for example. Again, we have a recommandation on methods that should be implemented on a cache class : the PSR-6.

As caching is storing values, we'll have to think of the way it stores values. Should it be only on local storage in files (using json for example with a SerializableInterface interface on objects 🤔 )? Should we provide different drivers that would allow people to cache on S3 for example? (the last solution won't be implemented if chosen, but we would provide a default driver, with a possibility to set the driver and an interface that the user would be able to implement to code its own driver)

Database

To use a SQL database, we'll want some classes to make our life easier. For this, we'll need some classes to perform queries BUT we'll decide to not implement features handling INSERT request in non prepared request to avoid SQL injection. We'll see later if we do it with a warning or thing like that.

ORM

The ORM accronym stands for Object Relationnal Mapping. It means that, when we'll fetch rows from the database, we'll try to transform this resulsts into real PHP objects so that it will be easier to work with in our project codebase. We'll also try to implement a query builder to make relationnal mapping possible but as it seems to be a pretty hard stuff we'll only do that if we have enough time left.

Http

This group of classes is quite big. It will group classes representing the Http messages: requests, responses, request/response factories etc. We will first focus on the recommandations from the PHP-FIG team:

  • PSR-7 to represent Http messages ;
  • PSR-15 for Http handlers and middlewares ;
  • PSR-17 for factories ;
  • PSR-18 for clients (classes used to perform http actions, such as using an API).

If we realise we don't have the time to implement all of these PSR features, we will use libraries for that.

Routing

Routing is the process where it matches an incoming request path to a controller's action (a method in a controller). Then we have to define what routes exist, and for each, which php code should be called. We can identify at least two classes: the Router which will owns Routes. No recommandation seems to exist (and will probably never exist as it really depends on the framework and no library may need to use it, so it may not have the need to uniformize the contract of a router).

We will need a router able to:

  • Register routes ;
  • Match an incoming request to a route ;

The matching process would be very simple if we forget some important pieces... We must remember that a route has:

  • Some methods it supports (for example, the homepage might only support the GET method) ;
  • Some path parameters (a slug, an id, that kind of sutff) ;
  • Some queries in the URL

As we can see it in Laravel, we will might appreciate to be able to create group of route, to add some classes to be executed before handling the matched action (HTTP Handlers/Middleware) etc but we have a basic idea here what our router should do.

Coding styles

To keep the code nice to read at, I'll follow the PSR-12 recommandations. To keep tracking that my code is successfully formatted, I'll use PHPCodeSniffer.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions