[Core][Contact] Fixes after PR review

This commit is contained in:
Grzegorz Sadowski 2016-12-16 22:38:09 +01:00
parent 68e956f1cc
commit 9b824d65a4
15 changed files with 161 additions and 148 deletions

View file

@ -1,8 +1,8 @@
@requesting_contact
Feature: Requesting contact
In order to get help from the store's support team
In order to receive help from the store's support
As a Customer
I want to be able to send message to store's support team
I want to be able to send a message to the store's support
Background:
Given the store operates on a single channel in "United States"
@ -10,7 +10,7 @@ Feature: Requesting contact
@ui @email
Scenario: Requesting contact as a logged in customer
Given there is a user "lucifer@morningstar.com" identified by "devil"
Given there is a user "lucifer@morningstar.com"
And I am logged in as "lucifer@morningstar.com"
When I want to request contact
And I specify the message as "Hi! I did not receive an item!"
@ -18,7 +18,6 @@ Feature: Requesting contact
Then I should be notified that the contact request has been submitted successfully
And the email with contact request should be sent to "contact@goodshop.com"
@ui @email
Scenario: Requesting contact as a guest
When I want to request contact

View file

@ -2,7 +2,7 @@
Feature: Requesting contact validation
In order to avoid making mistakes when requesting contact
As a Customer
I want to be prevented from making mistakes in my email address
I want to be prevented from making mistakes in my contact request
Background:
Given the store operates on a single channel in "United States"
@ -41,4 +41,4 @@ Feature: Requesting contact validation
And I specify the email as "lucifer@morningstar.com"
And I specify the message as "Hi! I did not receive an item!"
And I try to send it
Then I should be notified that there was a problem with sending a contact request
Then I should be notified that a problem occured while sending the contact request

View file

@ -104,24 +104,24 @@ final class ContactContext implements Context
}
/**
* @Then /^I should be notified that the (email) is invalid$/
* @Then I should be notified that the email is invalid
*/
public function iShouldBeNotifiedThatElementIsInvalid($element)
public function iShouldBeNotifiedThatEmailIsInvalid()
{
$this->assertFieldValidationMessage(
$this->contactPage,
$element,
sprintf('This %s is invalid.', $element)
'email',
'This email is invalid.'
);
}
/**
* @Then /^I should be notified that there was a problem with sending a contact request$/
* @Then I should be notified that a problem occured while sending the contact request
*/
public function iShouldBeNotifiedThatThereWasAProblemWithSendingAContactRequest()
public function iShouldBeNotifiedThatAProblemOccuredWhileSendingTheContactRequest()
{
$this->notificationChecker->checkNotification(
'There was a problem with sending a contact request. Please try again later.',
'A problem occurred while sending the contact request. Please try again later.',
NotificationType::failure()
);
}
@ -133,9 +133,12 @@ final class ContactContext implements Context
*/
private function assertFieldValidationMessage(PageInterface $page, $element, $expectedMessage)
{
Assert::true(
$page->checkValidationMessageFor($element, $expectedMessage),
sprintf('There should be a message: "%s".', $expectedMessage)
$currentMessage = $page->getValidationMessageFor($element);
Assert::same(
$currentMessage,
$expectedMessage,
'There is a message: "%s", but should be: "%s".'
);
}
}

View file

@ -15,7 +15,7 @@ use Behat\Mink\Exception\ElementNotFoundException;
use Sylius\Behat\Page\SymfonyPage;
/**
* @author Grzegorz Sadowski <grzegorz.sadowksi@lakion.com>
* @author Grzegorz Sadowski <grzegorz.sadowski@lakion.com>
*/
class ContactPage extends SymfonyPage implements ContactPageInterface
{
@ -53,7 +53,7 @@ class ContactPage extends SymfonyPage implements ContactPageInterface
*
* @throws ElementNotFoundException
*/
public function checkValidationMessageFor($element, $message)
public function getValidationMessageFor($element)
{
$errorLabel = $this->getElement($element)->getParent()->find('css', '.sylius-validation-error');
@ -64,7 +64,7 @@ class ContactPage extends SymfonyPage implements ContactPageInterface
;
}
return $message === $errorLabel->getText();
return $errorLabel->getText();
}
/**

View file

@ -32,9 +32,8 @@ interface ContactPageInterface extends PageInterface
/**
* @param string $element
* @param string $message
*
* @return bool
* @return string
*/
public function checkValidationMessageFor($element, $message);
public function getValidationMessageFor($element);
}

View file

@ -12,8 +12,6 @@
namespace Sylius\Bundle\CoreBundle\EmailManager;
use Sylius\Bundle\CoreBundle\Mailer\Emails;
use Sylius\Component\Channel\Context\ChannelContextInterface;
use Sylius\Component\Core\Model\ChannelInterface;
use Sylius\Component\Mailer\Sender\SenderInterface;
/**
@ -26,46 +24,20 @@ final class ContactEmailManager
*/
private $emailSender;
/**
* @var ChannelContextInterface
*/
private $channelContext;
/**
* @param SenderInterface $emailSender
* @param ChannelContextInterface $channelContext
*/
public function __construct(SenderInterface $emailSender, ChannelContextInterface $channelContext)
public function __construct(SenderInterface $emailSender)
{
$this->emailSender = $emailSender;
$this->channelContext = $channelContext;
}
/**
* @param array $data
*
* @return bool
* @param array $recipients
*/
public function sendContactRequest(array $data)
public function sendContactRequest(array $data, array $recipients)
{
/** @var ChannelInterface $channel */
$channel = $this->channelContext->getChannel();
$contactEmail = $channel->getContactEmail();
if (null === $contactEmail) {
return false;
}
$this->emailSender->send(
Emails::CONTACT_REQUEST,
[
$contactEmail,
],
[
'data' => $data,
]
);
return true;
$this->emailSender->send(Emails::CONTACT_REQUEST, $recipients, ['data' => $data]);
}
}

View file

@ -11,13 +11,13 @@
namespace Sylius\Bundle\CoreBundle\Form\Type;
use Sylius\Component\Customer\Context\CustomerContextInterface;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\Email;
use Symfony\Component\Validator\Constraints\NotBlank;
@ -26,19 +26,6 @@ use Symfony\Component\Validator\Constraints\NotBlank;
*/
final class ContactType extends AbstractType
{
/**
* @var CustomerContextInterface
*/
private $customerContext;
/**
* @param CustomerContextInterface $customerContext
*/
public function __construct(CustomerContextInterface $customerContext)
{
$this->customerContext = $customerContext;
}
/**
* {@inheritdoc}
*/
@ -64,21 +51,32 @@ final class ContactType extends AbstractType
]),
],
])
->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
$customer = $this->customerContext->getCustomer();
if (null === $customer) {
->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($options) {
$email = $options['email'];
if (null === $email) {
return;
}
$data = $event->getData();
$data['email'] = $customer->getEmail();
$data['email'] = $email;
$event->setData($data);
})
;
}
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver
->setDefaults([
'email' => null,
])
;
}
/**
* {@inheritdoc}
*/

View file

@ -24,7 +24,6 @@
<service id="sylius.email_manager.contact" class="Sylius\Bundle\CoreBundle\EmailManager\ContactEmailManager">
<argument type="service" id="sylius.email_sender" />
<argument type="service" id="sylius.context.channel" />
</service>
<service id="sylius.email_manager.order" class="Sylius\Bundle\CoreBundle\EmailManager\OrderEmailManager">

View file

@ -197,11 +197,6 @@
<tag name="form.type" />
</service>
<service id="sylius.form.type.contact" class="Sylius\Bundle\CoreBundle\Form\Type\ContactType">
<argument type="service" id="sylius.context.customer" />
<tag name="form.type" />
</service>
<service id="sylius.form.event_subscriber.channel_pricing" class="Sylius\Bundle\CoreBundle\Form\EventSubscriber\ChannelPricingsFormSubscriber">
<argument type="service" id="sylius.repository.channel" />
<argument type="service" id="sylius.factory.channel_pricing" />

View file

@ -13,8 +13,6 @@ namespace spec\Sylius\Bundle\CoreBundle\EmailManager;
use PhpSpec\ObjectBehavior;
use Sylius\Bundle\CoreBundle\EmailManager\ContactEmailManager;
use Sylius\Component\Channel\Context\ChannelContextInterface;
use Sylius\Component\Core\Model\ChannelInterface;
use Sylius\Component\Mailer\Sender\SenderInterface;
/**
@ -22,9 +20,9 @@ use Sylius\Component\Mailer\Sender\SenderInterface;
*/
final class ContactEmailManagerSpec extends ObjectBehavior
{
function let(SenderInterface $sender, ChannelContextInterface $channelContext)
function let(SenderInterface $sender)
{
$this->beConstructedWith($sender, $channelContext);
$this->beConstructedWith($sender);
}
function it_is_initializable()
@ -32,14 +30,8 @@ final class ContactEmailManagerSpec extends ObjectBehavior
$this->shouldHaveType(ContactEmailManager::class);
}
function it_sends_a_contact_request_email(
SenderInterface $sender,
ChannelContextInterface $channelContext,
ChannelInterface $channel
) {
$channelContext->getChannel()->willReturn($channel);
$channel->getContactEmail()->willReturn('contact@example.com');
function it_sends_a_contact_request_email(SenderInterface $sender)
{
$sender
->send(
'contact_request',
@ -55,27 +47,13 @@ final class ContactEmailManagerSpec extends ObjectBehavior
;
$this
->sendContactRequest([
'email' => 'customer@example.com',
'message' => 'Hello!',
])
->shouldReturn(true);
;
}
function it_does_not_send_a_contact_request_email_when_channel_has_no_contact_email_set(
ChannelContextInterface $channelContext,
ChannelInterface $channel
) {
$channelContext->getChannel()->willReturn($channel);
$channel->getContactEmail()->willReturn(null);
$this
->sendContactRequest([
'email' => 'customer@example.com',
'message' => 'Hello!',
])
->shouldReturn(false);
->sendContactRequest(
[
'email' => 'customer@example.com',
'message' => 'Hello!',
],
['contact@example.com']
)
;
}
}

View file

@ -13,25 +13,71 @@ namespace Sylius\Bundle\ShopBundle\Controller;
use Sylius\Bundle\CoreBundle\EmailManager\ContactEmailManager;
use Sylius\Bundle\CoreBundle\Form\Type\ContactType;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sylius\Component\Channel\Context\ChannelContextInterface;
use Sylius\Component\Customer\Context\CustomerContextInterface;
use Symfony\Bundle\FrameworkBundle\Templating\EngineInterface;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\RouterInterface;
/**
* @author Grzegorz Sadowski <grzegorz.sadowski@lakion.com>
*/
class ContactController extends Controller
class ContactController
{
/**
* @var RouterInterface
*/
private $router;
/**
* @var FormFactoryInterface
*/
private $formFactory;
/**
* @var EngineInterface
*/
private $templatingEngine;
/**
* @var ChannelContextInterface
*/
private $channelContext;
/**
* @var CustomerContextInterface
*/
private $customerContext;
/**
* @var ContactEmailManager
*/
private $contactEmailManager;
/**
* @param RouterInterface $router
* @param FormFactoryInterface $formFactory
* @param EngineInterface $templatingEngine
* @param ChannelContextInterface $channelContext
* @param CustomerContextInterface $customerContext
* @param ContactEmailManager $contactEmailManager
*/
public function __construct(ContactEmailManager $contactEmailManager)
{
public function __construct(
RouterInterface $router,
FormFactoryInterface $formFactory,
EngineInterface $templatingEngine,
ChannelContextInterface $channelContext,
CustomerContextInterface $customerContext,
ContactEmailManager $contactEmailManager
) {
$this->router = $router;
$this->formFactory = $formFactory;
$this->templatingEngine = $templatingEngine;
$this->channelContext = $channelContext;
$this->customerContext = $customerContext;
$this->contactEmailManager = $contactEmailManager;
}
@ -43,47 +89,68 @@ class ContactController extends Controller
public function requestAction(Request $request)
{
$formType = $this->getSyliusAttribute($request, 'form', ContactType::class);
$form = $this->createForm($formType);
$form = $this->formFactory->create($formType, null, $this->getFormOptions());
if ($request->isMethod('POST') && $form->handleRequest($request)->isValid()) {
$data = $form->getData();
$channel = $this->channelContext->getChannel();
$contactEmail = $channel->getContactEmail();
if (!$this->contactEmailManager->sendContactRequest($data)) {
$flashMessage = $this->getSyliusAttribute($request, 'error_flash', 'sylius.contact.request_error');
$this->addFlash('error', $flashMessage);
if (null === $contactEmail) {
$errorMessage = $this->getSyliusAttribute(
$request,
'error_flash',
'sylius.contact.request_error'
);
$request->getSession()->getFlashBag()->add('error', $errorMessage);
return $this->redirect($request->headers->get('referer'));
return new RedirectResponse($request->headers->get('referer'));
}
$flashMessage = $this->getSyliusAttribute($request, 'success_flash', 'sylius.contact.request_success');
$this->addFlash('success', $flashMessage);
$this->contactEmailManager->sendContactRequest($data, [$contactEmail]);
$successMessage = $this->getSyliusAttribute(
$request,
'success_flash',
'sylius.contact.request_success'
);
$request->getSession()->getFlashBag()->add('success', $successMessage);
$redirectRoute = $this->getSyliusAttribute($request, 'redirect', 'referer');
return $this->redirectToRoute($redirectRoute);
return new RedirectResponse($this->router->generate($redirectRoute));
}
$template = $this->getSyliusAttribute($request, 'template');
$template = $this->getSyliusAttribute($request, 'template', "@SyliusShop/Contact/request.html.twig");
return $this->render(
$template,
[
'form' => $form->createView(),
]
);
return $this->templatingEngine->renderResponse($template, ['form' => $form->createView()]);
}
/**
* @param Request $request
* @param string $attribute
* @param mixed $default
* @param string $attributeName
* @param string|null $default
*
* @return mixed
* @return string|null
*/
private function getSyliusAttribute(Request $request, $attribute, $default = null)
private function getSyliusAttribute(Request $request, $attributeName, $default = null)
{
$attributes = $request->attributes->get('_sylius');
return isset($attributes[$attribute]) ? $attributes[$attribute] : $default;
return isset($attributes[$attributeName]) ? $attributes[$attributeName] : $default;
}
/**
* @return array
*/
private function getFormOptions()
{
$customer = $this->customerContext->getCustomer();
if (null === $customer) {
return [];
}
return ['email' => $customer->getEmail()];
}
}

View file

@ -7,5 +7,4 @@ sylius_shop_contact_request:
defaults:
_controller: sylius.controller.shop.contact:requestAction
_sylius:
template: "@SyliusShop/Contact/request.html.twig"
redirect: sylius_shop_homepage

View file

@ -14,9 +14,11 @@
<container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="sylius.controller.shop.contact" class="Sylius\Bundle\ShopBundle\Controller\ContactController">
<call method="setContainer">
<argument type="service" id="service_container" />
</call>
<argument type="service" id="router" />
<argument type="service" id="form.factory" />
<argument type="service" id="templating" />
<argument type="service" id="sylius.context.channel" />
<argument type="service" id="sylius.context.customer" />
<argument type="service" id="sylius.email_manager.contact" />
</service>

View file

@ -6,7 +6,7 @@ sylius:
delete_error: 'The channel cannot be deleted. At least one enabled channel is required.'
contact:
request_success: 'Your contact request has been submitted successfully.'
request_error: 'There was a problem with sending a contact request. Please try again later.'
request_error: 'A problem occurred while sending the contact request. Please try again later.'
customer:
add_address: 'Address has been successfully added.'
impersonate: 'Successfully impersonated customer %name%.'

View file

@ -35,7 +35,7 @@ final class ChannelSpec extends ObjectBehavior
$this->shouldImplement(ChannelInterface::class);
}
function it_extends_an_channel()
function it_extends_a_channel()
{
$this->shouldHaveType(BaseChannel::class);
}
@ -84,36 +84,38 @@ final class ChannelSpec extends ObjectBehavior
$this->getTaxCalculationStrategy()->shouldReturn($taxCalculationStrategy);
}
function it_initializes_currencies_collection_by_default()
function it_has_an_empty_collection_of_currencies_by_default()
{
$this->getCurrencies()->shouldHaveType(Collection::class);
$this->getCurrencies()->count()->shouldReturn(0);
}
function it_adds_a_currency(CurrencyInterface $currency)
function it_can_have_a_currency_added(CurrencyInterface $currency)
{
$this->addCurrency($currency);
$this->hasCurrency($currency)->shouldReturn(true);
}
function it_removes_a_currency(CurrencyInterface $currency)
function it_can_have_a_currency_removed(CurrencyInterface $currency)
{
$this->addCurrency($currency);
$this->removeCurrency($currency);
$this->hasCurrency($currency)->shouldReturn(false);
}
function it_initializes_locales_collection_by_default()
function it_has_an_empty_collection_of_locales_by_default()
{
$this->getLocales()->shouldHaveType(Collection::class);
$this->getLocales()->count()->shouldReturn(0);
}
function it_adds_a_locale(LocaleInterface $locale)
function it_can_have_a_locale_added(LocaleInterface $locale)
{
$this->addLocale($locale);
$this->hasLocale($locale)->shouldReturn(true);
}
function it_removes_a_locale(LocaleInterface $locale)
function it_can_have_a_locale_removed(LocaleInterface $locale)
{
$this->addLocale($locale);
$this->removeLocale($locale);