问题描述
我正在尝试创建此API端点,该端点将接受JSON有效负载并根据提供的因素及其等级计算报价。
我的实体中的评分约为
- “年龄”
- “邮政编码”
- “ ABI代码”
这些Agerating,Postcoderating和Abirating实体实现ratingFactorInterface来强制实施getratingFactor()
方法。
QuoteController似乎违反了“单一职责”和“开放/关闭”设计原则,因为诸如“年龄”,“邮政编码”之类的因素可以改变-可以添加额外的因素,也可以不使用其中之一。 / p>
我当时想也许可以在依赖项注入容器中指定评级因子,但似乎找不到一个很好的例子,特别是在依赖于其他服务(例如依赖于AbiCoderating的依赖项)的情况下,如何工作使用接受汽车注册号的第三方API返回的ABI代码。
如何重构控制器和服务,以免违反单一职责和开放/封闭设计原则?
POST JSON有效负载示例
{
"age": 20,"postcode": "PE3 8AF","regNo": "PJ63 LXR"
}
QuoteController
<?PHP
namespace App\Controller;
use App\Repository\AbiCoderatingRepository;
use App\Repository\AgeratingRepository;
use App\Repository\PostcoderatingRepository;
use App\Service\AbiCodeLookup;
use App\Service\QuoteCalculator;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
/**
* Class QuoteController
* @package App\Controller
*/
class QuoteController extends AbstractController
{
/**
* @Route("/",name="quote")
*
* @param Request $request
* @param AbiCoderatingRepository $abiCoderatingRepository
* @param AgeratingRepository $ageratingRepository
* @param PostcoderatingRepository $postcoderatingRepository
* @return JsonResponse
*/
public function index(Request $request,AbiCoderatingRepository $abiCoderatingRepository,AgeratingRepository $ageratingRepository,PostcoderatingRepository $postcoderatingRepository)
{
try{
$request = $this->transformJsonBody($request);
/**
* Quoting engine Could be used with a different set of rating factors!
* Meaning age,postcode and regNo maybe not be required,some other rating factors might be introduced
* How to make controller to accept rating factors dynamically?
*/
if (!$request || !$request->get('age') || !$request->request->get('postcode') || !$request->get('regNo')){
throw new \Exception();
}
/**
* call to a third party API to look up the vehicle registration number and return an ABI code
* this is only required if Abirating is used with the quoting engine
*/
$abiCode = AbiCodeLookup::getAbiCode($request->get('regNo'));
/**
* $abiCode is only required if postcoderating is used by quoting engine
*/
$ratingFactors[] = $abiCoderatingRepository->findOneBy(["abiCode"=>$abiCode]);
$ratingFactors[] = $ageratingRepository->findOneBy(["age"=>$request->get("age")]);
/**
* $area is only required if postcoderating is used by quoting engine
*/
$area = substr($request->get("postcode"),3);
$ratingFactors[] = $postcoderatingRepository->findByPostcodeArea($area);
$premiumTotal = QuoteCalculator::calculate($ratingFactors);
$data = [
'status' => 200,'success' => "Quote created successfully",'quote' => $premiumTotal
];
return new JsonResponse($data,200);
}catch (\Exception $e){
$data = [
'status' => 422,'errors' => "Data is not valid",];
return new JsonResponse($data,422);
}
}
/**
* @param Request $request
* @return Request
*/
protected function transformJsonBody(Request $request)
{
$data = json_decode($request->getContent(),true);
if ($data === null) {
return $request;
}
$request->request->replace($data);
return $request;
}
}
AbiCoderating
<?PHP
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use App\Repository\AbiCoderatingRepository;
use Doctrine\ORM\Mapping as ORM;
/**
* @ApiResource(
* collectionoperations={"get","post"},* itemOperations={"get"}
* )
* @ORM\Entity(repositoryClass=AbiCoderatingRepository::class)
*/
class AbiCoderating implements ratingFactorInterface
{
/**
* @ORM\Id
* @ORM\Column(type="string",length=10)
*/
private $abiCode;
/**
* @ORM\Column(type="decimal",precision=10,scale=2,nullable=true)
*/
private $ratingFactor;
public function getAbiCode(): ?string
{
return $this->abiCode;
}
public function setAbiCode(string $abiCode): self
{
$this->abiCode = $abiCode;
return $this;
}
public function getratingFactor(): ?float
{
return $this->ratingFactor;
}
public function setratingFactor(?float $ratingFactor): self
{
$this->ratingFactor = $ratingFactor;
return $this;
}
}
Agerating
<?PHP
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use App\Repository\AgeratingRepository;
use Doctrine\ORM\Mapping as ORM;
/**
* @ApiResource(
* collectionoperations={"get",* itemOperations={"get"}
* )
* @ORM\Entity(repositoryClass=AgeratingRepository::class)
*/
class Agerating implements ratingFactorInterface
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
*/
private $age;
/**
* @ORM\Column(type="decimal",nullable=true)
*/
private $ratingFactor;
public function getAge(): ?int
{
return $this->age;
}
public function setAge(int $age): self
{
$this->age = $age;
return $this;
}
public function getratingFactor(): ?float
{
return $this->ratingFactor;
}
public function setratingFactor(?float $ratingFactor): self
{
$this->ratingFactor = $ratingFactor;
return $this;
}
}
Postcoderating
<?PHP
namespace App\Entity;
use App\Repository\PostcoderatingRepository;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity(repositoryClass=PostcoderatingRepository::class)
*/
class Postcoderating implements ratingFactorInterface
{
/**
* @ORM\Id
* @ORM\Column(type="string",length=4)
*/
private $postcodeArea;
/**
* @ORM\Column(type="decimal",nullable=true)
*/
private $ratingFactor;
public function getPostcodeArea(): ?string
{
return $this->postcodeArea;
}
public function setPostcodeArea(string $postcodeArea): self
{
$this->postcodeArea = $postcodeArea;
return $this;
}
public function getratingFactor(): ?float
{
return $this->ratingFactor;
}
public function setratingFactor(?float $ratingFactor): self
{
$this->ratingFactor = $ratingFactor;
return $this;
}
}
ratingFactorInterface
<?PHP
namespace App\Entity;
interface ratingFactorInterface
{
/**
* @return float|null
*/
public function getratingFactor(): ?float;
}
AbiCoderatingRepository
<?PHP
namespace App\Repository;
use App\Entity\AbiCoderating;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @method AbiCoderating|null find($id,$lockMode = null,$lockVersion = null)
* @method AbiCoderating|null findOneBy(array $criteria,array $orderBy = null)
* @method AbiCoderating[] findAll()
* @method AbiCoderating[] findBy(array $criteria,array $orderBy = null,$limit = null,$offset = null)
*/
class AbiCoderatingRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry,AbiCoderating::class);
}
}
AgeratingRepository
<?PHP
namespace App\Repository;
use App\Entity\Agerating;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @method Agerating|null find($id,$lockVersion = null)
* @method Agerating|null findOneBy(array $criteria,array $orderBy = null)
* @method Agerating[] findAll()
* @method Agerating[] findBy(array $criteria,$offset = null)
*/
class AgeratingRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry,Agerating::class);
}
}
PostcoderatingRepository
<?PHP
namespace App\Repository;
use App\Entity\Postcoderating;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @method Postcoderating|null find($id,$lockVersion = null)
* @method Postcoderating|null findOneBy(array $criteria,array $orderBy = null)
* @method Postcoderating[] findAll()
* @method Postcoderating[] findBy(array $criteria,$offset = null)
*/
class PostcoderatingRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry,Postcoderating::class);
}
/**
* @return Postcoderating Returns Postcoderating objects based on area
*/
public function findByPostcodeArea($area): ?Postcoderating
{
return $this->findOneBy(["postcodeArea"=>$area]);
}
}
AbiCodeLookup
<?PHP
namespace App\Service;
class AbiCodeLookup
{
public static function getAbiCode(string $regNumber){
/**
* create a request to third party api which would return abi code
* How to configure this service to be used only with regNo factor
*/
return "22529902";
}
}
QuoteCalculator
<?PHP
namespace App\Service;
use App\Entity\ratingFactorInterface;
/**
* Class QuoteCalculator
*/
class QuoteCalculator
{
/**
* @param array $ratingFactors
* @return float
*/
public static function calculate(array $ratingFactors): float
{
$premiumTotal = 500;
foreach ($ratingFactors as $ratingFactor){
$premiumTotal = $premiumTotal * ($ratingFactor instanceof ratingFactorInterface ? $ratingFactor->getratingFactor() : 1);
}
return $premiumTotal ;
}
}
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)