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

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