问题描述
我正在使用 Shop API plugin
设置 Sylius 1.8.6需要做的是在用户注册上添加一些字段。通过添加到类 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 }
现在我想要做的是确保在 /register
上调用 api 时添加了这个我一直在关注 documentation 并创建了一个自定义的 Request
,{{1} } 和 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
正如文档所说的覆盖处理程序
扩展处理程序的主要方式是装饰它。这使得在处理程序之前和之后添加功能变得容易。但是,如果要更改处理程序中的逻辑,则需要覆盖它。这可以通过使用相同的服务 ID 注册新的处理程序来完成。
我是这么想的:
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
并且在使用 xdebug 或什至在这三个类中的任何一个中添加一些 {
"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\",\"ketyu603mrk0ksg0s0ssc0wkcw44k8g\",\"$argon2i$v=19$m=65536,t=4,p=1$Z09IeWlJR05nSW40cVYuYg$JIUtgpsZRVnKJoJJZvfN+kX5XRF+U69t8SQzRdZTVOs\",\"argon2i\",null,\"a:1:{i:0;s:9:\\\"ROLE_USER\\\";}\",\"2020-12-22 08:41:08\",102]:\n\nsqlSTATE[23000]: Integrity constraint violation: 1048 Column 'permit' cannot be null"
}
时,代码永远不会通过它们。
我没有正确注册新服务吗?我找不到任何关于此的信息。
感谢任何为我指明正确方向的人。
解决方法
好的,我开始工作了。设置所有服务后,我仍然遇到错误。这是因为我的
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());
}
因此它将返回父类,并且该类不再有处理程序。