최근 Doctrine 2.2 및 Zend Framework 2의 일부를 사용하여 조직을 개선하고 중복을 줄이기 시작했습니다. 오늘 저는 컨트롤러와 Doctrine 엔터티 사이의 중개자 역할을하는 서비스 계층을 구현하기위한 아이디어를 던지기 시작했습니다.서비스 레이어 (Doctrine & ZF)의 데이터 액세스 및 보안
지금 우리 논리의 대부분은 컨트롤러에 있습니다. 또한 액션 헬퍼를 사용하여 특정 권한을 테스트합니다. 그러나 Zend \ Di를 구현 한 후에 새로운 접근법을 생각해 냈습니다. Zend \ Di를 사용하여 EntityManager 인스턴스를 삽입하고 현재 사용자의 권한을 사용하는 엔티티 관련 서비스 모델을 만들기 시작했습니다.
제어기 코드는 다음과 같다 :
class Project_DeleteController extends Webjawns_Controller_Action
{
public function init()
{
$this->_initJsonContext();
}
public function indexAction()
{
$response = $this->_getAjaxResponse();
$auditId = (int) $this->_getParam('audit_id');
if (!$auditId) {
throw new DomainException('Audit ID required');
}
/* @var $auditService Service\Audit */
$auditService = $this->getDependencyInjector()->get('Service\Audit');
try {
$auditService->delete($auditId);
$response->setStatusSuccess();
} catch (Webjawns\Exception\SecurityException $e) {
$this->_noAuth();
} catch (Webjawns\Exception\Exception $e) {
$response->setStatusFailure($e->getMessage());
}
$response->sendResponse();
}
}
그리고 우리의 서비스 층의 하나의 예입니다. 생성자는 두 개의 매개 변수를 취합니다. 하나는 EntityManager이고 다른 하나는 Entity \ UserAccess 객체입니다. Zend \ Di에 의해 주입됩니다.
namespace Service;
use Webjawns\Service\Doctrine,
Webjawns\Exception;
class Audit extends AbstractService
{
public function delete($auditId)
{
// Only account admins can delete audits
if (\Webjawns_Acl::ROLE_ACCT_ADMIN != $this->getUserAccess()->getAccessRole()) {
throw new Exception\SecurityException('Only account administrators can delete audits');
}
$audit = $this->get($auditId);
if ($audit->getAuditStatus() !== \Entity\Audit::STATUS_IN_PROGRESS) {
throw new Exception\DomainException('Audits cannot be deleted once submitted for review');
}
$em = $this->getEntityManager();
$em->remove($audit);
$em->flush();
}
/**
* @param integer $auditId
* @return \Entity\Audit
*/
public function get($auditId)
{
/* @var $audit \Entity\Audit */
$audit = $this->getEntityManager()->find('Entity\Audit', $auditId);
if (null === $audit) {
throw new Exception\DomainException('Audit not found');
}
if ($audit->getAccount()->getAccountId() != $this->getUserAccess()->getAccount()->getAccountId()) {
throw new Exception\SecurityException('User and audit accounts do not match');
}
return $audit;
}
}
- 이것은 우리가 달성하려고하는 무엇에 사용하는 적절한 패턴인가?
- 게시 된 서비스 계층 내에서 사용 권한 유효성 검사를 수행하는 것이 좋습니다.
- 필자가 이해 하듯이, 뷰 로직은 컨트롤러에 여전히 존재하므로 다양한 컨텍스트 (JSON, XML, HTML 등)에서 사용할 수있는 모델 유연성을 제공합니다. 생각?
저는 지금까지의 방식에 만족합니다. 그러나 누군가가 우리가 어떻게하는지에 대해 어떤 단점이 보이면, 생각해보십시오.
그냥 내 두 펜스.올바른 방법과 잘못된 방법이 있다고 생각하지 않지만 서비스 계층에 인증을 시작했지만 내 컨트롤러로 옮겼습니다. 내 추론은 서비스 레이어가 내 내부 API이며 내 컨트롤러 레이어를 사용하여이를 세계에 공개해야하므로 누구에게 무엇에 대한 액세스 권한을 부여해야하는지 결정해야합니다. 또한 모든 내부 도구/스크립트 등을 빌드하려는 경우 내 서비스 계층을 사용하기 위해 인증을 구축 할 필요가 없습니다. –
인증과 액세스 제어가 섞이지 않도록주의하십시오. 도메인 클래스가 그림으로 들어가기 전에 인증이 모듈로 들어가야합니까? 사용자 신원을 확인한 후에 만 예 : 도메인 서비스 모델 내부에서 if (! $ authService-> hasIdentity()). – dualmon
@ JamieSutherland : 나는 동의하지 않는다. 서비스는 비즈니스 로직을 정의합니다. 컨트롤러는 요청과 적절한 비즈니스 로직 사이의 다리 역할을합니다. 예를 들어, 제품 주문을위한 단일 서비스 만 있지만 HTTP 요청, API 요청 등에 대한 여러 컨트롤러가있을 수 있습니다. 특정 요청을하는 ACL에 관심이 있다면 (예 : HTTP를 통해 API 요청의 비밀 키가 필요한 사용자 세션을 기대할 수 있음) ACL 구현을 일반화하여 허용하십시오. – moteutsch