나는 사람들이 일반적인 Symfony 2 번들 개념에 대해 토론하는 경향 이 있는 이와 같은 질문을 알고 있습니다.
예를 들어 트위터와 같은 응용 프로그램과 같은 특정 응용 프로그램에서는 공식 문서 와 같이 모든 것이 일반 번들 안에 있어야 합니까?
내가 묻는 이유는 일반적으로 응용 프로그램을 개발할 때 코드를 풀 스택 접착제 프레임 워크에 강력하게 연결하고 싶지 않기 때문입니다.
Symfony 2 기반 응용 프로그램을 개발하고 어느 시점에서 Symfony 2가 개발 을 계속 진행 하는 최선의 선택이 아니라고 결정 하면 문제가 될까요?
일반적인 질문은 왜 모든 것이 번들이되는 것입니까?
편집 # 1
이 질문을 한 지 거의 1 년이 지난 지금 이 주제에 대한 지식을 공유 하는 기사 를 썼습니다 .
답변
이 주제에 대해 더 철저하고 업데이트 된 블로그 게시물을 작성했습니다 : http://elnur.pro/symfony-without-bundles/
아니요, 모든 것이 번들로 제공 될 필요는 없습니다. 다음과 같은 구조를 가질 수 있습니다.
src/Vendor/Model
— 모델의 경우src/Vendor/Controller
— 컨트롤러 용src/Vendor/Service
— 서비스,src/Vendor/Bundle
—와 같은 번들의src/Vendor/Bundle/AppBundle
경우- 기타
이런 식으로, 당신 AppBundle
은 실제로 Symfony2에만 해당되는 것들을 넣을 것입니다. 나중에 다른 프레임 워크로 전환하기로 결정한 경우 Bundle
네임 스페이스를 제거 하고 선택한 프레임 워크로 바꿉니다.
여기서 제안하는 것은 앱 특정 코드를 위한 것 입니다. 재사용 가능한 번들의 경우 여전히 모범 사례를 사용 하는 것이 좋습니다 .
엔티티를 번들에서 제외
엔티티를 src/Vendor/Model
번들 외부에 유지하기 위해 doctrine
섹션 config.yml
을
doctrine:
# ...
orm:
# ...
auto_mapping: true
에
doctrine:
# ...
orm:
# ...
mappings:
model:
type: annotation
dir: %kernel.root_dir%/../src/Vendor/Model
prefix: Vendor\Model
alias: Model
is_bundle: false
Doctrine 저장소에서 액세스 할 수있는 엔티티 이름 Model
은이 경우로 시작 합니다 (예 🙂 Model:User
.
하위 네임 스페이스를 사용하여 관련 엔터티를 함께 그룹화 할 수 있습니다 (예 🙂 src/Vendor/User/Group.php
. 이 경우 엔터티 이름은 Model:User\Group
입니다.
컨트롤러를 번들에서 제외
먼저 다음을 추가하여 JMSDiExtraBundlesrc
에 서비스 의 폴더 를 스캔하도록 지시 해야 합니다 config.yml
.
jms_di_extra:
locations:
directories: %kernel.root_dir%/../src
그런 다음 컨트롤러를 서비스로 정의 하고 Controller
네임 스페이스 아래에 배치하십시오 .
<?php
namespace Vendor\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use JMS\DiExtraBundle\Annotation\Service;
use JMS\DiExtraBundle\Annotation\InjectParams;
use JMS\SecurityExtraBundle\Annotation\Secure;
use Elnur\AbstractControllerBundle\AbstractController;
use Vendor\Service\UserService;
use Vendor\Model\User;
/**
* @Service("user_controller", parent="elnur.controller.abstract")
* @Route(service="user_controller")
*/
class UserController extends AbstractController
{
/**
* @var UserService
*/
private $userService;
/**
* @InjectParams
*
* @param UserService $userService
*/
public function __construct(UserService $userService)
{
$this->userService = $userService;
}
/**
* @Route("/user/add", name="user.add")
* @Template
* @Secure("ROLE_ADMIN")
*
* @param Request $request
* @return array
*/
public function addAction(Request $request)
{
$user = new User;
$form = $this->formFactory->create('user', $user);
if ($request->getMethod() == 'POST') {
$form->bind($request);
if ($form->isValid()) {
$this->userService->save($user);
$request->getSession()->getFlashBag()->add('success', 'user.add.success');
return new RedirectResponse($this->router->generate('user.list'));
}
}
return ['form' => $form->createView()];
}
/**
* @Route("/user/profile", name="user.profile")
* @Template
* @Secure("ROLE_USER")
*
* @param Request $request
* @return array
*/
public function profileAction(Request $request)
{
$user = $this->getCurrentUser();
$form = $this->formFactory->create('user_profile', $user);
if ($request->getMethod() == 'POST') {
$form->bind($request);
if ($form->isValid()) {
$this->userService->save($user);
$request->getSession()->getFlashBag()->add('success', 'user.profile.edit.success');
return new RedirectResponse($this->router->generate('user.view', [
'username' => $user->getUsername()
]));
}
}
return [
'form' => $form->createView(),
'user' => $user
];
}
}
컨트롤러를 서비스로 정의하는 것을 단순화하기 위해 ElnurAbstractControllerBundle 을 사용 하고 있습니다.
마지막으로 남은 것은 번들없이 템플릿을 찾도록 Symfony에 알리는 것입니다. 템플릿 추측 서비스를 재정 의하여이 작업을 수행하지만 Symfony 2.0과 2.1의 접근 방식이 다르기 때문에 두 가지 버전을 모두 제공하고 있습니다.
Symfony 2.1 이상 템플릿 추측 자 재정의
나는 당신을 위해 번들 을 만들었습니다 .
Symfony 2.0 템플리트 리스너 대체
먼저 클래스를 정의하십시오.
<?php
namespace Vendor\Listener;
use InvalidArgumentException;
use Symfony\Bundle\FrameworkBundle\Templating\TemplateReference;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Bundle\Bundle;
use Sensio\Bundle\FrameworkExtraBundle\EventListener\TemplateListener as FrameworkExtraTemplateListener;
use JMS\DiExtraBundle\Annotation\Service;
class TemplateListener extends FrameworkExtraTemplateListener
{
/**
* @param array $controller
* @param Request $request
* @param string $engine
* @throws InvalidArgumentException
* @return TemplateReference
*/
public function guessTemplateName($controller, Request $request, $engine = 'twig')
{
if (!preg_match('/Controller\\\(.+)Controller$/', get_class($controller[0]), $matchController)) {
throw new InvalidArgumentException(sprintf('The "%s" class does not look like a controller class (it must be in a "Controller" sub-namespace and the class name must end with "Controller")', get_class($controller[0])));
}
if (!preg_match('/^(.+)Action$/', $controller[1], $matchAction)) {
throw new InvalidArgumentException(sprintf('The "%s" method does not look like an action method (it does not end with Action)', $controller[1]));
}
$bundle = $this->getBundleForClass(get_class($controller[0]));
return new TemplateReference(
$bundle ? $bundle->getName() : null,
$matchController[1],
$matchAction[1],
$request->getRequestFormat(),
$engine
);
}
/**
* @param string $class
* @return Bundle
*/
protected function getBundleForClass($class)
{
try {
return parent::getBundleForClass($class);
} catch (InvalidArgumentException $e) {
return null;
}
}
}
그리고 Symfony에게 다음을 추가하여 사용하도록 지시하십시오 config.yml
.
parameters:
jms_di_extra.template_listener.class: Vendor\Listener\TemplateListener
번들없이 템플릿 사용
이제 번들에서 템플릿을 사용할 수 있습니다. app/Resources/views
폴더 아래에 보관하십시오 . 예를 들어 위의 예제 컨트롤러에서이 두 작업에 대한 템플릿은 다음 위치에 있습니다.
app/Resources/views/User/add.html.twig
app/Resources/views/User/profile.html.twig
템플릿을 참조 할 때는 번들 부분을 생략하십시오.
{% include ':Controller:view.html.twig' %}
답변
물론 응용 프로그램을 분리 할 수 있습니다. 그냥 라이브러리로 개발하고 심포니에 통합 vendor/
합니다 (을 사용하여 중 – 폴더 deps
또는 composer.json
당신이 Symfony2.0 또는 Symfony2.1를 사용 어떠했는지를 따라). 그러나 라이브러리의 “프론트 엔드”역할을하는 하나 이상의 번들이 필요합니다. Symfony2는 컨트롤러 등을 찾습니다.
답변
풀 스택 프레임 워크에서 사용하려는 기능의 양에 따라 일반적인 심포니 배포판은 추가 (응용 프로그램) 번들없이 작동 할 수 있습니다.
예를 들어, 컨트롤러는 자동로드되는 즉시 프로젝트 구조의 어느 곳에 나 배치 할 수있는 호출 가능할 수 있습니다.
라우팅 정의 파일에서 다음을 사용할 수 있습니다.
test:
pattern: /test
defaults: { _controller: Controller\Test::test }
평범한 오래된 PHP 객체 일 수 있으며 객체를 반환해야한다는 사실에 의해서만 프레임 워크에 묶여 Symfony\Component\HttpFoundation\Response
있습니다.
나뭇 가지 템플릿 (또는 다른 것)은 논리적 이름을 app/Resources/views/template.html.twig
사용하여 표현하고 렌더링 할 수 있습니다 ::template.html.twig
.
모든 DI 서비스는 app / config / config.yml에서 정의 할 수 있습니다 (또는 app/config/services.yml
예를 들어 가져 오기). 모든 서비스 클래스는 프레임 워크에 전혀 묶이지 않은 평범한 PHP 객체 일 수 있습니다.
이 모든 것은 기본적으로 symfony full stack 프레임 워크에 의해 제공됩니다.
번역 파일 (xliff와 같은)은 번들을 통해서만 발견되기 때문에 번역 파일을 사용하고 싶을 때 문제가 발생합니다 .
심포니 빛 분포 목적은 보통 번들을 통해 발견 될 모든 것을 발견하여 이러한 문제 유형을 해결합니다.
답변
당신은 사용할 수 KnpRadBundle 프로젝트 구조를 단순화하려고합니다.
다른 접근 방식은 src/Company/Bundle/FrontendBundle
예를 들어 번들 및 src/Company/Stuff/Class.php
심포니 독립적이며 프레임 워크 외부에서 재사용 할 수있는 클래스에 사용하는 것입니다
답변
벌써 5 년이 지났으므로 Symfony Bundles에 대한 몇 가지 기사가 더 있습니다.
- Symfony의 번들은 무엇입니까? Iltar van der Berg.
TLDR :
애플리케이션에 여러 번들이 직접 필요합니까? 아마 아닐 것입니다. 의존성 스파게티를 방지하기 위해 AppBundle을 작성하는 것이 좋습니다. 모범 사례 를 따르기 만하면 제대로 작동합니다.
- 심포니 : Toni Uebernickel의 묶는 방법.
TLDR :
애플리케이션 로직에 대해 AppBundle이라는 하나의 번들 만 작성하십시오. 하나의 AppBundle-애플리케이션 로직을 넣지 마십시오!
답변
Symfony 프레임 워크는 개념 증명을 신속하게 시작하는 데 매우 적합하며 모든 코드는 src /의 기본 번들 응용 프로그램 내에 입력 할 수 있습니다.
이 번들에서 원하는대로 코드를 구성 할 수 있습니다.
POC 개발을 위해 다른 기술을 사용하려는 경우 모든 코드를 번들 개념으로 구성하지 않기 때문에 쉽게 번역 할 수 있습니다.
모든 개념에 대해 당신은 이것을 극단으로하지 않습니다. 번들은 좋지만 모든 것을 번들로 묶고 매일은 좋지 않습니다.
번들 번들의 영향을 줄이기 위해 개념 증명을 개발하기 위해 Silex (Symfony 마이크로 프레임 워크)를 사용할 수 있습니다.