这是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
,建表,插入数据。
CREATETABLEcustomers (idintegerPRIMARYKEY,namevarchar(100)NOTNULL, emailvarchar(100)NOTNULL); CREATETABLEorders (idintegerPRIMARYKEY, customer_idintREFERENCEScustomers(id)NOTNULL, order_numbervarchar(20)NOTNULL, descript iontextNOTNULL, totalfloatNOTNULL); CREATETABLEinvoices (idintegerPRIMARYKEY, order_idintREFERENCESorders(id)NOTNULL, invoice_datedateNOTNULL, totalfloatNOTNULL); INSERTINTOcustomers(name, email)VALUES('Acme Corp','ap@acme.com');INSERTINTOcustomers(name, email)VALUES('ABC Company','invoices@abc.com');
建立Dashboard
我们通过命令
php artisan make:controller DashboardController
来新建控制器,并修改 routes/web.php
来设置路由
Route::get('/',"DashboardController@index");
而控制器文件里面的内容是:
namespaceApp\Http\Controllers; classDashboardControllerextendsController { publicfunctionindex() { returnview("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
,
classCustomersControllerextendsController { /** * @var\CleanPhp\Invoicer\Domain\Repository\CustomerRepositoryInterface */ private$customerRepository; /** * CustomersController constructor. * * @param\CleanPhp\Invoicer\Domain\Repository\CustomerRepositoryInterface $customerRepository */ publicfunction__construct(CustomerRepositoryInterface $customerRepository) { $this->customerRepository = $customerRepository; } }
通过Laravel的service container,能很方便的注入进来,此处我们需要声明 CustomerRepositoryInterface
的实现,需要在文件 app/Providers/AppServiceProvider.php
中新增:
useCleanPhp\Invoicer\Persistence\Eloquent\Repository\CustomerRepository; useCleanPhp\Invoicer\Domain\Repository\CustomerRepositoryInterface; publicfunctionregister() { $this->app->bind(CustomerRepositoryInterface::class, CustomerRepository::class); }
此处 CustomerRepository
是持久层的基于Laravel的Eloquent的实现,Eloquent是Active Record的ORM,具体介绍可以看 eloquent 。
下面我们来实现具体Customer的操作。
Customer Listing
在CustomersController中新增index方法
publicfunctionindex( ) { $customers = $this->customerRepository->getAll(); returnview('customers/index', ['customers'=> $customers]); }
并新增文件resources/views/customers/index.blade.php
Adding and Editing Customers
此处我们需要根据 /customers/new
是get还是post方法来判断是新建一个customer还是进行修改。
此处我们需要几个功能
- form filter,我们需要对post的表单进行验证
- Hydrator,我们需要将输入的表单方便的赋值到我们的Entity的属性上
此处表单验证上,我们使用laravel的表单验证,不再自己开发了,通过命令 php artisan make:request NewCustomerPost
新建。
publicfunctionrules() { return[ 'name'=>'required', 'email'=>'required|email', ]; }
然后去controller中实现方法,
publicfunctionstore(NewCustomerPost $request, $id ='') { $data = $request->all(); $customer = $id ? $this->customerRepository->getById($id) :newCustomer(); $customer->setName($data['name'])->setEmail($data['email']); $this->customerRepository->persist($customer); returnnewRedirectResponse('/customers/edit/'. $customer->getId()); } publicfunctionedit($id ='') { $customer = $id ? $this->customerRepository->getById($id) :newCustomer(); $viewModel['customer'] = $customer; returnview('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 * @paramOrder $entity */ protectedfunctionhydrate( $object, $entity ) { $customer = $this->customerRepository->getById($object->customer_id); $entity->setCustomer($customer)->setOrderNumber($object->order_number) ->setTotal($object->total)->setDescript ion($object->descript ion); }
此处hydrate的作用是将数据库里的数据正确设置到Order对象$entity上。
具体代码查看
git clone https://github.com/zhuanxuhit/php-clean-code.git git checkout 17-laravel-orders
invoice管理
invoice和之前的customer和order类似,需要注意的是invoice会有一个领域服务 InvoicingService
,实现未出账单的出账操作。
/** * @returnarray */ publicfunctiongenerateInvoices() { $orders = $this->orderRepository->getUninvoicedOrders(); $invoices = []; foreach($ordersas$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的第十篇,你的鼓励是我继续写下去的动力,期待我们共同进步。