У меня есть несколько объектов, которые связаны между собой, такие как McDoublePrice
, CheeseburgerPrice
, BigMacPrice
и т. д., которые имеют общее BurgerPrice
сущность в Сопоставленный суперкласс Конфигурация доктрины.
Как я могу получить доступ к определенной сущности из моего контроллера, действия или обработчика запроса? То есть я хочу, чтобы следующий код работал:
$burgers = array(
'McDoublePrice' => 4,
'CheeseburgerPrice' => 5,
'BigMacPrice' => 6
);
foreach($burgers as $burger => $burgerId)
{
$repository = $this->repositoryFactory->getBurgerRepository($burger);
$entity = $repository->getBurgerEntity($burgerId);
echo $entity->getBurgerPrice(); // total price of current burger
}
Примечание: разные $burgerId
s может представлять различные стили бургера в одном и том же типе бургера. то есть, версия Deluxe, обычная версия и т. д. и могут использовать разные конкретные цены для одного и того же типа ингредиентов. то есть обычная булочка против роскошной булочки может иметь разные $ burderID и разные цены на булочки.
Вопрос: Как мне структурировать мой код?
Должен ли я создать один класс хранилища для каждого из BurgerPrice
юридическое лицо? Это может создать много дополнительных классов и кажется расточительным.
Могу ли я сойти с рук с одним BurgerRepository
класс, который может обрабатывать несколько гамбургеров? Если так, то как бы я изложил это в доктринально-ориентированной манере?
Я ищу пример кода или четкую идею о том, как это сделать. Меня интересует прежде всего Doctrine-ориентированный или Doctrine-рекомендуемый подход к работе с несколькими полиморфными сущностями в конфигурации Mapped Superclass.
Моя конечная цель — иметь возможность запрашивать цену определенных гамбургеров во время выполнения.
Я смотрел в Паттерн Doctrine Entity Repository, и структура репозитория (где я могу создавать собственные имена методов) — это то, что я хотел бы использовать, но пример не показывает, как использовать ее с полиморфными сущностями.
Образцы сущностей
/**
* @ORM\Entity(repositoryClass="BurgerPriceRepository")
* @Table(name="bigmac", indexes={@Index(name="product_id", columns={"product_id"})})
* @Entity
*/
class BigMacPrice extends BurgerPrice
{
/** @var float @Column(name="sauce", type="decimal", precision=6, scale=2, nullable=false) */
private $sauce;
function getBurgerPrice(): float
{
//secret sauce price
return 5 * $this->patty + 3 * $this->bun + $this->sauce;
}
}
/**
* @ORM\Entity(repositoryClass="BurgerPriceRepository")
* @Table(name="mcdouble", indexes={@Index(name="product_id", columns={"product_id"})})
* @Entity
*/
class McDoublePrice extends BurgerPrice
{
function getBurgerPrice(): float
{
//a different price for mcdouble
return 2 * $this->patty + 2 * $this->bun;
}
}
abstract class BurgerPrice
{
/** @var integer @Column(name="id", type="integer", nullable=false) @Id @GeneratedValue(strategy="IDENTITY") */
protected $id;
/** @var integer @Column(name="product_id", type="integer", nullable=false) */
protected $productId;
/** @var float @Column(name="patty", type="decimal", precision=6, scale=2, nullable=false) */
public $patty;
/** @var float @Column(name="bun", type="decimal", precision=6, scale=2, nullable=false) */
public $bun;
/**
* Computes specific product price for a given burger
*
* @return float
*/
abstract function getBurgerPrice(): float;
}
Не уверен, является ли это подходом, рекомендованным доктриной, или нет, но он кажется мне достаточно конгруэнтным, чтобы я мог определять один репозиторий, но используйте разные случаи этого
На каждой полиморфной сущности я могу следовать шаблону Entity Repository Doctrine и указать
@ORM\Entity(repositoryClass="BurgerPriceRepository")
хотя, кажется, не имеет значения, если я не включу эту строку. Может быть, это пригодится в другом месте.
И тогда я могу использовать эти классы:
class BurgerPriceRepositoryFactory
{
/**@var EntityManager*/
private $entityManager;
function __construct(EntityManager $entityManager)
{
$this->entityManager = $entityManager;
}
function getRepository(string $entityName): BurgerPriceRepository
{
return new BurgerPriceRepository(
$this->entityManager,
new ClassMetadata($entityName)
);
}
}
class BurgerPriceRepository extends EntityRepository
{
function getBurgerPriceEntity(int $burgerId): BurgerPrice
{
return $this->getEntityManager()
->getRepository($this->_entityName)
->findOneBy(array(
'productId' => $burgerId
));
}
}
Затем используйте их в моем тесте так:
/** @var ContainerInterface $container */
/* Service-creation time */
$factory = new ProductPricingRepositoryFactoryFactory();
$this->repositoryFactory = $factory($container);
/* Run-time - Big Mac */
$repository = $this->repositoryFactory->getRepository(BigMacPrice::class);
$entity = $repository->getBurgerPriceEntity($bigMacId);
$this->assertEquals(3.57, $entity->getBurgerPrice());
/* Run-time - McDouble*/
$repository = $this->repositoryFactory->getRepository(McDoublePrice::class);
$entity = $repository->getBurgerPriceEntity($mdDoubleId);
$this->assertEquals(1.39, $entity->getBurgerPrice());
Других решений пока нет …