diff --git a/src/AppBundle/Command/AddUserCommand.php b/src/AppBundle/Command/AddUserCommand.php index 17e0744a4..994829261 100644 --- a/src/AppBundle/Command/AddUserCommand.php +++ b/src/AppBundle/Command/AddUserCommand.php @@ -12,6 +12,7 @@ namespace AppBundle\Command; use AppBundle\Entity\User; +use AppBundle\Utils\Validator; use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; @@ -23,7 +24,7 @@ use Symfony\Component\Stopwatch\Stopwatch; /** - * A command console that creates users and stores them in the database. + * A console command that creates users and stores them in the database. * * To use this command, open a terminal window, enter into your project * directory and execute the following: @@ -48,13 +49,15 @@ class AddUserCommand extends Command private $io; private $entityManager; private $passwordEncoder; + private $validator; - public function __construct(EntityManagerInterface $em, UserPasswordEncoderInterface $encoder) + public function __construct(EntityManagerInterface $em, UserPasswordEncoderInterface $encoder, Validator $validator) { parent::__construct(); $this->entityManager = $em; $this->passwordEncoder = $encoder; + $this->validator = $validator; } /** @@ -120,14 +123,7 @@ protected function interact(InputInterface $input, OutputInterface $output) if (null !== $username) { $this->io->text(' > Username: '.$username); } else { - $username = $this->io->ask('Username', null, function ($answer) { - if (empty($answer)) { - throw new \RuntimeException('The username cannot be empty'); - } - - return $answer; - }); - + $username = $this->io->ask('Username', null, [$this->validator, 'validateUsername']); $input->setArgument('username', $username); } @@ -136,7 +132,7 @@ protected function interact(InputInterface $input, OutputInterface $output) if (null !== $password) { $this->io->text(' > Password: '.str_repeat('*', mb_strlen($password))); } else { - $password = $this->io->askHidden('Password (your type will be hidden)', null, [$this, 'passwordValidator']); + $password = $this->io->askHidden('Password (your type will be hidden)', null, [$this, 'validatePassword']); $input->setArgument('password', $password); } @@ -145,7 +141,7 @@ protected function interact(InputInterface $input, OutputInterface $output) if (null !== $email) { $this->io->text(' > Email: '.$email); } else { - $email = $this->io->ask('Email', null, [$this, 'emailValidator']); + $email = $this->io->ask('Email', null, [$this->validator, 'validateEmail']); $input->setArgument('email', $email); } @@ -154,7 +150,7 @@ protected function interact(InputInterface $input, OutputInterface $output) if (null !== $fullName) { $this->io->text(' > Full Name: '.$fullName); } else { - $fullName = $this->io->ask('Full Name', null, [$this, 'fullNameValidator']); + $fullName = $this->io->ask('Full Name', null, [$this->validator, 'validateFullName']); $input->setArgument('full-name', $fullName); } } @@ -199,50 +195,6 @@ protected function execute(InputInterface $input, OutputInterface $output) } } - /** - * @internal - */ - public function passwordValidator($plainPassword) - { - if (empty($plainPassword)) { - throw new \Exception('The password can not be empty.'); - } - - if (mb_strlen(trim($plainPassword)) < 6) { - throw new \Exception('The password must be at least 6 characters long.'); - } - - return $plainPassword; - } - - /** - * @internal - */ - public function emailValidator($email) - { - if (empty($email)) { - throw new \Exception('The email can not be empty.'); - } - - if (false === mb_strpos($email, '@')) { - throw new \Exception('The email should look like a real email.'); - } - - return $email; - } - - /** - * @internal - */ - public function fullNameValidator($fullName) - { - if (empty($fullName)) { - throw new \Exception('The full name can not be empty.'); - } - - return $fullName; - } - private function validateUserData($username, $plainPassword, $email, $fullName) { $userRepository = $this->entityManager->getRepository(User::class); @@ -255,9 +207,9 @@ private function validateUserData($username, $plainPassword, $email, $fullName) } // validate password and email if is not this input means interactive. - $this->passwordValidator($plainPassword); - $this->emailValidator($email); - $this->fullNameValidator($fullName); + $this->validator->validatePassword($plainPassword); + $this->validator->validateEmail($email); + $this->validator->validateFullName($fullName); // check if a user with the same email already exists. $existingEmail = $userRepository->findOneBy(['email' => $email]); diff --git a/src/AppBundle/Command/DeleteUserCommand.php b/src/AppBundle/Command/DeleteUserCommand.php index a89db0ecb..a3a287e71 100644 --- a/src/AppBundle/Command/DeleteUserCommand.php +++ b/src/AppBundle/Command/DeleteUserCommand.php @@ -12,6 +12,7 @@ namespace AppBundle\Command; use AppBundle\Entity\User; +use AppBundle\Utils\Validator; use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; @@ -20,7 +21,7 @@ use Symfony\Component\Console\Style\SymfonyStyle; /** - * A command console that deletes users from the database. + * A console command that deletes users from the database. * * To use this command, open a terminal window, enter into your project * directory and execute the following: @@ -42,12 +43,14 @@ class DeleteUserCommand extends Command private $io; private $entityManager; + private $validator; - public function __construct(EntityManagerInterface $em) + public function __construct(EntityManagerInterface $em, Validator $validator) { parent::__construct(); $this->entityManager = $em; + $this->validator = $validator; } /** @@ -103,8 +106,7 @@ protected function interact(InputInterface $input, OutputInterface $output) protected function execute(InputInterface $input, OutputInterface $output) { - $username = $input->getArgument('username'); - $this->usernameValidator($username); + $username = $this->validator->validateUsername($input->getArgument('username')); $repository = $this->entityManager->getRepository(User::class); /** @var User $user */ @@ -124,23 +126,4 @@ protected function execute(InputInterface $input, OutputInterface $output) $this->io->success(sprintf('User "%s" (ID: %d, email: %s) was successfully deleted.', $user->getUsername(), $userId, $user->getEmail())); } - - /** - * This internal method should be private, but it's declared public to - * maintain PHP 5.3 compatibility when using it in a callback. - * - * @internal - */ - public function usernameValidator($username) - { - if (empty($username)) { - throw new \Exception('The username can not be empty.'); - } - - if (1 !== preg_match('/^[a-z_]+$/', $username)) { - throw new \Exception('The username must contain only lowercase latin characters and underscores.'); - } - - return $username; - } } diff --git a/src/AppBundle/Command/ListUsersCommand.php b/src/AppBundle/Command/ListUsersCommand.php index 59950debe..bd0794369 100644 --- a/src/AppBundle/Command/ListUsersCommand.php +++ b/src/AppBundle/Command/ListUsersCommand.php @@ -21,7 +21,7 @@ use Symfony\Component\Console\Style\SymfonyStyle; /** - * A command console that lists all the existing users. + * A console command that lists all the existing users. * * To use this command, open a terminal window, enter into your project directory * and execute the following: diff --git a/src/AppBundle/Utils/Validator.php b/src/AppBundle/Utils/Validator.php new file mode 100644 index 000000000..770117b10 --- /dev/null +++ b/src/AppBundle/Utils/Validator.php @@ -0,0 +1,63 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace AppBundle\Utils; + +class Validator +{ + public function validateUsername($username) + { + if (empty($username)) { + throw new \Exception('The username can not be empty.'); + } + + if (1 !== preg_match('/^[a-z_]+$/', $username)) { + throw new \Exception('The username must contain only lowercase latin characters and underscores.'); + } + + return $username; + } + + public function validatePassword($plainPassword) + { + if (empty($plainPassword)) { + throw new \Exception('The password can not be empty.'); + } + + if (mb_strlen(trim($plainPassword)) < 6) { + throw new \Exception('The password must be at least 6 characters long.'); + } + + return $plainPassword; + } + + public function validateEmail($email) + { + if (empty($email)) { + throw new \Exception('The email can not be empty.'); + } + + if (false === mb_strpos($email, '@')) { + throw new \Exception('The email should look like a real email.'); + } + + return $email; + } + + public function validateFullName($fullName) + { + if (empty($fullName)) { + throw new \Exception('The full name can not be empty.'); + } + + return $fullName; + } +} diff --git a/tests/AppBundle/Command/AddUserCommandTest.php b/tests/AppBundle/Command/AddUserCommandTest.php index 7c835665f..d372e60ea 100644 --- a/tests/AppBundle/Command/AddUserCommandTest.php +++ b/tests/AppBundle/Command/AddUserCommandTest.php @@ -13,6 +13,7 @@ use AppBundle\Command\AddUserCommand; use AppBundle\Entity\User; +use AppBundle\Utils\Validator; use Symfony\Bundle\FrameworkBundle\Console\Application; use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; use Symfony\Component\Console\Tester\CommandTester; @@ -66,7 +67,7 @@ public function testCreateUserNonInteractive($isAdmin) public function testCreateUserInteractive($isAdmin) { $this->executeCommand( - // these are the arguments (only 1 is passed, the rest are missing) + // these are the arguments (only 1 is passed, the rest are missing) $isAdmin ? ['--admin' => 1] : [], // these are the responses given to the questions asked by the command // to get the value of the missing required arguments @@ -116,7 +117,7 @@ private function executeCommand(array $arguments, array $inputs = []) self::bootKernel(); $container = self::$kernel->getContainer(); - $command = new AddUserCommand($container->get('doctrine')->getManager(), $container->get('security.password_encoder')); + $command = new AddUserCommand($container->get('doctrine')->getManager(), $container->get('security.password_encoder'), new Validator()); $command->setApplication(new Application(self::$kernel)); $commandTester = new CommandTester($command); diff --git a/tests/AppBundle/Utils/ValidatorTest.php b/tests/AppBundle/Utils/ValidatorTest.php new file mode 100644 index 000000000..0da2315ea --- /dev/null +++ b/tests/AppBundle/Utils/ValidatorTest.php @@ -0,0 +1,96 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Tests\AppBundle\Utils; + +use AppBundle\Utils\Validator; + +class ValidatorTest extends \PHPUnit_Framework_TestCase +{ + private $object; + + public function __construct() + { + parent::__construct(); + + $this->object = new Validator(); + } + + public function testValidateUsername() + { + $test = 'username'; + + $this->assertSame($test, $this->object->validateUsername($test)); + } + + public function testValidateUsernameEmpty() + { + $this->setExpectedException('Exception', 'The username can not be empty.'); + $this->object->validateUsername(null); + } + + public function testValidateUsernameInvalid() + { + $this->setExpectedException('Exception', 'The username must contain only lowercase latin characters and underscores.'); + $this->object->validateUsername('INVALID'); + } + + public function testValidatePassword() + { + $test = 'password'; + + $this->assertSame($test, $this->object->validatePassword($test)); + } + + public function testValidatePasswordEmpty() + { + $this->setExpectedException('Exception', 'The password can not be empty.'); + $this->object->validatePassword(null); + } + + public function testValidatePasswordInvalid() + { + $this->setExpectedException('Exception', 'The password must be at least 6 characters long.'); + $this->object->validatePassword('12345'); + } + + public function testValidateEmail() + { + $test = '@'; + + $this->assertSame($test, $this->object->validateEmail($test)); + } + + public function testValidateEmailEmpty() + { + $this->setExpectedException('Exception', 'The email can not be empty.'); + $this->object->validateEmail(null); + } + + public function testValidateEmailInvalid() + { + $this->setExpectedException('Exception', 'The email should look like a real email.'); + $this->object->validateEmail('invalid'); + } + + public function testValidateFullName() + { + $test = 'Full Name'; + + $this->assertSame($test, $this->object->validateFullName($test)); + } + + public function testValidateEmailFullName() + { + $this->setExpectedException('Exception', 'The full name can not be empty.'); + $this->object->validateFullName(null); + } +}