简体   繁体   中英

How to structure Laravel applications when not using Eloquent ORM

I'm new to Laravel and am working on a collection of API endpoints that fetch data from a variety of database tables, transforms and processes that data, and then returns it as a JSON response. What I'm struggling to decide, from reading the documentation, is where my processing/transformation code should live.

I've setup my routes in routes/api.php, and have them point towards a Controller subclass, but from here things get a little murky because I'm not currently looking to make use of Eloquent ORM. It seems like typically I'd generate Model subclasses for each database table, and have a Repository call into those and transform the returned data, like so:

Route => Controller => Repository => Model

But where should I be placing both the database query code, and the logic required to process/transform that data (the business logic), when not making use of Eloquent ORM or the Model paradigm? Making the controller fat with DB queries and logic seems like a messy solution, but at the same time a lot of the Laravel DB example code does place logic in Controller subclasses.

So I'll offer an approach that is I think accomplishes what you are asking. In the API I developed, I used the route/api.php file to create the API endpoints. Each of these point to a Controller where the authentication and request validation is performed. The Controller then calls a Service class that handles all the business logic of the application and these are the real heavy lifting parts. The Service class makes calls to a Repository , which actually performs Model changes and saving.

I saw this used in another project several years ago and mimicked it for my projects. The code flow is shown below. Not sure if it will work for you, but I find it to be a very neat and keeps the code grouped together in logical ways.

Route => Controller => Service => Repository => Model

Here is an example of how you can setup your project without Eloquent .

  1. Models are just data containers (records). They don't know how or where to store themselves. They are instantiated with some data and provide access for it:
class OrderRecord
{
    protected $id;
    protected $createdAt;

    public function __construct($id, $createdAt = null)
    {
        $this->id = $id;
        $this->createdAt = $createdAt ?: date('d-m-Y H:i:s');
    }

    public function getID()
    {
        return $this->id;
    }

    ...
}
  1. You read and write models only via repositories. Repository is just a class with your typical methods to retrieve/write one or multiple records (find, findAll, update, delete etc). It reads data, instantiates record(s) with it or take record(s), gets data from them and writes it. For example:
class OrderRepository
{
    public function find($id): OrderRecord
    {
        // Here goes your querying. StdClass will be returned in this case
        // that will be used to create new record.
        $row = DB::table('orders')->find($id);

        if ($row) {
            return (new OrderRecord($row->id, $row->created_at));
        } else {
            // If not found you can throw an exception or return null 
            // (return type should be ?OrderRecord then) depending on 
            // how you want to design your workflow with repositories.
            ...
        }
    }

    ...
}
  1. Lastly your business logic can be in your controllers. Your controllers should use repositories to get your model objects, work with them and the use repositories to store result if needed.

  2. Obviously, you will need to implement base classes/interfaces for all your entities. Use dependency injection and Laravel's service container to glue everything together.

You can also extend this design by separating querying and mapping in your repository - you will have Repository classes that know only how to retrieve/store raw data and you will have Mapper classes that know how to create/retrieve raw data to/from your records (and serve as factories that repository will use to generate record objects from query results). If business logic also need to be interchangeable then you can also take business logic out of your controllers and put it into separate classes that your controller can utilize.

Here is an excellent article about repository-based approach and how you can extend it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM