Skip to content

Commit e04fc83

Browse files
committed
feature #701 Make Doctrine repository as service and autowire/use it anywhere (yceruto)
This PR was merged into the master branch. Discussion ---------- Make Doctrine repository as service and autowire/use it anywhere Living in the edge of the [new awesome features like this](doctrine/DoctrineBundle#727), I'm proposing before doctrine-bundle 1.8 release, show/test this great feature that simplify our lives and to see how it works! and because soon, best practices should adopt this approach by default. (In fact [maker-bundle will do it](https://github.com/symfony/maker-bundle/blob/master/src/Resources/skeleton/doctrine/Repository.php.txt) <3) What do you think? Commits ------- ceac1df Make repository as service and autowire/use it anywhere
2 parents 014a273 + ceac1df commit e04fc83

11 files changed

+52
-32
lines changed

composer.json

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"require": {
77
"php": "^7.1.3",
88
"ext-pdo_sqlite": "*",
9+
"doctrine/doctrine-bundle": "^1.8",
910
"doctrine/doctrine-fixtures-bundle": "^2.4",
1011
"erusev/parsedown": "^1.6",
1112
"ezyang/htmlpurifier": "^4.9",

composer.lock

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/services.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ services:
2828
resource: '../src/*'
2929
# you can exclude directories or files
3030
# but if a service is unused, it's removed anyway
31-
exclude: '../src/{DataFixtures,Entity,Migrations,Repository,Tests}'
31+
exclude: '../src/{DataFixtures,Entity,Migrations,Tests}'
3232

3333
# controllers are imported separately to make sure they're public
3434
# and have a tag that allows actions to type-hint services

src/Command/AddUserCommand.php

+6-5
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace App\Command;
1313

1414
use App\Entity\User;
15+
use App\Repository\UserRepository;
1516
use App\Utils\Validator;
1617
use Doctrine\ORM\EntityManagerInterface;
1718
use Symfony\Component\Console\Command\Command;
@@ -57,14 +58,16 @@ class AddUserCommand extends Command
5758
private $entityManager;
5859
private $passwordEncoder;
5960
private $validator;
61+
private $users;
6062

61-
public function __construct(EntityManagerInterface $em, UserPasswordEncoderInterface $encoder, Validator $validator)
63+
public function __construct(EntityManagerInterface $em, UserPasswordEncoderInterface $encoder, Validator $validator, UserRepository $users)
6264
{
6365
parent::__construct();
6466

6567
$this->entityManager = $em;
6668
$this->passwordEncoder = $encoder;
6769
$this->validator = $validator;
70+
$this->users = $users;
6871
}
6972

7073
/**
@@ -202,10 +205,8 @@ protected function execute(InputInterface $input, OutputInterface $output)
202205

203206
private function validateUserData($username, $plainPassword, $email, $fullName)
204207
{
205-
$userRepository = $this->entityManager->getRepository(User::class);
206-
207208
// first check if a user with the same username already exists.
208-
$existingUser = $userRepository->findOneBy(['username' => $username]);
209+
$existingUser = $this->users->findOneBy(['username' => $username]);
209210

210211
if (null !== $existingUser) {
211212
throw new RuntimeException(sprintf('There is already a user registered with the "%s" username.', $username));
@@ -217,7 +218,7 @@ private function validateUserData($username, $plainPassword, $email, $fullName)
217218
$this->validator->validateFullName($fullName);
218219

219220
// check if a user with the same email already exists.
220-
$existingEmail = $userRepository->findOneBy(['email' => $email]);
221+
$existingEmail = $this->users->findOneBy(['email' => $email]);
221222

222223
if (null !== $existingEmail) {
223224
throw new RuntimeException(sprintf('There is already a user registered with the "%s" email.', $email));

src/Command/DeleteUserCommand.php

+6-3
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace App\Command;
1313

1414
use App\Entity\User;
15+
use App\Repository\UserRepository;
1516
use App\Utils\Validator;
1617
use Doctrine\ORM\EntityManagerInterface;
1718
use Symfony\Component\Console\Command\Command;
@@ -42,16 +43,19 @@ class DeleteUserCommand extends Command
4243
{
4344
protected static $defaultName = 'app:delete-user';
4445

46+
/** @var SymfonyStyle */
4547
private $io;
4648
private $entityManager;
4749
private $validator;
50+
private $users;
4851

49-
public function __construct(EntityManagerInterface $em, Validator $validator)
52+
public function __construct(EntityManagerInterface $em, Validator $validator, UserRepository $users)
5053
{
5154
parent::__construct();
5255

5356
$this->entityManager = $em;
5457
$this->validator = $validator;
58+
$this->users = $users;
5559
}
5660

5761
/**
@@ -108,9 +112,8 @@ protected function execute(InputInterface $input, OutputInterface $output)
108112
{
109113
$username = $this->validator->validateUsername($input->getArgument('username'));
110114

111-
$repository = $this->entityManager->getRepository(User::class);
112115
/** @var User $user */
113-
$user = $repository->findOneByUsername($username);
116+
$user = $this->users->findOneByUsername($username);
114117

115118
if (null === $user) {
116119
throw new RuntimeException(sprintf('User with username "%s" not found.', $username));

src/Command/ListUsersCommand.php

+6-6
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
namespace App\Command;
1313

1414
use App\Entity\User;
15-
use Doctrine\ORM\EntityManagerInterface;
15+
use App\Repository\UserRepository;
1616
use Symfony\Component\Console\Command\Command;
1717
use Symfony\Component\Console\Input\InputInterface;
1818
use Symfony\Component\Console\Input\InputOption;
@@ -39,17 +39,17 @@ class ListUsersCommand extends Command
3939
// a good practice is to use the 'app:' prefix to group all your custom application commands
4040
protected static $defaultName = 'app:list-users';
4141

42-
private $entityManager;
4342
private $mailer;
4443
private $emailSender;
44+
private $users;
4545

46-
public function __construct(EntityManagerInterface $em, \Swift_Mailer $mailer, $emailSender)
46+
public function __construct(\Swift_Mailer $mailer, $emailSender, UserRepository $users)
4747
{
4848
parent::__construct();
4949

50-
$this->entityManager = $em;
5150
$this->mailer = $mailer;
5251
$this->emailSender = $emailSender;
52+
$this->users = $users;
5353
}
5454

5555
/**
@@ -91,7 +91,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
9191
{
9292
$maxResults = $input->getOption('max-results');
9393
// Use ->findBy() instead of ->findAll() to allow result sorting and limiting
94-
$users = $this->entityManager->getRepository(User::class)->findBy([], ['id' => 'DESC'], $maxResults);
94+
$allUsers = $this->users->findBy([], ['id' => 'DESC'], $maxResults);
9595

9696
// Doctrine query returns an array of objects and we need an array of plain arrays
9797
$usersAsPlainArrays = array_map(function (User $user) {
@@ -102,7 +102,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
102102
$user->getEmail(),
103103
implode(', ', $user->getRoles()),
104104
];
105-
}, $users);
105+
}, $allUsers);
106106

107107
// In your console commands you should always use the regular output type,
108108
// which outputs contents directly in the console window. However, this

src/Controller/Admin/BlogController.php

+4-4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use App\Entity\Post;
1515
use App\Form\PostType;
16+
use App\Repository\PostRepository;
1617
use App\Utils\Slugger;
1718
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
1819
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
@@ -54,12 +55,11 @@ class BlogController extends AbstractController
5455
* @Route("/", name="admin_post_index")
5556
* @Method("GET")
5657
*/
57-
public function index(): Response
58+
public function index(PostRepository $posts): Response
5859
{
59-
$em = $this->getDoctrine()->getManager();
60-
$posts = $em->getRepository(Post::class)->findBy(['author' => $this->getUser()], ['publishedAt' => 'DESC']);
60+
$authorPosts = $posts->findBy(['author' => $this->getUser()], ['publishedAt' => 'DESC']);
6161

62-
return $this->render('admin/blog/index.html.twig', ['posts' => $posts]);
62+
return $this->render('admin/blog/index.html.twig', ['posts' => $authorPosts]);
6363
}
6464

6565
/**

src/Controller/BlogController.php

+7-7
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use App\Entity\Post;
1616
use App\Events;
1717
use App\Form\CommentType;
18+
use App\Repository\PostRepository;
1819
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache;
1920
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
2021
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
@@ -47,15 +48,14 @@ class BlogController extends AbstractController
4748
* Content-Type header for the response.
4849
* See https://symfony.com/doc/current/quick_tour/the_controller.html#using-formats
4950
*/
50-
public function index(int $page, string $_format): Response
51+
public function index(int $page, string $_format, PostRepository $posts): Response
5152
{
52-
$em = $this->getDoctrine()->getManager();
53-
$posts = $em->getRepository(Post::class)->findLatest($page);
53+
$latestPosts = $posts->findLatest($page);
5454

5555
// Every template name also has two extensions that specify the format and
5656
// engine for that template.
5757
// See https://symfony.com/doc/current/templating.html#template-suffix
58-
return $this->render('blog/index.'.$_format.'.twig', ['posts' => $posts]);
58+
return $this->render('blog/index.'.$_format.'.twig', ['posts' => $latestPosts]);
5959
}
6060

6161
/**
@@ -148,18 +148,18 @@ public function commentForm(Post $post): Response
148148
* @Route("/search", name="blog_search")
149149
* @Method("GET")
150150
*/
151-
public function search(Request $request): Response
151+
public function search(Request $request, PostRepository $posts): Response
152152
{
153153
if (!$request->isXmlHttpRequest()) {
154154
return $this->render('blog/search.html.twig');
155155
}
156156

157157
$query = $request->query->get('q', '');
158158
$limit = $request->query->get('l', 10);
159-
$posts = $this->getDoctrine()->getRepository(Post::class)->findBySearchQuery($query, $limit);
159+
$foundPosts = $posts->findBySearchQuery($query, $limit);
160160

161161
$results = [];
162-
foreach ($posts as $post) {
162+
foreach ($foundPosts as $post) {
163163
$results[] = [
164164
'title' => htmlspecialchars($post->getTitle()),
165165
'date' => $post->getPublishedAt()->format('M d, Y'),

src/Repository/PostRepository.php

+8-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
namespace App\Repository;
1313

1414
use App\Entity\Post;
15-
use Doctrine\ORM\EntityRepository;
15+
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
16+
use Doctrine\Common\Persistence\ManagerRegistry;
1617
use Doctrine\ORM\Query;
1718
use Pagerfanta\Adapter\DoctrineORMAdapter;
1819
use Pagerfanta\Pagerfanta;
@@ -27,8 +28,13 @@
2728
* @author Javier Eguiluz <[email protected]>
2829
* @author Yonel Ceruto <[email protected]>
2930
*/
30-
class PostRepository extends EntityRepository
31+
class PostRepository extends ServiceEntityRepository
3132
{
33+
public function __construct(ManagerRegistry $registry)
34+
{
35+
parent::__construct($registry, Post::class);
36+
}
37+
3238
public function findLatest(int $page = 1): Pagerfanta
3339
{
3440
$query = $this->getEntityManager()

src/Repository/UserRepository.php

+8-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111

1212
namespace App\Repository;
1313

14-
use Doctrine\ORM\EntityRepository;
14+
use App\Entity\User;
15+
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
16+
use Doctrine\Common\Persistence\ManagerRegistry;
1517

1618
/**
1719
* This custom Doctrine repository is empty because so far we don't need any custom
@@ -23,6 +25,10 @@
2325
* @author Ryan Weaver <[email protected]>
2426
* @author Javier Eguiluz <[email protected]>
2527
*/
26-
class UserRepository extends EntityRepository
28+
class UserRepository extends ServiceEntityRepository
2729
{
30+
public function __construct(ManagerRegistry $registry)
31+
{
32+
parent::__construct($registry, User::class);
33+
}
2834
}

tests/Command/AddUserCommandTest.php

+4-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use App\Command\AddUserCommand;
1515
use App\Entity\User;
1616
use App\Utils\Validator;
17+
use Doctrine\Bundle\DoctrineBundle\Registry;
1718
use Symfony\Bundle\FrameworkBundle\Console\Application;
1819
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
1920
use Symfony\Component\Console\Tester\CommandTester;
@@ -117,7 +118,9 @@ private function executeCommand(array $arguments, array $inputs = [])
117118
self::bootKernel();
118119

119120
$container = self::$kernel->getContainer();
120-
$command = new AddUserCommand($container->get('doctrine')->getManager(), $container->get('security.password_encoder'), new Validator());
121+
/** @var Registry $doctrine */
122+
$doctrine = $container->get('doctrine');
123+
$command = new AddUserCommand($doctrine->getManager(), $container->get('security.password_encoder'), new Validator(), $doctrine->getRepository(User::class));
121124
$command->setApplication(new Application(self::$kernel));
122125

123126
$commandTester = new CommandTester($command);

0 commit comments

Comments
 (0)