Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add explicit mapping between product and reviews, and between product and attributes #15221

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions UPGRADE-1.13.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,3 +126,8 @@
1. Due to optimizations of the Order's grid the `Sylius\Component\Core\Repository\OrderRepositoryInterface::createSearchListQueryBuilder` method bas been deprecated and replaced by `Sylius\Component\Core\Repository\OrderRepositoryInterface::createCriteriaAwareSearchListQueryBuilder`.
Also `Sylius\Component\Core\Repository\OrderRepositoryInterface::createByCustomerIdQueryBuilder` has been deprecated and replaced by `Sylius\Component\Core\Repository\OrderRepositoryInterface::createByCustomerIdCriteriaAwareQueryBuilder` for the same reason. Both changes affect
`sylius_admin_order` and `sylius_admin_customer_order` grids configuration.

1. We have explicitly added relationships between product and reviews and between product and attributes in XML mappings.
Because of that, the subscribers `Sylius\Bundle\AttributeBundle\Doctrine\ORM\Subscriber\LoadMetadataSubscriber`
and `Sylius\Bundle\ReviewBundle\Doctrine\ORM\Subscriber\LoadMetadataSubscriber` have changed so that it does not add
a relationship if one already exists. If you have overwritten or decorated it, there may be a need to update it.
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ private function mapSubjectOnAttributeValue(
ClassMetadataInfo $metadata,
ClassMetadataFactory $metadataFactory,
): void {
if ($metadata->hasAssociation('subject')) {
return;
}

/** @var ClassMetadataInfo $targetEntityMetadata */
$targetEntityMetadata = $metadataFactory->getMetadataFor($subjectClass);
$subjectMapping = [
Expand All @@ -64,14 +68,18 @@ private function mapSubjectOnAttributeValue(
]],
];

$this->mapManyToOne($metadata, $subjectMapping);
$metadata->mapManyToOne($subjectMapping);
}

private function mapAttributeOnAttributeValue(
string $attributeClass,
ClassMetadataInfo $metadata,
ClassMetadataFactory $metadataFactory,
): void {
if ($metadata->hasAssociation('attribute')) {
return;
}

/** @var ClassMetadataInfo $attributeMetadata */
$attributeMetadata = $metadataFactory->getMetadataFor($attributeClass);
$attributeMapping = [
Expand All @@ -84,11 +92,6 @@ private function mapAttributeOnAttributeValue(
]],
];

$this->mapManyToOne($metadata, $attributeMapping);
}

private function mapManyToOne(ClassMetadataInfo $metadata, array $subjectMapping): void
{
$metadata->mapManyToOne($subjectMapping);
$metadata->mapManyToOne($attributeMapping);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,30 +58,14 @@ function it_subscribes_load_class_metadata_event(): void
$this->getSubscribedEvents()->shouldReturn(['loadClassMetadata']);
}

function it_does_not_add_a_many_to_one_mapping_if_the_class_is_not_a_configured_attribute_value_model(
LoadClassMetadataEventArgs $eventArgs,
ClassMetadataInfo $metadata,
EntityManager $entityManager,
ClassMetadataFactory $classMetadataFactory,
): void {
$eventArgs->getEntityManager()->willReturn($entityManager);
$entityManager->getMetadataFactory()->willReturn($classMetadataFactory);

$eventArgs->getClassMetadata()->willReturn($metadata);
$metadata->getName()->willReturn('KeepMoving\ThisClass\DoesNot\Concern\You');

$metadata->mapManyToOne(Argument::any())->shouldNotBeCalled();

$this->loadClassMetadata($eventArgs);
}

function it_maps_many_to_one_associations_from_the_attribute_value_model_to_the_subject_model_and_the_attribute_model(
LoadClassMetadataEventArgs $eventArgs,
ClassMetadataInfo $metadata,
EntityManager $entityManager,
ClassMetadataFactory $classMetadataFactory,
ClassMetadataInfo $classMetadataInfo,
): void {
$eventArgs->getClassMetadata()->willReturn($metadata);
$eventArgs->getEntityManager()->willReturn($entityManager);
$entityManager->getMetadataFactory()->willReturn($classMetadataFactory);
$classMetadataInfo->fieldMappings = [
Expand All @@ -92,9 +76,9 @@ function it_maps_many_to_one_associations_from_the_attribute_value_model_to_the_
$classMetadataFactory->getMetadataFor('Some\App\Product\Entity\Product')->willReturn($classMetadataInfo);
$classMetadataFactory->getMetadataFor('Some\App\Product\Entity\Attribute')->willReturn($classMetadataInfo);

$eventArgs->getClassMetadata()->willReturn($metadata);
$eventArgs->getClassMetadata()->willReturn($metadata);
$metadata->getName()->willReturn('Some\App\Product\Entity\AttributeValue');
$metadata->hasAssociation('subject')->willReturn(false);
$metadata->hasAssociation('attribute')->willReturn(false);

$subjectMapping = [
'fieldName' => 'subject',
Expand Down Expand Up @@ -124,6 +108,42 @@ function it_maps_many_to_one_associations_from_the_attribute_value_model_to_the_
$this->loadClassMetadata($eventArgs);
}

function it_does_not_map_relations_for_attribute_value_model_if_the_relations_already_exist(
LoadClassMetadataEventArgs $eventArgs,
ClassMetadataInfo $metadata,
EntityManager $entityManager,
ClassMetadataFactory $classMetadataFactory,
): void {
$eventArgs->getClassMetadata()->willReturn($metadata);
$eventArgs->getEntityManager()->willReturn($entityManager);
$entityManager->getMetadataFactory()->willReturn($classMetadataFactory);

$metadata->getName()->willReturn('Some\App\Product\Entity\AttributeValue');
$metadata->hasAssociation('subject')->willReturn(true);
$metadata->hasAssociation('attribute')->willReturn(true);

$metadata->mapManyToOne(Argument::any())->shouldNotBeCalled();

$this->loadClassMetadata($eventArgs);
}

function it_does_not_add_a_many_to_one_mapping_if_the_class_is_not_a_configured_attribute_value_model(
LoadClassMetadataEventArgs $eventArgs,
ClassMetadataInfo $metadata,
EntityManager $entityManager,
ClassMetadataFactory $classMetadataFactory,
): void {
$eventArgs->getEntityManager()->willReturn($entityManager);
$entityManager->getMetadataFactory()->willReturn($classMetadataFactory);

$eventArgs->getClassMetadata()->willReturn($metadata);
$metadata->getName()->willReturn('KeepMoving\ThisClass\DoesNot\Concern\You');

$metadata->mapManyToOne(Argument::any())->shouldNotBeCalled();

$this->loadClassMetadata($eventArgs);
}

function it_does_not_add_values_one_to_many_mapping_if_the_class_is_not_a_configured_attribute_model(
LoadClassMetadataEventArgs $eventArgs,
ClassMetadataInfo $metadata,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@
</cascade>
</one-to-many>

<one-to-many field="reviews" target-entity="Sylius\Component\Review\Model\ReviewInterface" mapped-by="reviewSubject">
<cascade>
<cascade-all />
</cascade>
</one-to-many>

<many-to-many field="channels" target-entity="Sylius\Component\Channel\Model\ChannelInterface">
<order-by>
<order-by-field name="id" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,17 @@

<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping">

<mapped-superclass name="Sylius\Component\Core\Model\ProductReview" table="sylius_product_review" />
<mapped-superclass name="Sylius\Component\Core\Model\ProductReview" table="sylius_product_review">
<many-to-one field="reviewSubject" target-entity="Sylius\Component\Product\Model\ProductInterface" inversed-by="reviews">
<join-column name="product_id" referenced-column-name="id" nullable="false" on-delete="CASCADE" />
</many-to-one>

<many-to-one field="author" target-entity="Sylius\Component\Customer\Model\CustomerInterface">
<join-column name="author_id" referenced-column-name="id" nullable="false" on-delete="CASCADE" />
<cascade>
<cascade-persist />
</cascade>
</many-to-one>
</mapped-superclass>

</doctrine-mapping>
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">

<mapped-superclass name="Sylius\Component\Product\Model\ProductAttributeValue" table="sylius_product_attribute_value" />
<mapped-superclass name="Sylius\Component\Product\Model\ProductAttributeValue" table="sylius_product_attribute_value">
<many-to-one field="subject" target-entity="Sylius\Component\Product\Model\ProductInterface" inversed-by="attributes">
<join-column name="product_id" referenced-column-name="id" nullable="false" on-delete="CASCADE" />
</many-to-one>

<many-to-one field="attribute" target-entity="Sylius\Component\Attribute\Model\AttributeInterface">
<join-column name="attribute_id" referenced-column-name="id" nullable="false" />
</many-to-one>
</mapped-superclass>

</doctrine-mapping>
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,22 @@ public function loadClassMetadata(LoadClassMetadataEventArgs $eventArguments): v

foreach ($this->subjects as $subject => $class) {
if ($class['review']['classes']['model'] === $metadata->getName()) {
$reviewableEntity = $class['subject'];
$reviewerEntity = $class['reviewer']['classes']['model'];
$reviewableEntityMetadata = $metadataFactory->getMetadataFor($reviewableEntity);
$reviewerEntityMetadata = $metadataFactory->getMetadataFor($reviewerEntity);
if (!$metadata->hasAssociation('reviewSubject')) {
$reviewableEntity = $class['subject'];
$reviewableEntityMetadata = $metadataFactory->getMetadataFor($reviewableEntity);

$metadata->mapManyToOne($this->createSubjectMapping($reviewableEntity, $subject, $reviewableEntityMetadata));
$metadata->mapManyToOne($this->createReviewerMapping($reviewerEntity, $reviewerEntityMetadata));
$metadata->mapManyToOne($this->createSubjectMapping($reviewableEntity, $subject, $reviewableEntityMetadata));
}

if (!$metadata->hasAssociation('author')) {
$reviewerEntity = $class['reviewer']['classes']['model'];
$reviewerEntityMetadata = $metadataFactory->getMetadataFor($reviewerEntity);

$metadata->mapManyToOne($this->createReviewerMapping($reviewerEntity, $reviewerEntityMetadata));
}
}

if ($class['subject'] === $metadata->getName()) {
if ($class['subject'] === $metadata->getName() && !$metadata->hasAssociation('reviews')) {
$reviewEntity = $class['review']['classes']['model'];

$metadata->mapOneToMany($this->createReviewsMapping($reviewEntity));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,10 @@ function it_maps_proper_relations_for_review_model(
$classMetadataInfo->fieldMappings = ['id' => ['columnName' => 'id']];
$metadataFactory->getMetadataFor('AcmeBundle\Entity\ReviewableModel')->willReturn($classMetadataInfo);
$metadataFactory->getMetadataFor('AcmeBundle\Entity\ReviewerModel')->willReturn($classMetadataInfo);

$metadata->getName()->willReturn('AcmeBundle\Entity\ReviewModel');
$metadata->hasAssociation('reviewSubject')->willReturn(false);
$metadata->hasAssociation('author')->willReturn(false);

$metadata->mapManyToOne([
'fieldName' => 'reviewSubject',
Expand Down Expand Up @@ -95,6 +98,25 @@ function it_maps_proper_relations_for_review_model(
$this->loadClassMetadata($eventArguments);
}

function it_does_not_map_relation_for_review_model_if_the_relation_already_exists(
ClassMetadataFactory $metadataFactory,
ClassMetadata $metadata,
EntityManager $entityManager,
LoadClassMetadataEventArgs $eventArguments,
): void {
$eventArguments->getClassMetadata()->willReturn($metadata);
$eventArguments->getEntityManager()->willReturn($entityManager);
$entityManager->getMetadataFactory()->willReturn($metadataFactory);

$metadata->getName()->willReturn('AcmeBundle\Entity\ReviewModel');
$metadata->hasAssociation('reviewSubject')->willReturn(true);
$metadata->hasAssociation('author')->willReturn(true);

$metadata->mapManyToOne(Argument::any())->shouldNotBeCalled();

$this->loadClassMetadata($eventArguments);
}

function it_maps_proper_relations_for_reviewable_model(
ClassMetadataFactory $metadataFactory,
ClassMetadata $metadata,
Expand All @@ -104,7 +126,9 @@ function it_maps_proper_relations_for_reviewable_model(
$eventArguments->getClassMetadata()->willReturn($metadata);
$eventArguments->getEntityManager()->willReturn($entityManager);
$entityManager->getMetadataFactory()->willReturn($metadataFactory);

$metadata->getName()->willReturn('AcmeBundle\Entity\ReviewableModel');
$metadata->hasAssociation('reviews')->willReturn(false);

$metadata->mapOneToMany([
'fieldName' => 'reviews',
Expand All @@ -116,7 +140,25 @@ function it_maps_proper_relations_for_reviewable_model(
$this->loadClassMetadata($eventArguments);
}

function it_skips_mapping_configuration_if_metadata_name_is_not_different(
function it_does_not_map_relations_for_reviewable_model_if_the_relation_already_exists(
ClassMetadataFactory $metadataFactory,
ClassMetadata $metadata,
EntityManager $entityManager,
LoadClassMetadataEventArgs $eventArguments,
): void {
$eventArguments->getClassMetadata()->willReturn($metadata);
$eventArguments->getEntityManager()->willReturn($entityManager);
$entityManager->getMetadataFactory()->willReturn($metadataFactory);

$metadata->getName()->willReturn('AcmeBundle\Entity\ReviewableModel');
$metadata->hasAssociation('reviews')->willReturn(true);

$metadata->mapOneToMany(Argument::any())->shouldNotBeCalled();

$this->loadClassMetadata($eventArguments);
}

function it_skips_mapping_configuration_if_metadata_name_is_different(
ClassMetadataFactory $metadataFactory,
ClassMetadata $metadata,
EntityManager $entityManager,
Expand Down