php - 如何覆盖 sylius shop api 插件上的用户注册
问题描述
我正在使用Shop API 插件设置 Sylius 1.8.6
需要做的是在用户注册上添加一些字段。我设法通过添加到类将它们添加到 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
我一直在关注文档并创建了一个 custom 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%"
正如文档所说的关于覆盖处理程序
扩展处理程序的主要方法是装饰它。这使得在处理程序之前和之后添加功能变得容易。但是,如果要更改处理程序中的逻辑,则需要覆盖它。这可以通过使用相同的服务 ID 注册新的处理程序来完成。
我想到了这一点:
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 [\"test3@example.com\", \"test3@example.com\", 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());
}
所以它将返回父类,并且该类不再有处理程序。
推荐阅读
- python - 即使在中断后程序循环
- swift - 从服务器视频 url 创建的缩略图在滚动 tableview 时不断变化
- r - R:在矩阵中找到最小值
- python - 将数据从 Json 提取到 Id 位于 Key 中的表中
- javascript - cytoscape 的条件样式
- ansible - 使用 ansible-lint 处理全局角色目录
- aframe - 当还使用 Aframe-Vimeo-Component 时,为什么在 Aframe 中添加激光控件不起作用?
- apple-watch - Cutsom 打算开发独立的 Apple Watch 应用程序 watchos6
- python - 间歇性 Firestore 超时锁定整个客户端
- database - 在 mongoDb 中实现一对多关系的最佳方法