namespace
Application\Controller;
use
CleanPhp\Invoicer\Domain\Repository\InvoiceRepositoryInterface;
use
CleanPhp\Invoicer\Domain\Repository\OrderRepositoryInterface;
use
CleanPhp\Invoicer\Domain\Service\InvoicingService;
use
Zend\Mvc\Controller\AbstractActionController;
class
InvoicesController
extends
AbstractActionController {
protected
$invoiceRepository
;
protected
$orderRepository
;
protected
$invoicing
;
public function
__construct
(
InvoiceRepositoryInterface
$invoices
,
OrderRepositoryInterface
$orders
,
InvoicingService
$invoicing
) {
$this
->
invoiceRepository
=
$invoices
;
$this
->
orderRepository
=
$orders
;
$this
->
invoicing
=
$invoicing
;
}
Our Application in Zend Framework 2
191
// ...
}
Of course, we need to modify our controller config for this to work:
return
[
// ...
'controllers'
=>
[
// ...
'factories'
=>
[
// ...
'Application\Controller\Invoices'
=>
function
(
$sm
) {
return new
\Application\Controller\InvoicesController(
$sm
->
getServiceLocator
()
->
get
(
'InvoiceTable'
),
$sm
->
getServiceLocator
()
->
get
(
'OrderTable'
),
new
InvoicingService(
$sm
->
getServiceLocator
()
->
get
(
'OrderTable'
),
new
InvoiceFactory()
)
);
},
// ...
],
],
// ...
];
We’ll use this
InvoicingService
in our
generateAction()
:
public function
generateProcessAction
() {
$invoices
=
$this
->
invoicing
->
generateInvoices
();
$this
->
invoiceRepository
->
begin
();
foreach
(
$invoices
as
$invoice
) {
$this
->
invoiceRepository
->
persist
(
$invoice
);
}
$this
->
invoiceRepository
->
commit
();
return
[
'invoices'
=>
$invoices
];
}
Our Application in Zend Framework 2
192
Here, we loop through the invoices generated by the
InvoicingService
and persist them to the
InvoiceRepository
. Finally, we’ll return the list of generated invoices to the view.
Speaking of the view, let’s create that:
<
div class
=
"page-header"
>
<
h2
>
Generated Invoices
h2
>
div
>
php
if
(
empty
(
$this
->
invoices
))
:
?>
No invoices were generated.
else
:
?>
# |
Order Number |
Invoice Date |
Customer |
Description |
Total |
foreach
(
$this
->
invoices
as
$invoice
)
:
?>
=
$this
->
escapeHtmlAttr
(
$invoice
->
getId
())
?>
">
=
$this
->
escapeHtml
(
$invoice
->
getId
())
?>
|
=
$invoice
->
getInvoiceDate
()
->
format
(
'm/d/Y'
)
?>
|
=
$this
->
escapeHtml
(
$invoice
->
getOrder
()
->
getOrderNumber
())
?>
|
=
$this
->
escapeHtmlAttr
(
$invoice
->
getOrder
()
->
getCustomer
()
->
getId
()
)
?>
">
=
$this
->
escapeHtml
(
$invoice
->
getOrder
()
->
getCustomer
()
->
getName
()
)
?>
|
Our Application in Zend Framework 2
193
=
$this
->
escapeHtml
(
$invoice
->
getOrder
()
->
getDescription
())
?>
|
$
=
number_format
(
$invoice
->
getTotal
(),
2
)
?>
|
endforeach
;
?>
endif
;
?>
This view will show the user all the invoices generated on an invoicing run. It looks just like our
Invoice index view.
Our table of invoices is identical to the table in the invoice index view. A better solution
would be to store this code in a separate view file and load it using Zend’s
partial view
helper⁵⁰
. Give it a shot.
The last thing we have to do is setup our View Invoice action.
Viewing Invoices
Let’s create a
viewAction()
. We’ll steal from the
OrderController
and modify it:
// module/Application/src/Application/Controller/InvoicesController.php
public function
viewAction
() {
$id
=
$this
->
params
()
->
fromRoute
(
'id'
);
$invoice
=
$this
->
invoiceRepository
->
getById
(
$id
);
if
(
!
$invoice
) {
$this
->
getResponse
()
->
setStatusCode
(
404
);
return null
;
}
return
[
'invoice'
=>
$invoice
,
'order'
=>
$invoice
->
getOrder
()
];
}
And a simple view:
⁵⁰
http://framework.zend.com/manual/current/en/modules/zend.view.helpers.partial.html
Our Application in Zend Framework 2
194
module
/
Application
/
view
/
application
/
invoices
/
view
.
phtml
-->
<
div class
=
"page-header clearfix"
>
<
h2
>
Invoice
#= $this->escapeHtml($this->invoice->getId()) ?>
div
>
<
table class
=
"table table-striped"
>
<
thead
>
<
tr
>
<
th colspan
=
"2"
>
Invoice Details
th
>
tr
>
thead
>
<
tr
>
<
th
>
Customer
:
th
>
<
td
>
<
a href
=
"/customers/edit/=
$this->escapeHtmlAttr
(
$this->order
->getCustomer()->getId()) ?>"
>
=
$this
->
escapeHtml
(
$this
->
order
->
getCustomer
()
->
getName
())
?>
|
Order: |
=
$this
->
escapeHtmlAttr
(
$this
->
order
->
getId
())
?>
">
=
$this
->
escapeHtml
(
$this
->
order
->
getOrderNumber
())
?>
|
Description: |
=
$this
->
escapeHtml
(
$this
->
order
->
getDescription
())
?>
|
Total: |
$
=
number_format
(
$this
->
invoice
->
getTotal
(),
2
)
?>
|
And with this, we’ve completed the sample application.
Our Application in Zend Framework 2
195
This would make a good place to commit your code to source control.
If you’re just reading, but want to see the code in action, you can checkout the tag
09-invoicing:
git
clone
https
://
github
.
com
/
mrkrstphr
/
cleanphp
-
example
.
git
git checkout
09-
invoicing
Doctrine 2
We have a working, functional app written in Zend Framework 2 that satisfies our business
requirements. Let’s say for some reason that we wanted to try a different approach to interacting
with the database. Maybe we’re about to scale up and add many more features and have decided
that we need an easier solution for interacting with the database.
Whatever the reason is, let’s say that we have done extensive research and have settled on using
Doctrine ORM⁵¹
.
Doctrine is a
Data Mapper⁵²
based
Object Relational Mapping (ORM)⁵³
library. Essentially,
Doctrine allows us to map database tables and columns to PHP objects and attributes, and
manipulate data as if we were simply manipulating objects.
The Doctrine ORM project is built on top of the
Doctrine DBAL⁵⁴
(Database Abstraction Layer)
project, and utilizes the
Doctrine Common⁵⁵
project as well. We’ll get these tools simply by
requiring the
doctrine/orm
library via Composer. We’ll also need
symfony/yaml
as we’re going
to be writing some mapping files in YAML:
composer require doctrine/orm symfony/yaml
⁵¹
http://www.doctrine-project.org/projects/orm.html
⁵²
http://martinfowler.com/eaaCatalog/dataMapper.html
⁵³
http://en.wikipedia.org/wiki/Object-relational_mapping
⁵⁴
http://www.doctrine-project.org/projects/dbal.html
⁵⁵
http://www.doctrine-project.org/projects/common.html
Doctrine 2
197
Rebuilding the Persistence Layer
Our goal is to swap out the persistence library, which is part of our infrastructure layer.
Remember that this layer of the onion diagram has nothing dependent upon it, meaning that
we should be able to entirely swap out this layer without having to touch any other layers of the
application.
Okay, I lied; there is one piece of the ZF2 app we’ll need to tweak: the configuration files. These
files are the social lubricant that gets the two layers talking. Without it, ZF2 simply wouldn’t be
able to use Doctrine. These two layers are pretty unique; every other layer just relies on interfaces
and dependency injection to make them work together. But config is necessary whenever a
database or third party service is involved.
So let’s see how well we did earlier when we set up these layers.
Creating Doctrine-based Repositories
We’ll need to implement the repository interfaces in our domain services layer using Doctrine.
These concrete repositories will sit on top of and utilize Doctrine’s
EntityManager
object,
which, along with the
UnitofWork
object, are the workhorses of Doctrine. In many cases, these
repositories methods will simply be a proxy to the
EntityManager
itself.
Let’s start by creating an
AbstractDoctrineRepository
that will encapsulate the vast majority
of the functionality that each individual repository can inherit from, much like we did with the
Zend Data Tables:
Doctrine 2
198
// src/Persistence/Doctrine/Repository/AbstractDoctrineRepository.php
namespace
CleanPhp\Invoicer\Persistence\Doctrine\Repository;
Do'stlaringiz bilan baham: |