vendor/pimcore/customer-management-framework-bundle/src/SegmentManager/DefaultSegmentManager.php line 164

Open in your IDE?
  1. <?php
  2. /**
  3.  * Pimcore
  4.  *
  5.  * This source file is available under two different licenses:
  6.  * - GNU General Public License version 3 (GPLv3)
  7.  * - Pimcore Commercial License (PCL)
  8.  * Full copyright and license information is available in
  9.  * LICENSE.md which is distributed with this source code.
  10.  *
  11.  *  @copyright  Copyright (c) Pimcore GmbH (http://www.pimcore.org)
  12.  *  @license    http://www.pimcore.org/license     GPLv3 and PCL
  13.  */
  14. namespace CustomerManagementFrameworkBundle\SegmentManager;
  15. use CustomerManagementFrameworkBundle\CustomerProvider\CustomerProviderInterface;
  16. use CustomerManagementFrameworkBundle\CustomerSaveManager\CustomerSaveManagerInterface;
  17. use CustomerManagementFrameworkBundle\Helper\Objects;
  18. use CustomerManagementFrameworkBundle\Model\CustomerInterface;
  19. use CustomerManagementFrameworkBundle\Model\CustomerSegmentInterface;
  20. use CustomerManagementFrameworkBundle\SegmentAssignment\StoredFunctions\StoredFunctionsInterface;
  21. use CustomerManagementFrameworkBundle\SegmentAssignment\TypeMapper\TypeMapperInterface;
  22. use CustomerManagementFrameworkBundle\SegmentBuilder\SegmentBuilderInterface;
  23. use CustomerManagementFrameworkBundle\SegmentManager\SegmentExtractor\SegmentExtractorInterface;
  24. use CustomerManagementFrameworkBundle\Traits\LoggerAware;
  25. use Pimcore\Model\DataObject\Concrete;
  26. use Pimcore\Model\DataObject\CustomerSegment;
  27. use Pimcore\Model\DataObject\CustomerSegmentGroup;
  28. use Pimcore\Model\DataObject\Folder;
  29. use Pimcore\Model\DataObject\Service;
  30. use Pimcore\Model\Element\ElementInterface;
  31. use Pimcore\Model\Tool\Targeting\TargetGroup;
  32. class DefaultSegmentManager implements SegmentManagerInterface
  33. {
  34.     use LoggerAware;
  35.     /**
  36.      * @var string|\Pimcore\Model\DataObject\Folder
  37.      */
  38.     protected $segmentFolderCalculated;
  39.     /**
  40.      * @var string|\Pimcore\Model\DataObject\Folder
  41.      */
  42.     protected $segmentFolderManual;
  43.     /**
  44.      * @var CustomerSaveManagerInterface
  45.      */
  46.     protected $customerSaveManager;
  47.     /**
  48.      * @var SegmentBuilderInterface[]
  49.      */
  50.     protected $segmentBuilders = [];
  51.     /**
  52.      * @var CustomerProviderInterface
  53.      */
  54.     protected $customerProvider;
  55.     /**
  56.      * maps actual types of elements implementing ElementInterface to type strings used with db tables
  57.      *
  58.      * @var TypeMapperInterface
  59.      */
  60.     protected $typeMapper null;
  61.     /**
  62.      * @var StoredFunctionsInterface
  63.      */
  64.     protected $storedFunctions null;
  65.     /**
  66.      * @param string|\Pimcore\Model\DataObject\Folder $segmentFolderCalculated
  67.      * @param string|\Pimcore\Model\DataObject\Folder $segmentFolderManual
  68.      * @param CustomerSaveManagerInterface $customerSaveManager
  69.      * @param CustomerProviderInterface $customerProvider
  70.      * @param TypeMapperInterface $typeMapper
  71.      * @param StoredFunctionsInterface $storedFunctions
  72.      */
  73.     public function __construct($segmentFolderCalculated$segmentFolderManualCustomerSaveManagerInterface $customerSaveManagerCustomerProviderInterface $customerProviderTypeMapperInterface $typeMapperStoredFunctionsInterface $storedFunctions)
  74.     {
  75.         $this->segmentFolderCalculated $segmentFolderCalculated;
  76.         $this->segmentFolderManual $segmentFolderManual;
  77.         $this->customerSaveManager $customerSaveManager;
  78.         $this->customerProvider $customerProvider;
  79.         $this->setTypeMapper($typeMapper);
  80.         $this->setStoredFunctions($storedFunctions);
  81.     }
  82.     /**
  83.      * @return TypeMapperInterface
  84.      */
  85.     public function getTypeMapper(): TypeMapperInterface
  86.     {
  87.         return $this->typeMapper;
  88.     }
  89.     /**
  90.      * @param TypeMapperInterface $typeMapper
  91.      */
  92.     public function setTypeMapper(TypeMapperInterface $typeMapper)
  93.     {
  94.         $this->typeMapper $typeMapper;
  95.     }
  96.     /**
  97.      * @return StoredFunctionsInterface
  98.      */
  99.     public function getStoredFunctions(): StoredFunctionsInterface
  100.     {
  101.         return $this->storedFunctions;
  102.     }
  103.     /**
  104.      * @param StoredFunctionsInterface $storedFunctions
  105.      */
  106.     public function setStoredFunctions(StoredFunctionsInterface $storedFunctions)
  107.     {
  108.         $this->storedFunctions $storedFunctions;
  109.     }
  110.     /**
  111.      * @inheritdoc
  112.      */
  113.     public function getSegmentById($id)
  114.     {
  115.         return CustomerSegment::getById($id);
  116.     }
  117.     /**
  118.      * @inheritdoc
  119.      */
  120.     public function getSegmentGroupById($id)
  121.     {
  122.         return CustomerSegmentGroup::getById($id);
  123.     }
  124.     /**
  125.      * @inheritdoc
  126.      */
  127.     public function getSegmentsForElement(ElementInterface $element): array
  128.     {
  129.         $id $element->getId();
  130.         $type $this->getTypeMapper()->getTypeStringByObject($element);
  131.         return $this->getSegmentsForElementId($id$type);
  132.     }
  133.     /**
  134.      * @inheritdoc
  135.      */
  136.     public function getSegmentsForElementId(string $idstring $type): array
  137.     {
  138.         $segmentIds $this->getStoredFunctions()->retrieve($id$type);
  139.         $segments array_map(function (string $id) {
  140.             return CustomerSegment::getById($id);
  141.         }, $segmentIds);
  142.         return array_filter($segments);
  143.     }
  144.     /**
  145.      * @inheritdoc
  146.      */
  147.     public function getCustomersBySegmentIds(array $segmentIds$conditionMode self::CONDITION_AND)
  148.     {
  149.         $list $this->customerProvider->getList();
  150.         $list->setUnpublished(false);
  151.         $conditions = [];
  152.         foreach ($segmentIds as $segmentId) {
  153.             $conditions[] = '(o_id in (select distinct src_id from object_relations_' $this->customerProvider->getCustomerClassId() . ' where (fieldname = "manualSegments" or fieldname = "calculatedSegments") and dest_id = ' intval($segmentId) . '))';
  154.         }
  155.         if (sizeof($conditions)) {
  156.             $list->setCondition('(' implode(' ' $conditionMode ' '$conditions) . ')');
  157.         }
  158.         return $list;
  159.     }
  160.     /**
  161.      * @inheritdoc
  162.      */
  163.     public function getSegments(array $params = [])
  164.     {
  165.         /**
  166.          * @var CustomerSegment\Listing $list;
  167.          */
  168.         $list CustomerSegment::getList();
  169.         $list->setUnpublished(false);
  170.         return $list;
  171.     }
  172.     /**
  173.      * @inheritdoc
  174.      */
  175.     public function getSegmentGroups()
  176.     {
  177.         /**
  178.          * @var CustomerSegmentGroup\Listing $list;
  179.          */
  180.         $list CustomerSegmentGroup::getList();
  181.         $list->setUnpublished(false);
  182.         return $list;
  183.     }
  184.     /**
  185.      * @inheritdoc
  186.      */
  187.     public function getSegmentsFolder($calculated true)
  188.     {
  189.         $folder $calculated $this->segmentFolderCalculated $this->segmentFolderManual;
  190.         if ($folder instanceof Folder) {
  191.             return $folder;
  192.         }
  193.         $folder Service::createFolderByPath($folder);
  194.         if ($calculated) {
  195.             $this->segmentFolderCalculated $folder;
  196.         } else {
  197.             $this->segmentFolderManual $folder;
  198.         }
  199.         return $folder;
  200.     }
  201.     /**
  202.      * Needed for resetting the segments folder between tests
  203.      *
  204.      * @internal
  205.      */
  206.     public function resetSegmentsFolder(): void
  207.     {
  208.         if ($this->segmentFolderCalculated instanceof Folder) {
  209.             $this->segmentFolderCalculated $this->segmentFolderCalculated->getFullPath();
  210.         }
  211.         if ($this->segmentFolderManual instanceof Folder) {
  212.             $this->segmentFolderManual $this->segmentFolderManual->getFullPath();
  213.         }
  214.     }
  215.     /**
  216.      * @inheritdoc
  217.      */
  218.     public function getSegmentByReference($segmentReferenceCustomerSegmentGroup $segmentGroup null$calculated null)
  219.     {
  220.         $list $this->getSegments()
  221.             ->setUnpublished(true)
  222.             ->addConditionParam('reference = ?'$segmentReference);
  223.         if (!is_null($calculated)) {
  224.             if ($calculated) {
  225.                 $list->addConditionParam('calculated = 1');
  226.             } else {
  227.                 $list->addConditionParam('(calculated is null or calculated = 0)');
  228.             }
  229.         }
  230.         if ($segmentGroup) {
  231.             $list->addConditionParam('group__id = ?'$segmentGroup->getId());
  232.         }
  233.         if ($list->count() > 1) {
  234.             throw new \RuntimeException(
  235.                 sprintf('Ambiguous results: found more than one segment with reference %s'$segmentReference)
  236.             );
  237.         }
  238.         return $list->current();
  239.     }
  240.     /**
  241.      * @inheritdoc
  242.      */
  243.     public function createSegment(
  244.         $segmentName,
  245.         $segmentGroup,
  246.         $segmentReference null,
  247.         $calculated true,
  248.         $subFolder null
  249.     ) {
  250.         if ($segmentGroup instanceof CustomerSegmentGroup && $segmentGroup->getCalculated() != $calculated) {
  251.             throw new \RuntimeException(
  252.                 sprintf(
  253.                     "it's not possible to create a %s segment within a %s segment group",
  254.                     $calculated 'calculated' 'manual',
  255.                     $calculated 'manual' 'calculated'
  256.                 )
  257.             );
  258.         }
  259.         $segmentGroup self::createSegmentGroup($segmentGroup$segmentGroup$calculated);
  260.         if ($segment $this->getSegmentByReference($segmentReference$segmentGroup)) {
  261.             return $segment;
  262.         }
  263.         $parent $segmentGroup;
  264.         if (!is_null($subFolder)) {
  265.             $subFolder explode('/'$subFolder);
  266.             $folder = [];
  267.             foreach ($subFolder as $f) {
  268.                 if ($f Objects::getValidKey($f)) {
  269.                     $folder[] = $f;
  270.                 }
  271.             }
  272.             $subFolder implode('/'$folder);
  273.             if ($subFolder) {
  274.                 $fullPath str_replace('//''/'$segmentGroup->getFullPath().'/'.$subFolder);
  275.                 $parent Service::createFolderByPath($fullPath);
  276.             }
  277.         }
  278.         $segment = new CustomerSegment();
  279.         $segment->setParent($parent);
  280.         $segment->setKey(Objects::getValidKey($segmentReference ?: $segmentName));
  281.         $segment->setName($segmentName);
  282.         $segment->setReference($segmentReference);
  283.         $segment->setPublished(true);
  284.         $segment->setCalculated($calculated);
  285.         $segment->setGroup($segmentGroup);
  286.         Objects::checkObjectKey($segment);
  287.         $segment->save();
  288.         return $segment;
  289.     }
  290.     /**
  291.      * @inheritdoc
  292.      */
  293.     public function createCalculatedSegment($segmentReference$segmentGroup$segmentName null$subFolder null)
  294.     {
  295.         return $this->createSegment(
  296.             $segmentName ?: $segmentReference,
  297.             $segmentGroup,
  298.             $segmentReference,
  299.             true,
  300.             $subFolder
  301.         );
  302.     }
  303.     /**
  304.      * @inheritdoc
  305.      */
  306.     public function createSegmentGroup(
  307.         $segmentGroupName,
  308.         $segmentGroupReference null,
  309.         $calculated true,
  310.         array $values = []
  311.     ) {
  312.         if ($segmentGroupName instanceof CustomerSegmentGroup) {
  313.             return $segmentGroupName;
  314.         }
  315.         if ($segmentGroup $this->getSegmentGroupByReference($segmentGroupReference$calculated)) {
  316.             return $segmentGroup;
  317.         }
  318.         $segmentGroup = new CustomerSegmentGroup();
  319.         $segmentGroup->setParent($this->getSegmentsFolder($calculated));
  320.         $segmentGroup->setPublished(true);
  321.         $segmentGroup->setKey(Objects::getValidKey($segmentGroupReference ?: $segmentGroupName));
  322.         $segmentGroup->setCalculated($calculated);
  323.         $segmentGroup->setName($segmentGroupName);
  324.         $segmentGroup->setReference($segmentGroupReference);
  325.         $segmentGroup->setValues($values);
  326.         Objects::checkObjectKey($segmentGroup);
  327.         $segmentGroup->save();
  328.         return $segmentGroup;
  329.     }
  330.     /**
  331.      * @inheritdoc
  332.      */
  333.     public function updateSegmentGroup(CustomerSegmentGroup $segmentGroup, array $values = [])
  334.     {
  335.         $currentCalculatedState $segmentGroup->getCalculated();
  336.         $segmentGroup->setValues($values);
  337.         $segmentGroup->setKey($segmentGroup->getReference() ?: $segmentGroup->getName());
  338.         Objects::checkObjectKey($segmentGroup);
  339.         if (isset($values['calculated'])) {
  340.             $newCalculatedState = (bool)$values['calculated'];
  341.             if ($newCalculatedState != $currentCalculatedState) {
  342.                 foreach ($this->getSegmentsFromSegmentGroup($segmentGroup) as $segment) {
  343.                     if ($segment->getCalculated() != $newCalculatedState) {
  344.                         $segment->setCalculated($newCalculatedState);
  345.                         $segment->save();
  346.                     }
  347.                 }
  348.                 $segmentGroup->setParent($this->getSegmentsFolder($newCalculatedState));
  349.             }
  350.         }
  351.         $segmentGroup->save();
  352.     }
  353.     /**
  354.      * @inheritdoc
  355.      */
  356.     public function updateSegment(CustomerSegmentInterface $segment, array $values = [])
  357.     {
  358.         $segment->setValues($values);
  359.         if (!empty($values['group'])) {
  360.             if (!$segmentGroup CustomerSegmentGroup::getById($values['group'])) {
  361.                 throw new \Exception('SegmentGroup with id %s not found'$values['group']);
  362.             }
  363.             $segment->setGroup($segmentGroup);
  364.             $segment->setParent($segmentGroup);
  365.         }
  366.         if (isset($values['calculated']) && $group $segment->getGroup()) {
  367.             if ($group->getCalculated() != (bool)$values['calculated']) {
  368.                 throw new \Exception("calculated state of segment cannot be different then for it's segment group");
  369.             }
  370.         }
  371.         $segment->setKey($segment->getReference() ?: $segment->getName());
  372.         Objects::checkObjectKey($segment);
  373.         $segment->save();
  374.     }
  375.     /**
  376.      * @inheritdoc
  377.      */
  378.     public function getSegmentGroupByReference($segmentGroupReference$calculated)
  379.     {
  380.         if (is_null($segmentGroupReference)) {
  381.             return null;
  382.         }
  383.         $list $this->getSegmentGroups()
  384.             ->setUnpublished(true)
  385.             ->setCondition(
  386.                 'reference = ? and '.($calculated '(calculated = 1)' '(calculated is null or calculated = 0)'),
  387.                 $segmentGroupReference
  388.             );
  389.         if ($list->count() > 1) {
  390.             throw new \RuntimeException(
  391.                 sprintf('Ambiguous results: found more than one segment group with reference %s'$segmentGroupReference)
  392.             );
  393.         }
  394.         return $list->current();
  395.     }
  396.     /**
  397.      * @inheritdoc
  398.      */
  399.     public function getSegmentsFromSegmentGroup(CustomerSegmentGroup $segmentGroup, array $ignoreSegments = [])
  400.     {
  401.         $list $this->getSegments()
  402.             ->addConditionParam('group__id = ?'$segmentGroup->getId())
  403.             ->setOrderKey('name');
  404.         $ignoreIds Objects::getIdsFromArray($ignoreSegments);
  405.         if (sizeof($ignoreIds)) {
  406.             $list->addConditionParam('o_id not in(' implode(','$ignoreIds) . ')');
  407.         }
  408.         $result $list->load();
  409.         return $result ?: [];
  410.     }
  411.     /**
  412.      * @inheritdoc
  413.      */
  414.     public function preSegmentUpdate(CustomerSegmentInterface $segment)
  415.     {
  416.         $this->checkAndUpdateTargetGroupConnection($segment);
  417.         $this->updateGroupRelation($segment);
  418.     }
  419.     /**
  420.      * @param CustomerSegmentInterface $segment
  421.      */
  422.     protected function checkAndUpdateTargetGroupConnection(CustomerSegmentInterface $segment)
  423.     {
  424.         //check connection to target groups
  425.         if ($segment->getUseAsTargetGroup() && (empty($segment->getTargetGroup()) || empty(TargetGroup::getById($segment->getTargetGroup())))) {
  426.             $targetGroup = new TargetGroup();
  427.             $targetGroup->setName($segment->getName());
  428.             $targetGroup->setActive(true);
  429.             $targetGroup->save();
  430.             $segment->setTargetGroup($targetGroup->getId());
  431.         }
  432.     }
  433.     /**
  434.      * @inheritdoc
  435.      */
  436.     public function postSegmentDelete(CustomerSegmentInterface $segment)
  437.     {
  438.         if ($segment->getUseAsTargetGroup() && !empty($segment->getTargetGroup()) && !empty(TargetGroup::getById($segment->getTargetGroup()))) {
  439.             $targetGroup TargetGroup::getById($segment->getTargetGroup());
  440.             $targetGroup->delete();
  441.         }
  442.     }
  443.     /**
  444.      * @param CustomerSegmentInterface $segment
  445.      */
  446.     protected function updateGroupRelation(CustomerSegmentInterface $segment)
  447.     {
  448.         if ($segment instanceof Concrete) {
  449.             $parent $segment;
  450.             $segment->setGroup(null);
  451.             while ($parent) {
  452.                 $parent $parent->getParent();
  453.                 if ($parent instanceof CustomerSegmentGroup) {
  454.                     $segment->setGroup($parent);
  455.                     return;
  456.                 }
  457.             }
  458.         }
  459.     }
  460.     /**
  461.      * @inheritdoc
  462.      */
  463.     public function customerHasSegment(CustomerInterface $customerCustomerSegmentInterface $segment)
  464.     {
  465.         foreach ($customer->getAllSegments() as $s) {
  466.             if ($s->getId() == $segment->getId()) {
  467.                 return true;
  468.             }
  469.         }
  470.         return false;
  471.     }
  472.     /**
  473.      * @inheritdoc
  474.      */
  475.     public function getCalculatedSegmentsFromCustomer(CustomerInterface $customer)
  476.     {
  477.         return $this->getSegmentExtractor()->getCalculatedSegmentsFromCustomer($customer);
  478.     }
  479.     /**
  480.      * @inheritdoc
  481.      */
  482.     public function getManualSegmentsFromCustomer(CustomerInterface $customer)
  483.     {
  484.         return $this->getSegmentExtractor()->getManualSegmentsFromCustomer($customer);
  485.     }
  486.     /**
  487.      * @inheritdoc
  488.      */
  489.     public function getSegmentExtractor(): SegmentExtractorInterface
  490.     {
  491.         return \Pimcore::getContainer()->get(SegmentExtractorInterface::class);
  492.     }
  493.     /**
  494.      * @inheritdoc
  495.      */
  496.     public function getCustomersSegmentsFromGroup(CustomerInterface $customer$group)
  497.     {
  498.         if (!$group instanceof CustomerSegmentGroup) {
  499.             $group $this->getSegmentGroupByReference($grouptrue);
  500.         }
  501.         if (!$group instanceof CustomerSegmentGroup) {
  502.             return [];
  503.         }
  504.         if (!$segments $customer->getAllSegments()) {
  505.             return [];
  506.         }
  507.         $result = [];
  508.         foreach ($segments as $segment) {
  509.             if ($segment->getGroup() && $segment->getGroup()->getId() == $group->getId()) {
  510.                 $result[] = $segment;
  511.             }
  512.         }
  513.         return $result;
  514.     }
  515.     /**
  516.      * @inheritdoc
  517.      */
  518.     public function mergeSegments(
  519.         CustomerInterface $customer,
  520.         array $addSegments,
  521.         array $deleteSegments = [],
  522.         $hintForNotes null,
  523.         $segmentCreatedTimestamp null,
  524.         $segmentApplicationCounter null
  525.     ) {
  526.         \Pimcore::getContainer()->get('cmf.segment_manager.segment_merger')->mergeSegments(
  527.             $customer,
  528.             $addSegments,
  529.             $deleteSegments,
  530.             $hintForNotes,
  531.             $segmentCreatedTimestamp,
  532.             $segmentApplicationCounter
  533.         );
  534.     }
  535.     /**
  536.      * @inheritdoc
  537.      */
  538.     public function saveMergedSegments(CustomerInterface $customer)
  539.     {
  540.         \Pimcore::getContainer()->get('cmf.segment_manager.segment_merger')->saveMergedSegments($customer);
  541.     }
  542.     public function addSegmentBuilder(SegmentBuilderInterface $segmentBuilder)
  543.     {
  544.         $this->segmentBuilders[] = $segmentBuilder;
  545.     }
  546.     /**
  547.      * @inheritdoc
  548.      */
  549.     public function getSegmentBuilders()
  550.     {
  551.         return $this->segmentBuilders;
  552.     }
  553. }