laravel 怎么规划多应用喃?

laravel 怎么规划多应用喃? 比如现在业务 有
APP端需要提供api
后端管理模块也需要提供api
开放服务对外提供接口支持也需要提供api
等等等。。。。后面可能需要增加更多的业务模块
这些应该怎么架构和规划业务喃?
是不是不能像TP那样本来就提供多应用?那么laravel应该怎么处理比较优雅喃?

《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 20

引入服务的概念,把业务和服务区分开。例如上面提到的三个地方的api都需要用到查询,如果单纯的只是区分分块的话,那就成了下面这样:

// appapi
$user = User::find($id);

// adminapi
$user = User::find($id);

// openapi
$user = User::find($id);

好,三个同样的代码,我可以直接封装成一个方法并且优化后再调用:

//common/user/userController
public function getUser($condition) {
    return User::query->where($condition)->first();
}

一般这样的封装可以满足大部分的需求,就算是后续修改也只需要修改这个common/user/userController下的函数。
但是再深入一些,符合单一、无状态原则,可以把查询用户封装成服务,控制器在业务层调用不同的服务。例如我需要查询用户的信息和房间信息。

// 用户查询的接口
Interface UserInfoInterface{
    public function getUserInfoById($id);
}

// 房屋接口
Interface RoomInterface{
    public function getRoomByUserId($userId);
}

// 实现用户接口的service类:
class UserInfoService implements UserInfoInterface{
    protected $userInfoRepository;
    public function __construct(UserInfoRepository $userInfoRepository){
        $this->userInfoRepository = $userInfoRepository;
    }
    public function getUserInfoById($id){
        return $this->userInfoRepository->getUserInfoById($id);
    }
}

// 实现房间接口的service类:
class RoomService implements RoomInterface{
    protected $roomRepository;
    public function __construct(RoomRepository $roomRepository){
        $this->roomRepository = $roomRepository;
    }
    public function getRoomByUserId($userId){
        return $this->roomRepository->getRoomByUserId($userId);
    }
}

// 用户数据仓库
use App\Models\UserInfo;

class UserInfoRepository{
    public function getUserInfoById($id){
        return UserInfo::query()->find($id);
    }
}

// 房屋数据仓库
use App\Models\Room;

class RoomRepository{
    public function getUserInfoById($userId){
        return Room::query()->where("user_id",$userId)->first();
    }
}

//App\Providers\AppServiceProvider.php的register()中进行接口注入,这一步的作用可以省去在构造函数中依赖注入的方式引用service,在程序中任意地方都可以通过app(UserInfoService::class)的方式调用。

public function register()
{
  $this->app->bind(UserInfoInterface::class, UserInfoService::class);
  $this->app->bind(RoomInterface::class, RoomService::class);
}

//控制器调用service
class UserController extends BaseController
{
  private $userInfoService;
  private $roomService;
  public function __construct()
  {
      //使用app()的方式,可以调用多个sevice,而不用在参数中进行注入
      $this->userInfoService = app(UserInfoService::class);
      $this->roomService = app(RoomService::class);
  }


  public function getUserInfoById($id) {
      $data = [];
    // 获取用户信息
      $userInfo = this->userInfoService->getUserInfoById($id);
      if(!userInfo) {
          return false;// 在这里写返回的错误数据格式
      }
      $room = this->userInfoService->getUserInfoById($userInfo->id);
      $data = [
          "userInfo" => userInfo,
        "room" => room
      ];
      ...
      //后续自己优化,可以调用不同的无状态的服务,获取需要的结果
  }
}

这样做的好处就是,后续有修改,可以只修改一个地方,或者需求变更,有某个地方需要特定的方法来进行查询,那就从interface开始重新写一个方法,这样的好处就是解耦,以前的需求也不受影响!

当然,还有另外一种写法,把业务代码放入service中,service中调用不同的数据仓库来获取相应的数据。例如还是上述的例子,我可以在service中定义一个对外提供的方法,然后在这个方法中调用UserRepositoryRoomRepository

开始开发的时候会感觉很多余,但是后续就很舒服了。

1年前 评论
黑将军

laravel-modules扩展包

1年前 评论
tiantian10000 (楼主) 1年前
黑将军 (作者) 1年前

引入服务的概念,把业务和服务区分开。例如上面提到的三个地方的api都需要用到查询,如果单纯的只是区分分块的话,那就成了下面这样:

// appapi
$user = User::find($id);

// adminapi
$user = User::find($id);

// openapi
$user = User::find($id);

好,三个同样的代码,我可以直接封装成一个方法并且优化后再调用:

//common/user/userController
public function getUser($condition) {
    return User::query->where($condition)->first();
}

一般这样的封装可以满足大部分的需求,就算是后续修改也只需要修改这个common/user/userController下的函数。
但是再深入一些,符合单一、无状态原则,可以把查询用户封装成服务,控制器在业务层调用不同的服务。例如我需要查询用户的信息和房间信息。

// 用户查询的接口
Interface UserInfoInterface{
    public function getUserInfoById($id);
}

// 房屋接口
Interface RoomInterface{
    public function getRoomByUserId($userId);
}

// 实现用户接口的service类:
class UserInfoService implements UserInfoInterface{
    protected $userInfoRepository;
    public function __construct(UserInfoRepository $userInfoRepository){
        $this->userInfoRepository = $userInfoRepository;
    }
    public function getUserInfoById($id){
        return $this->userInfoRepository->getUserInfoById($id);
    }
}

// 实现房间接口的service类:
class RoomService implements RoomInterface{
    protected $roomRepository;
    public function __construct(RoomRepository $roomRepository){
        $this->roomRepository = $roomRepository;
    }
    public function getRoomByUserId($userId){
        return $this->roomRepository->getRoomByUserId($userId);
    }
}

// 用户数据仓库
use App\Models\UserInfo;

class UserInfoRepository{
    public function getUserInfoById($id){
        return UserInfo::query()->find($id);
    }
}

// 房屋数据仓库
use App\Models\Room;

class RoomRepository{
    public function getUserInfoById($userId){
        return Room::query()->where("user_id",$userId)->first();
    }
}

//App\Providers\AppServiceProvider.php的register()中进行接口注入,这一步的作用可以省去在构造函数中依赖注入的方式引用service,在程序中任意地方都可以通过app(UserInfoService::class)的方式调用。

public function register()
{
  $this->app->bind(UserInfoInterface::class, UserInfoService::class);
  $this->app->bind(RoomInterface::class, RoomService::class);
}

//控制器调用service
class UserController extends BaseController
{
  private $userInfoService;
  private $roomService;
  public function __construct()
  {
      //使用app()的方式,可以调用多个sevice,而不用在参数中进行注入
      $this->userInfoService = app(UserInfoService::class);
      $this->roomService = app(RoomService::class);
  }


  public function getUserInfoById($id) {
      $data = [];
    // 获取用户信息
      $userInfo = this->userInfoService->getUserInfoById($id);
      if(!userInfo) {
          return false;// 在这里写返回的错误数据格式
      }
      $room = this->userInfoService->getUserInfoById($userInfo->id);
      $data = [
          "userInfo" => userInfo,
        "room" => room
      ];
      ...
      //后续自己优化,可以调用不同的无状态的服务,获取需要的结果
  }
}

这样做的好处就是,后续有修改,可以只修改一个地方,或者需求变更,有某个地方需要特定的方法来进行查询,那就从interface开始重新写一个方法,这样的好处就是解耦,以前的需求也不受影响!

当然,还有另外一种写法,把业务代码放入service中,service中调用不同的数据仓库来获取相应的数据。例如还是上述的例子,我可以在service中定义一个对外提供的方法,然后在这个方法中调用UserRepositoryRoomRepository

开始开发的时候会感觉很多余,但是后续就很舒服了。

1年前 评论

N套代码,根据业务独立部署,全部写在一起,找起来和维护起来不费力吗?

1年前 评论
tiantian10000 (楼主) 1年前
ononl (作者) 1年前
ononl (作者) 1年前

1、app 目录下新建 Admin (后端) Api(app接口)如 app/Api 目录下的结构跟默认的 app/Http 目录保持一致。

2、新建路由 routes/admin.php routes/api.php

3、注册路由 App\Providers\RouteServiceProvider::boot() 方法中注册,如下:

Route::prefix('api')
    ->middleware('api')
    ->group(base_path('routes/api.php'));

Route::prefix('admin')
    ->middleware('api')
    ->group(base_path('routes/admin.php'));
1年前 评论
tiantian10000 (楼主) 1年前
看上隔壁小花了啦 (作者) 1年前

常规的就app分组,每个api一个大组。

太大了还是拆分为多个系统好,有些api简单,单独一个系统更好维护

1年前 评论

可以自荐一下我们的模块规划么 :blush:

1年前 评论
tiantian10000 (楼主) 1年前

我也是刚从tp转过来,也有这样的疑惑,难道得APP一个项目,后台管理系统一个项目,还有其他的。。。感觉这样好分散啊,楼主有没有好的建议?

1年前 评论

这好像没啥问题啊,,,最多也就登录不一样吧,这个配置一下简单的很,,,

1年前 评论
mouyong

gitee.com/fresns/plugin-manager/ 你试试?可以按照多应用的玩法去玩。可以自行开发插件。

玩法如下:

composer config repositories.plugin-manager vcs https://gitee.com/fresns/plugin-manager

composer require fresns/plugin-manager:2.x-dev

php artisan fresns

开发见图:

Laravel

Laravel

使用效果见图:

Laravel

1年前 评论

建议你早点按照项目分开,别用那种丑陋的文件和module区分

1年前 评论
QIN秦同学
  • 从绩效和维护看:分开项目单独部署要好一点。
  • 从以后扩展看:干大了,想上微服务几乎不用拆分,无缝衔接。
  • 从新人上手看:来个新人哪里需要往哪去,了解的少,上手快。
  • 到一块也有好处:就是除了你别人整不了,也算是变相的不可替代性。
1年前 评论
QIN秦同学 (作者) 1年前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!