Я настраиваю Sylius 1.8.6 с плагином Shop API
Что нужно сделать, так это добавить некоторые поля при регистрации пользователя. Мне удалось добавить их в сущность Sylius ShopUser, добавив в класс namespace App\Entity\User\ShopUser
namespace App\Entity\User;
use Doctrine\ORM\Mapping as ORM;
use Sylius\Component\Core\Model\ShopUser as BaseShopUser;
/**
* @ORM\Entity
* @ORM\Table(name = "sylius_shop_user")
*/
class ShopUser extends BaseShopUser
{
/**
* @var string
* @ORM\Column(type = "string", nullable=false)
*/
private string $permit;
public function getPermit(): string
{
return $this->permit;
}
public function setPermit(string $permit): void
{
$this->permit = $permit;
}
}
А к светильникам создав ShopUserFactory
<?php
namespace App\Fixtures;
use App\Entity\User\ShopUser;
use Sylius\Bundle\CoreBundle\Fixture\Factory\ShopUserExampleFactory;
use Sylius\Component\Core\Model\ShopUserInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class ShopUserFactory extends ShopUserExampleFactory
{
public function create(array $options = []): ShopUserInterface
{
/** @var ShopUser $user */
$user = parent::create($options);
if (isset($options['permit'])) {
$user->setPermit($options['permit']);
}
return $user;
}
protected function configureOptions(OptionsResolver $resolver): void
{
parent::configureOptions($resolver);
$resolver
->setDefault('permit', 'default_permit')
->setAllowedTypes('permit', ['string'])
;
}
}
и ShopUserFixture
<?php
namespace App\Fixtures;
use Sylius\Bundle\CoreBundle\Fixture\ShopUserFixture as ShopUserFixtureBase;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
final class ShopUserFixture extends ShopUserFixtureBase
{
protected function configureResourceNode(ArrayNodeDefinition $resourceNode): void
{
parent::configureResourceNode($resourceNode);
$resourceNode
->children()
->scalarNode('permit')->end();
}
}
И добавляю два к моему services.yaml
sylius.fixture.example_factory.shop_user:
class: App\Fixtures\ShopUserFactory
arguments:
- "@sylius.factory.shop_user"
public: true
sylius.fixture.shop_user:
class: App\Fixtures\ShopUserFixture
arguments:
- "@sylius.manager.shop_user"
- "@sylius.fixture.example_factory.shop_user"
tags:
- { name: sylius_fixtures.fixture }
Теперь я хочу убедиться, что это добавлено при вызове API /register Я следил за документацией и создал пользовательские Request, Handler и Command
#Request
<?php
namespace App\Controller\ShopAPI\Requests;
use App\Controller\ShopAPI\Commands\UserRegistrationCommand;
use Sylius\ShopApiPlugin\Command\CommandInterface;
use Sylius\ShopApiPlugin\Command\Customer\RegisterCustomer;
use Sylius\ShopApiPlugin\Request\Customer\RegisterCustomerRequest;
use Symfony\Component\HttpFoundation\RequestStack;
final class UserRegistration extends RegisterCustomerRequest
{
private $address;
private $city;
private $postcode;
private $permit;
public function __construct(RequestStack $requestStack, string $channelCode)
{
$request = $requestStack->getCurrentRequest();
parent::__construct($request, $channelCode);
$this->address = $request->request->get('address');
$this->postcode = $request->request->get('postcode');
$this->city = $request->request->get('city');
$this->permit = $request->request->get('permit');
var_dump($request->request->get('permit'));die;
}
public function getCommand(): CommandInterface
{
return new UserRegistrationCommand(
$this->email,
$this->plainPassword,
$this->firstName,
$this->lastName,
$this->channelCode,
$this->subscribedToNewsletter,
$this->phoneNumber,
$this->address,
$this->postcode,
$this->city,
$this->permit
);
}
}
#Command
<?php
namespace App\Controller\ShopAPI\Commands;
use Sylius\ShopApiPlugin\Command\Customer\RegisterCustomer;
class UserRegistrationCommand extends RegisterCustomer
{
protected string $address;
protected string $city;
protected string $postcode;
protected string $permit;
public function __construct(
string $email,
string $plainPassword,
string $firstName,
string $lastName,
string $channelCode,
?bool $subscribedToNewsletter,
?string $phoneNumber,
string $address,
string $city,
string $postcode,
string $permit
)
{
parent::__construct(
$email,
$plainPassword,
$firstName,
$lastName,
$channelCode,
$subscribedToNewsletter,
$phoneNumber
);
$this->address = $address;
$this->city = $city;
$this->postcode = $postcode;
$this->permit = $permit;
}
public function address(): string
{
return $this->address;
}
public function city(): string
{
return $this->city;
}
public function postcode(): string
{
return $this->postcode;
}
public function permit(): string
{
return $this->permit;
}
}
#Handler
<?php
declare(strict_types=1);
namespace App\Controller\ShopAPI\Handlers;
use App\Controller\ShopAPI\Commands\UserRegistrationCommand;
use App\Entity\User\ShopUser;
use Sylius\Component\Channel\Repository\ChannelRepositoryInterface;
use Sylius\Component\Core\Model\AddressInterface;
use Sylius\Component\Core\Model\ShopUserInterface;
use Sylius\Component\Core\Repository\AddressRepositoryInterface;
use Sylius\Component\Resource\Factory\FactoryInterface;
use Sylius\Component\User\Repository\UserRepositoryInterface;
use Sylius\ShopApiPlugin\Event\CustomerRegistered;
use Sylius\ShopApiPlugin\Provider\CustomerProviderInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Webmozart\Assert\Assert;
final class UserRegistrationHandler
{
/** @var UserRepositoryInterface */
private $userRepository;
/** @var ChannelRepositoryInterface */
private $channelRepository;
/** @var FactoryInterface */
private $userFactory;
/** @var EventDispatcherInterface */
private $eventDispatcher;
/** @var CustomerProviderInterface */
private $customerProvider;
/** @var FactoryInterface */
private FactoryInterface $addressFactory;
/** @var AddressRepositoryInterface */
private AddressRepositoryInterface $addressRepository;
public function __construct(
UserRepositoryInterface $userRepository,
AddressRepositoryInterface $addressRepository,
ChannelRepositoryInterface $channelRepository,
FactoryInterface $userFactory,
FactoryInterface $addressFactory,
EventDispatcherInterface $eventDispatcher,
CustomerProviderInterface $customerProvider
)
{
$this->userRepository = $userRepository;
$this->channelRepository = $channelRepository;
$this->userFactory = $userFactory;
$this->eventDispatcher = $eventDispatcher;
$this->customerProvider = $customerProvider;
$this->addressFactory = $addressFactory;
$this->addressRepository = $addressRepository;
}
public function __invoke(UserRegistrationCommand $command): void
{
$this->assertEmailIsNotTaken($command->email());
$this->assertChannelExists($command->channelCode());
$customer = $this->customerProvider->provide($command->email());
$customer->setFirstName($command->firstName());
$customer->setLastName($command->lastName());
$customer->setEmail($command->email());
$customer->setSubscribedToNewsletter($command->subscribedToNewsletter());
$customer->setPhoneNumber($command->phoneNumber());
/** @var ShopUser $user */
$user = $this->userFactory->createNew();
$user->setPlainPassword($command->plainPassword());
$user->setUsername($command->email());
$user->setPermit($command->permit());
$user->setCustomer($customer);
$this->userRepository->add($user);
/** @var AddressInterface $address */
$address = $this->addressFactory->createNew();
$address->setPostcode($command->postcode());
$address->setPhoneNumber($command->phoneNumber());
$address->setCity($command->city());
$address->setCustomer($user);
$this->addressRepository->add($address);
$customer->setDefaultAddress($address);
$this->eventDispatcher->dispatch('sylius.customer.post_api_registered', new CustomerRegistered(
$command->email(),
$command->firstName(),
$command->lastName(),
$command->channelCode(),
$command->subscribedToNewsletter(),
$command->phoneNumber()
));
}
private function assertEmailIsNotTaken(string $email): void
{
Assert::null($this->userRepository->findOneByEmail($email), 'User with given email already exists.');
}
private function assertChannelExists(string $channelCode): void
{
Assert::notNull($this->channelRepository->findOneByCode($channelCode), 'Channel does not exist.');
}
}
И я также добавил их в свой services.yaml
App\Controller\ShopAPI\Commands\UserRegistrationCommand:
arguments:
$email: "%email%"
App\Controller\ShopAPI\Handlers\UserRegistrationHandler:
public: true
arguments:
$userRepository: '@sylius.repository.shop_user'
$userFactory: '@sylius.factory.shop_user'
$customerProvider: '@sylius.shop_api_plugin.provider.customer_provider'
Sylius\ShopApiPlugin\Command\Customer\RegisterCustomer:
class: App\Controller\ShopAPI\Handlers\UserRegistrationHandler
App\Controller\ShopAPI\Requests\UserRegistration:
arguments:
$channelCode: "%channelCode%"
Как говорится в документации о переопределении обработчиков
Основной способ расширить обработчик — украсить его. Это упрощает добавление функциональности до и после обработчика. Однако, если вы хотите изменить логику в обработчике, вам необходимо перезаписать его. Это можно сделать, зарегистрировав новый обработчик с тем же идентификатором службы.
Я немного подумал:
Sylius\ShopApiPlugin\Command\Customer\RegisterCustomer:
class: App\Controller\ShopAPI\Handlers\UserRegistrationHandler
сделает запрос через мой класс вместо значения по умолчанию, однако я продолжаю получать сообщение об ошибке:
{
"code": 500,
"message": "An exception occurred while executing 'INSERT INTO sylius_shop_user (username, username_canonical, enabled, salt, password, encoder_name, last_login, password_reset_token, password_requested_at, email_verification_token, verified_at, locked, expires_at, credentials_expire_at, roles, email, email_canonical, created_at, updated_at, permit, customer_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)' with params [\"[email protected]\", \"[email protected]\", 0, \"ketyu603mrk0ksg0s0ssc0wkcw44k8g\", \"$argon2i$v=19$m=65536,t=4,p=1$Z09IeWlJR05nSW40cVYuYg$JIUtgpsZRVnKJoJJZvfN+kX5XRF+U69t8SQzRdZTVOs\", \"argon2i\", null, null, null, null, null, 0, null, null, \"a:1:{i:0;s:9:\\\"ROLE_USER\\\";}\", null, null, \"2020-12-22 08:41:08\", \"2020-12-22 08:41:08\", null, 102]:\n\nSQLSTATE[23000]: Integrity constraint violation: 1048 Column 'permit' cannot be null"
}
И при использовании xdebug или даже добавлении некоторых dd() внутри любого из этих трех классов код никогда не проходит через них.
Я неправильно регистрирую новую услугу? Я ничего не могу найти по этому поводу.
Спасибо за любой, указывающий мне в правильном направлении.






Хорошо, я заработал. После настройки всех служб у меня все еще была ошибка. Это было из-за моего
use Sylius\ShopApiPlugin\Command\Customer\RegisterCustomer;
class UserRegistrationCommand extends RegisterCustomer
и ChannelBasedCommandProvider позвонит
$this->requestClass::fromHttpRequestAndChannel($httpRequest, $channel);
И я не переопределял эту функцию в своем дочернем классе:
public static function fromHttpRequestAndChannel(Request $request, ChannelInterface $channel): ChannelBasedRequestInterface
{
return new self($request, $channel->getCode());
}
Таким образом, вместо этого он вернет родительский класс, и для этого класса больше нет обработчика.