The Clean Architecture in PHP 读书笔记(十)

laravel

这是clean architecture的第十篇,也是具体案例的第二篇,本篇会通过使用laravel框架,来开发我们的应用。

本文为系列文章的第十篇,完成的目录请查看Clean Architecture

laravel的建立

composer create-project laravel/laravel --prefer-dist cleanphp-laravel

配置数据库采用sqlite,修改.env文件

DB_CONNECTION=sqlite
DB_DATABASE=/Users/zhuanxu/workspace/cleanphp-laravel/database/database.sqlite

此处DB_DATABASE换为你自己的路径,并新建database.sqlite,touch /Users/zhuanxu/workspace/cleanphp-laravel/database/database.sqlite

我们啊来建立我们的数据库sqlite3 database/database.sqlite,建表,插入数据。

CREATE TABLE customers ( id integer PRIMARY KEY, name varchar(100) NOT NULL, email varchar(100) NOT NULL );

CREATE TABLE orders ( id integer PRIMARY KEY, customer_id int REFERENCES customers(id) NOT NULL, order_number varchar(20) NOT NULL, description text NOT NULL, total float NOT NULL );

CREATE TABLE invoices ( id integer PRIMARY KEY, order_id int REFERENCES orders(id) NOT NULL, invoice_date date NOT NULL, total float NOT NULL );

INSERT INTO customers(name, email) VALUES('Acme Corp', 'ap@acme.com'); INSERT INTO customers(name, email) VALUES('ABC Company', 'invoices@abc.com');

建立Dashboard

我们通过命令

php artisan make:controller DashboardController

来新建控制器,并修改routes/web.php来设置路由

Route::get('/',"DashboardController@index");

而控制器文件里面的内容是:

namespace App\Http\Controllers;

class DashboardController extends Controller
{

    public function index()
    {
        return view("dashboard");
    }
}

此处我们再新建resources/views/dashboard.blade.php,填充好内容后,我们就可以通过php artisan serve

来访问了

具体代码查看

git clone https://github.com/zhuanxuhit/php-clean-code.git

git checkout 15-laravel-dashboard

Customer管理

我们接着设置Customer的路由

Route::get( '/customers', 'CustomersController@index' );
Route::get( '/customers/new', 'CustomersController@edit' );
Route::post('/customers/new','CustomersController@store');

Route::get( '/customers/edit/{id}', 'CustomersController@edit' );
Route::post('/customers/edit/{id}','CustomersController@store');

然后控制器CustomersController中注入CustomerRepositoryInterface

class CustomersController extends Controller
{

    /**
     * @var \CleanPhp\Invoicer\Domain\Repository\CustomerRepositoryInterface
     */
    private $customerRepository;

    /**
     * CustomersController constructor.
     *
     * @param \CleanPhp\Invoicer\Domain\Repository\CustomerRepositoryInterface $customerRepository
     */
    public function __construct(CustomerRepositoryInterface $customerRepository)
    {
        $this->customerRepository = $customerRepository;
    }
}

通过Laravel的service container,能很方便的注入进来,此处我们需要声明CustomerRepositoryInterface的实现,需要在文件app/Providers/AppServiceProvider.php中新增:

use CleanPhp\Invoicer\Persistence\Eloquent\Repository\CustomerRepository;
use CleanPhp\Invoicer\Domain\Repository\CustomerRepositoryInterface;

public function register()
{
  $this->app->bind(CustomerRepositoryInterface::class,
                   CustomerRepository::class);
}

此处CustomerRepository是持久层的基于Laravel的Eloquent的实现,Eloquent是Active Record的ORM,具体介绍可以看eloquent

下面我们来实现具体Customer的操作。

Customer Listing

在CustomersController中新增index方法

    public function index(  )
    {
        $customers = $this->customerRepository->getAll();
        return view('customers/index', ['customers' => $customers]);
    }

并新增文件resources/views/customers/index.blade.php

Adding and Editing Customers

此处我们需要根据/customers/new是get还是post方法来判断是新建一个customer还是进行修改。

此处我们需要几个功能

  1. form filter,我们需要对post的表单进行验证
  2. Hydrator,我们需要将输入的表单方便的赋值到我们的Entity的属性上

此处表单验证上,我们使用laravel的表单验证,不再自己开发了,通过命令php artisan make:request NewCustomerPost新建。

    public function rules()
    {
        return [
            'name' => 'required',
            'email' => 'required|email',
        ];
    }

然后去controller中实现方法,

public function store(NewCustomerPost $request, $id = '')
{
  $data = $request->all();
  $customer = $id ? $this->customerRepository->getById($id) : new Customer();

  $customer->setName($data['name'])->setEmail($data['email']);
  $this->customerRepository->persist($customer);
  return new RedirectResponse('/customers/edit/' . $customer->getId());
}

public function edit($id = '')
{
  $customer = $id ? $this->customerRepository->getById($id) : new Customer();
  $viewModel['customer'] = $customer;
  return view('customers/new-or-edit', $viewModel);
}

我们可以看到controller里的方法都非常的薄,主要还是通过domain层来完成具体的操作。

具体代码查看

git clone https://github.com/zhuanxuhit/php-clean-code.git

git checkout 16-laravel-customers

Order管理

order总的过程和Customer类似,一个不同的地方是,Order里面有个属性是Customer,Order和Customer的关系是1对1,这在实现OrderRepository需要注意了,里面从数据库转换后要进行转换,看代码:

    /**
     * @param $object
     * @param Order $entity
     */
    protected function hydrate( $object, $entity )
    {
        $customer = $this->customerRepository->getById($object->customer_id);
        $entity->setCustomer($customer)->setOrderNumber($object->order_number)
            ->setTotal($object->total)->setDescription($object->description);
    }

此处hydrate的作用是将数据库里的数据正确设置到Order对象$entity上。

具体代码查看

git clone https://github.com/zhuanxuhit/php-clean-code.git

git checkout 17-laravel-orders

invoice管理

invoice和之前的customer和order类似,需要注意的是invoice会有一个领域服务InvoicingService,实现未出账单的出账操作。

/**
 * @return array
 */
public function generateInvoices()
{
    $orders = $this->orderRepository->getUninvoicedOrders();
    $invoices = [];
    foreach ($orders as $order){
      $invoices[] = $this->factory->createFromOrder($order);
    }
    return $invoices;
}

除此之外就没什么需要注意的。

具体代码查看

git clone https://github.com/zhuanxuhit/php-clean-code.git

git checkout 18-laravel-invoices

以上就是php-clean-architecture的全部。

总结

The Clean Architecture in PHP读书笔记写到这全部结束了,在这最后一篇中,我们以laravel为框架给出了示例,最核心的领域逻辑是纯的php class,不依赖于任何的框架,我们可以快速的进行切换。

但是在使用laravel过程中,特别是repository这块,由于没有直接使用laravel的Eloquent模块,实现上确实比较麻烦,在实现CleanPhp\Invoicer\Persistence\Eloquent\Repository下的类的时候,很多方法都比较tricky,而且可以想象的是,随着项目负责度的提升,这一块会成为程序员的梦靥,所以下一个系列我会去带领大家看看php中几大主流orm的实现原理,包括laravel,doctrine2,尽情期待。

这是The Clean Architecture in PHP的第十篇,你的鼓励是我继续写下去的动力,期待我们共同进步。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容