├── .github ├── CODE_OF_CONDUCT.md ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ ├── coding-standard.yml │ ├── mess-detector.yml │ └── phpstan.yml ├── .gitignore ├── Api ├── ActionEntityRepositoryInterface.php ├── ActionInterface.php ├── Data │ ├── ActionContextInterface.php │ ├── ActionEntityInterface.php │ ├── ActionEntitySearchResultsInterface.php │ ├── ActionResultInterface.php │ ├── EraseEntityInterface.php │ ├── EraseEntitySearchResultsInterface.php │ ├── ExportEntityInterface.php │ └── ExportEntitySearchResultsInterface.php ├── EraseEntityCheckerInterface.php ├── EraseEntityManagementInterface.php ├── EraseEntityRepositoryInterface.php ├── EraseSalesInformationInterface.php ├── ExportEntityCheckerInterface.php ├── ExportEntityManagementInterface.php └── ExportEntityRepositoryInterface.php ├── Block └── Adminhtml │ ├── Action │ └── Edit │ │ ├── BackButton.php │ │ ├── ExecuteButton.php │ │ └── ResetButton.php │ ├── Config │ └── Form │ │ └── Field │ │ ├── AttributesAnonymizers.php │ │ ├── EraseComponentsProcessors.php │ │ └── Select │ │ └── OptionSourceSelect.php │ ├── Customer │ └── Edit │ │ ├── EraseButton.php │ │ └── ExportButton.php │ └── Order │ └── Edit │ ├── EraseButton.php │ └── ExportButton.php ├── Console └── Command │ ├── EraseCommand.php │ └── ExportCommand.php ├── Controller ├── AbstractAction.php ├── AbstractGuest.php ├── AbstractPrivacy.php ├── Adminhtml │ ├── AbstractAction.php │ ├── Action │ │ ├── Execute.php │ │ ├── Index.php │ │ ├── InlineEdit.php │ │ ├── MassDelete.php │ │ └── NewAction.php │ ├── Guest │ │ ├── Erase.php │ │ └── Export.php │ └── Privacy │ │ ├── Erase.php │ │ ├── Export.php │ │ ├── MassErase.php │ │ └── MassExport.php ├── Guest │ ├── Download.php │ ├── Erase.php │ ├── Export.php │ └── UndoErase.php └── Privacy │ ├── Download.php │ ├── Erase.php │ ├── ErasePost.php │ ├── Export.php │ ├── Settings.php │ └── UndoErase.php ├── Cron ├── EraseEntity.php ├── EraseEntityScheduler.php ├── ExportEntity.php └── ExportEntityExpired.php ├── LICENSE ├── Model ├── Action │ ├── AbstractAction.php │ ├── ActionComposite.php │ ├── ActionFactory.php │ ├── ArgumentReader.php │ ├── Context.php │ ├── ContextBuilder.php │ ├── Erase │ │ ├── ArgumentReader.php │ │ ├── CancelAction.php │ │ ├── CreateAction.php │ │ ├── ExecuteAction.php │ │ └── NotifierActionBundle.php │ ├── Export │ │ ├── ArgumentReader.php │ │ ├── CreateAction.php │ │ ├── CreateOrExportAction.php │ │ ├── ExportAction.php │ │ └── NotifierActionBundle.php │ ├── PerformedBy │ │ ├── AdminUser.php │ │ ├── Console.php │ │ ├── Customer.php │ │ ├── Guest.php │ │ └── NotEmptyStrategy.php │ ├── PerformedByInterface.php │ ├── Result.php │ └── ResultBuilder.php ├── ActionEntity.php ├── ActionEntityBuilder.php ├── ActionEntityRepository.php ├── Archive │ ├── ArchiveManager.php │ └── Zip.php ├── Config.php ├── Config │ ├── Backend │ │ └── Export.php │ ├── PrivacyMessage.php │ └── Source │ │ ├── ActionStates.php │ │ ├── EraseComponents.php │ │ ├── OrderPendingStates.php │ │ ├── VirtualArrayArgumentList.php │ │ ├── VirtualCustomerAttributes.php │ │ └── VirtualEntityAttributes.php ├── Customer │ ├── Anonymize │ │ └── Processor │ │ │ ├── CustomerAddressDataProcessor.php │ │ │ ├── CustomerDataProcessor.php │ │ │ ├── OrderDataProcessor.php │ │ │ ├── QuoteDataProcessor.php │ │ │ └── SubscriberDataProcessor.php │ ├── CustomerChecker.php │ ├── Delete │ │ └── Processor │ │ │ ├── CustomerAddressDataProcessor.php │ │ │ ├── CustomerDataProcessor.php │ │ │ ├── OrderDataProcessor.php │ │ │ ├── QuoteDataProcessor.php │ │ │ └── SubscriberDataProcessor.php │ ├── Erase │ │ └── Notifier.php │ ├── Export │ │ ├── Notifier.php │ │ └── Processor │ │ │ ├── CustomerAddressDataProcessor.php │ │ │ ├── CustomerDataProcessor.php │ │ │ ├── OrderDataProcessor.php │ │ │ ├── QuoteDataProcessor.php │ │ │ └── SubscriberDataProcessor.php │ ├── Notifier │ │ ├── MailSender.php │ │ └── SenderInterface.php │ ├── OrigDataRegistry.php │ └── SourceProvider │ │ └── IdleFilterModifier.php ├── Entity │ ├── DataCollector.php │ ├── DataCollectorGeneric.php │ ├── DataCollectorInterface.php │ ├── Document.php │ ├── DocumentInterface.php │ ├── EntityCheckerFactory.php │ ├── EntityCheckerInterface.php │ ├── EntityIterator.php │ ├── EntityIteratorInterface.php │ ├── EntityTypeList.php │ ├── EntityTypeResolver.php │ ├── EntityValue │ │ ├── CustomAttributesProcessor.php │ │ ├── ExtensibleDataProcessor.php │ │ └── StrategyProcessor.php │ ├── EntityValueProcessorInterface.php │ ├── Metadata.php │ ├── MetadataInterface.php │ ├── SourceProvider │ │ ├── FilterModifier.php │ │ ├── ModifierComposite.php │ │ ├── ModifierFactory.php │ │ ├── ModifierInterface.php │ │ └── NotErasedFilterModifier.php │ └── SourceProviderFactory.php ├── Erase │ ├── EraseEntityScheduler.php │ ├── EraseSalesInformation.php │ ├── NotifierInterface.php │ └── SecureEraseEntityManagement.php ├── EraseEntity.php ├── EraseEntityChecker.php ├── EraseEntityManagement.php ├── EraseEntityRepository.php ├── Export │ ├── ExportEntityData.php │ ├── ExportToFile.php │ └── NotifierInterface.php ├── ExportEntity.php ├── ExportEntityChecker.php ├── ExportEntityManagement.php ├── ExportEntityRepository.php ├── Newsletter │ └── Subscriber.php ├── Notifier │ └── AbstractMailSender.php ├── Order │ ├── Anonymize │ │ └── Processor │ │ │ ├── OrderDataProcessor.php │ │ │ ├── QuoteDataProcessor.php │ │ │ └── SubscriberDataProcessor.php │ ├── Delete │ │ └── Processor │ │ │ ├── OrderDataProcessor.php │ │ │ ├── QuoteDataProcessor.php │ │ │ └── SubscriberDataProcessor.php │ ├── Erase │ │ └── Notifier.php │ ├── Export │ │ ├── Notifier.php │ │ └── Processor │ │ │ ├── AbstractDataProcessor.php │ │ │ ├── OrderDataProcessor.php │ │ │ ├── QuoteDataProcessor.php │ │ │ └── SubscriberDataProcessor.php │ ├── Notifier │ │ ├── MailSender.php │ │ └── SenderInterface.php │ ├── OrderChecker.php │ └── SourceProvider │ │ └── GuestFilterModifier.php └── ResourceModel │ ├── ActionEntity.php │ ├── ActionEntity │ ├── Collection.php │ ├── Validator.php │ └── Validator │ │ └── StateValidator.php │ ├── EraseEntity.php │ ├── EraseEntity │ └── Collection.php │ ├── ExportEntity.php │ └── ExportEntity │ └── Collection.php ├── Observer ├── DeleteExport.php └── InvalidateExport.php ├── README.md ├── Service ├── Anonymize │ ├── Anonymizer │ │ ├── AlphaLower.php │ │ ├── AlphaNum.php │ │ ├── AlphaUpper.php │ │ ├── Anonymous.php │ │ ├── Date.php │ │ ├── Email.php │ │ ├── Entity.php │ │ ├── NullValue.php │ │ ├── Number.php │ │ ├── Phone.php │ │ └── Street.php │ ├── AnonymizerFactory.php │ ├── AnonymizerInterface.php │ ├── Metadata.php │ ├── MetadataInterface.php │ └── Processor │ │ └── Entity │ │ └── EntityValue │ │ ├── Processor.php │ │ └── SmartProcessor.php ├── Erase │ ├── Metadata.php │ ├── MetadataInterface.php │ ├── Processor │ │ └── EraseProcessor.php │ ├── ProcessorFactory.php │ ├── ProcessorInterface.php │ ├── ProcessorResolver │ │ ├── ProcessorResolver.php │ │ └── ProcessorResolverStrategy.php │ ├── ProcessorResolverFactory.php │ └── ProcessorResolverInterface.php └── Export │ ├── Processor │ ├── AbstractDataProcessor.php │ ├── CompositeProcessor.php │ └── Entity │ │ └── EntityValue │ │ ├── DataProcessor.php │ │ └── EntityProcessor.php │ ├── ProcessorFactory.php │ ├── ProcessorInterface.php │ ├── Renderer │ ├── AbstractRenderer.php │ ├── CsvRenderer.php │ ├── HtmlRenderer.php │ ├── HtmlRenderer │ │ ├── LayoutInitiator.php │ │ ├── LayoutInitiatorInterface.php │ │ └── View │ │ │ └── Renderer.php │ ├── JsonRenderer.php │ ├── PdfRenderer.php │ └── XmlRenderer.php │ ├── RendererFactory.php │ └── RendererInterface.php ├── TODO.md ├── ViewModel ├── Cookie │ └── NoticeDataProvider.php └── Customer │ ├── Guest │ ├── EraseDataProvider.php │ └── ExportDataProvider.php │ └── Privacy │ ├── EraseCustomerDataProvider.php │ ├── EraseDataProvider.php │ ├── ExportCustomerDataProvider.php │ ├── ExportDataProvider.php │ └── SettingsDataProvider.php ├── composer.json ├── etc ├── acl.xml ├── adminhtml │ ├── di.xml │ ├── menu.xml │ ├── routes.xml │ ├── system.xml │ └── system │ │ ├── action.xml │ │ ├── cookie.xml │ │ ├── erasure.xml │ │ ├── export.xml │ │ ├── general.xml │ │ └── notification.xml ├── config.xml ├── cron_groups.xml ├── crontab.xml ├── db_schema.xml ├── db_schema_whitelist.json ├── di.xml ├── email_templates.xml ├── events.xml ├── frontend │ ├── di.xml │ └── routes.xml └── module.xml ├── i18n ├── bg_BG.csv ├── da_DK.csv ├── de_DE.csv ├── en_US.csv ├── fr_FR.csv ├── it_IT.csv ├── nl_NL.csv ├── pl_PL.csv └── th_TH.csv ├── registration.php └── view ├── adminhtml ├── layout │ ├── gdpr_action_index.xml │ ├── gdpr_action_new.xml │ └── sales_order_view.xml └── ui_component │ ├── customer_form.xml │ ├── customer_listing.xml │ ├── gdpr_action_form.xml │ └── gdpr_action_listing.xml ├── base ├── layout │ ├── customer_privacy_export_personal_data.xml │ └── customer_privacy_export_personal_data_renderers.xml ├── layouts.xml ├── page_layout │ └── customer_privacy_export.xml ├── templates │ ├── export │ │ ├── renderer │ │ │ └── default.phtml │ │ └── result.phtml │ └── root.phtml └── web │ └── css │ └── export.less └── frontend ├── email ├── erase_canceled.html ├── erase_canceled_guest.html ├── erase_pending.html ├── erase_pending_guest.html ├── erase_succeeded.html ├── erase_succeeded_guest.html ├── export_pending.html ├── export_pending_guest.html ├── export_ready.html └── export_ready_guest.html ├── layout ├── customer_account.xml ├── customer_privacy_erase.xml ├── customer_privacy_settings.xml ├── default.xml └── sales_guest_view.xml ├── templates ├── account │ ├── erase.phtml │ ├── privacy │ │ ├── erase.phtml │ │ └── export.phtml │ └── settings.phtml ├── cookie │ └── notices.phtml └── order │ └── info │ ├── buttons │ ├── download.phtml │ ├── erase.phtml │ └── export.phtml │ ├── erase.phtml │ └── export.phtml └── web └── css └── source └── _module.less /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | #github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | #patreon: # Replace with a single Patreon username 5 | #open_collective: # Replace with a single Open Collective username 6 | #ko_fi: # Replace with a single Ko-fi username 7 | #tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | #community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | #liberapay: # Replace with a single Liberapay username 10 | #issuehunt: # Replace with a single IssueHunt username 11 | #otechie: # Replace with a single Otechie username 12 | custom: ['https://www.helloasso.com/associations/opengento/formulaires/1'] 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "[BUG]" 5 | labels: bug 6 | assignees: thomas-kl1 7 | 8 | --- 9 | 10 | ## Description 11 | A clear and concise description of what the bug is. 12 | 13 | ## Prerequisites 14 | 15 | **PHP Version:** 16 | - [e.g. 7.2.19] 17 | 18 | **Magento Version:** 19 | - [e.g. 2.3.2] 20 | 21 | **Module Version:** 22 | - [e.g. 1.0.0] 23 | 24 | **Desktop (if applicable):** 25 | - OS: [e.g. iOS] 26 | - Browser [e.g. chrome, safari] 27 | - Version [e.g. 22] 28 | 29 | **Smartphone (if applicable):** 30 | - Device: [e.g. iPhone6] 31 | - OS: [e.g. iOS8.1] 32 | - Browser [e.g. stock browser, safari] 33 | - Version [e.g. 22] 34 | 35 | ## Issue Details 36 | 37 | **Steps to reproduce the behavior** 38 | 1. Go to '...' 39 | 2. Click on '....' 40 | 3. Scroll down to '....' 41 | 4. See error 42 | 43 | **Expected behavior** 44 | A clear and concise description of what you expected to happen. 45 | 46 | **Screenshots** 47 | If applicable, add screenshots to help explain your problem. 48 | 49 | **Additional context** 50 | Add any other context about the problem here. 51 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: "[ENHANCEMENT]" 5 | labels: enhancement 6 | assignees: thomas-kl1 7 | 8 | --- 9 | 10 | ## Description 11 | 12 | - [ ] It's related to an existing issue: #[issueId] 13 | 14 | - [ ] It requires major modifications. 15 | 16 | Priority of the change: 17 | - [ ] High 18 | - [ ] Medium 19 | - [ ] Low 20 | 21 | **Which problem the feature would fix?** 22 | A clear and concise description of what the problem is. 23 | 24 | **Describe the solution as simple as possible** 25 | A clear and concise description of how it should works. 26 | 27 | **List the alternative solutions** 28 | Curated list of the alternative solutions. 29 | 30 | **Additional context** 31 | Add any other context or screenshots about the feature request here. 32 | 33 | ## Contributing 34 | 35 | - [ ] Would you want to contribute and to be assigned to this enhancement? 36 | -------------------------------------------------------------------------------- /.github/workflows/coding-standard.yml: -------------------------------------------------------------------------------- 1 | name: M2 Coding Standard 2 | on: [push, pull_request] 3 | 4 | jobs: 5 | static: 6 | name: M2 Coding Standard 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v2 10 | - uses: extdn/github-actions-m2/magento-coding-standard@master 11 | -------------------------------------------------------------------------------- /.github/workflows/mess-detector.yml: -------------------------------------------------------------------------------- 1 | name: M2 Mess Detector 2 | on: [push, pull_request] 3 | 4 | jobs: 5 | phpmd: 6 | name: M2 Mess Detector 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v2 10 | - uses: extdn/github-actions-m2/magento-mess-detector@master 11 | -------------------------------------------------------------------------------- /.github/workflows/phpstan.yml: -------------------------------------------------------------------------------- 1 | name: M2 PHPStan 2 | on: [push, pull_request, workflow_dispatch] 3 | 4 | jobs: 5 | phpstan: 6 | name: M2 PHPStan 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v2 10 | - uses: extdn/github-actions-m2/magento-phpstan@master 11 | with: 12 | composer_name: opengento/module-gdpr 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | -------------------------------------------------------------------------------- /Api/ActionInterface.php: -------------------------------------------------------------------------------- 1 | urlBuilder = $urlBuilder; 25 | } 26 | 27 | public function getButtonData(): array 28 | { 29 | return [ 30 | 'label' => new Phrase('Back'), 31 | 'on_click' => 'location.href = "' . $this->urlBuilder->getUrl('*/*/') . '";', 32 | 'class' => 'back', 33 | 'sort_order' => 10, 34 | ]; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Block/Adminhtml/Action/Edit/ExecuteButton.php: -------------------------------------------------------------------------------- 1 | new Phrase('Execute Action'), 19 | 'class' => 'primary', 20 | 'data_attribute' => [ 21 | 'mage-init' => ['button' => ['event' => 'save']], 22 | 'form-role' => 'save', 23 | ], 24 | 'on_click' => 'location.reload();', 25 | 'sort_order' => 30, 26 | 'aclResource' => 'Opengento_Gdpr::gdpr_actions_execute', 27 | ]; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Block/Adminhtml/Action/Edit/ResetButton.php: -------------------------------------------------------------------------------- 1 | new Phrase('Reset'), 19 | 'class' => 'reset', 20 | 'on_click' => 'location.reload();', 21 | 'sort_order' => 20, 22 | ]; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Block/Adminhtml/Config/Form/Field/Select/OptionSourceSelect.php: -------------------------------------------------------------------------------- 1 | optionSource = $optionSource; 27 | parent::__construct($context, $data); 28 | } 29 | 30 | public function setInputName(string $inputName): self 31 | { 32 | return $this->setData('name', $inputName); 33 | } 34 | 35 | protected function _toHtml(): string 36 | { 37 | if (!$this->getOptions()) { 38 | $this->setOptions($this->optionSource->toOptionArray()); 39 | } 40 | 41 | return parent::_toHtml(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Block/Adminhtml/Customer/Edit/ExportButton.php: -------------------------------------------------------------------------------- 1 | config = $config; 27 | parent::__construct($context, $registry); 28 | } 29 | 30 | public function getButtonData(): array 31 | { 32 | $customerId = $this->getCustomerId(); 33 | $buttonData = []; 34 | 35 | if ($customerId && $this->config->isModuleEnabled()) { 36 | $buttonData = [ 37 | 'label' => new Phrase('Export Personal Data'), 38 | 'class' => 'Export', 39 | 'id' => 'opengento-gdpr-customer-edit-export-button', 40 | 'on_click' => 'deleteConfirm("' . new Phrase('Are you sure you want to do this?') . '", ' 41 | . '"' . $this->getUrl('customer/privacy/export', ['id' => $customerId]) . '", {"data": {}})', 42 | 'sort_order' => 15, 43 | 'aclResource' => 'Opengento_Gdpr::customer_export', 44 | ]; 45 | } 46 | 47 | return $buttonData; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Block/Adminhtml/Order/Edit/ExportButton.php: -------------------------------------------------------------------------------- 1 | getLayout()->getBlock('sales_order_edit'); 27 | $orderId = (int) $orderView->getOrderId(); 28 | 29 | if ($this->_authorization->isAllowed('Opengento_Gdpr::order_export')) { 30 | $orderView->addButton( 31 | 'opengento-gdpr-order-view-export-button', 32 | [ 33 | 'label' => new Phrase('Export Personal Data'), 34 | 'class' => 'export', 35 | 'onclick' => 'setLocation("' . $this->getUrl('sales/guest/export', ['id' => $orderId]) . '")', 36 | ] 37 | ); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Controller/AbstractGuest.php: -------------------------------------------------------------------------------- 1 | orderLoader = $orderLoader; 37 | $this->registry = $registry; 38 | parent::__construct($request, $resultFactory, $messageManager, $config); 39 | } 40 | 41 | public function execute() 42 | { 43 | $result = $this->orderLoader->load($this->request); 44 | 45 | return $result instanceof ResultInterface ? $result : parent::execute(); 46 | } 47 | 48 | protected function currentOrder(): OrderInterface 49 | { 50 | return $this->registry->registry('current_order'); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Controller/Adminhtml/AbstractAction.php: -------------------------------------------------------------------------------- 1 | config = $config; 28 | parent::__construct($context); 29 | } 30 | 31 | public function execute() 32 | { 33 | if ($this->isAllowed()) { 34 | return $this->executeAction(); 35 | } 36 | 37 | return $this->forwardNoRoute(); 38 | } 39 | 40 | /** 41 | * Execute action based on request and return result 42 | * 43 | * @return ResultInterface|ResponseInterface 44 | * @throws NotFoundException 45 | */ 46 | abstract protected function executeAction(); 47 | 48 | protected function isAllowed(): bool 49 | { 50 | return $this->config->isModuleEnabled(); 51 | } 52 | 53 | protected function forwardNoRoute(): ResultInterface 54 | { 55 | /** @var Forward $resultForward */ 56 | $resultForward = $this->resultFactory->create(ResultFactory::TYPE_FORWARD); 57 | 58 | return $resultForward->forward('no_route'); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Controller/Adminhtml/Action/Index.php: -------------------------------------------------------------------------------- 1 | resultFactory->create(ResultFactory::TYPE_PAGE); 24 | $resultPage->setActiveMenu('Opengento_Gdpr::gdpr_actions'); 25 | $resultPage->getConfig()->getTitle()->set(new Phrase('View Actions')); 26 | $resultPage->addBreadcrumb(new Phrase('GDPR'), new Phrase('GDPR')); 27 | $resultPage->addBreadcrumb(new Phrase('View Actions'), new Phrase('View Actions')); 28 | 29 | return $resultPage; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Controller/Adminhtml/Action/NewAction.php: -------------------------------------------------------------------------------- 1 | resultFactory->create(ResultFactory::TYPE_PAGE); 24 | $resultPage->setActiveMenu('Opengento_Gdpr::gdpr_actions'); 25 | $resultPage->getConfig()->getTitle()->set(new Phrase('Execute New Action')); 26 | $resultPage->addBreadcrumb(new Phrase('GDPR'), new Phrase('GDPR')); 27 | $resultPage->addBreadcrumb(new Phrase('Execute New Action'), new Phrase('Execute New Action')); 28 | 29 | return $resultPage; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Controller/Privacy/Settings.php: -------------------------------------------------------------------------------- 1 | resultFactory->create(ResultFactory::TYPE_PAGE); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) OpenGento 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Model/Action/AbstractAction.php: -------------------------------------------------------------------------------- 1 | resultBuilder = $resultBuilder; 28 | } 29 | 30 | protected function createActionResult( 31 | array $result = [], 32 | string $message = self::DEFAULT_MESSAGE 33 | ): ActionResultInterface { 34 | $this->resultBuilder->setState(ActionEntityInterface::STATE_SUCCEEDED); 35 | $this->resultBuilder->setPerformedAt(new DateTime()); 36 | $this->resultBuilder->setMessage($message); 37 | $this->resultBuilder->setResult($result); 38 | 39 | return $this->resultBuilder->create(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Model/Action/ActionFactory.php: -------------------------------------------------------------------------------- 1 | actions = $actions; 37 | $this->objectManager = $objectManager; 38 | $this->instances = []; 39 | } 40 | 41 | public function get(string $type): ActionInterface 42 | { 43 | if (!isset($this->instances[$type])) { 44 | if (!isset($this->actions[$type])) { 45 | throw new InvalidArgumentException(sprintf('Unknown action for type "%s".', $type)); 46 | } 47 | 48 | $this->instances[$type] = $this->objectManager->create($this->actions[$type], ['type' => $type]); 49 | } 50 | 51 | return $this->instances[$type]; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Model/Action/ArgumentReader.php: -------------------------------------------------------------------------------- 1 | getParameters()[self::ENTITY_TYPE] ?? null; 20 | } 21 | 22 | public static function getEntityId(ActionContextInterface $actionContext): ?int 23 | { 24 | return $actionContext->getParameters()[self::ENTITY_ID] ?? null; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Model/Action/Context.php: -------------------------------------------------------------------------------- 1 | performedFrom = $performedFrom; 26 | $this->performedBy = $performedBy; 27 | $this->parameters = $parameters; 28 | } 29 | 30 | public function getPerformedFrom(): string 31 | { 32 | return $this->performedFrom; 33 | } 34 | 35 | public function getPerformedBy(): string 36 | { 37 | return $this->performedBy; 38 | } 39 | 40 | public function getParameters(): array 41 | { 42 | return $this->parameters; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Model/Action/Erase/ArgumentReader.php: -------------------------------------------------------------------------------- 1 | getParameters()[self::ERASE_ENTITY] ?? null; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Model/Action/Erase/ExecuteAction.php: -------------------------------------------------------------------------------- 1 | eraseManagement = $eraseManagement; 26 | parent::__construct($resultBuilder); 27 | } 28 | 29 | public function execute(ActionContextInterface $actionContext): ActionResultInterface 30 | { 31 | $eraseEntity = ArgumentReader::getEntity($actionContext); 32 | 33 | if ($eraseEntity === null) { 34 | throw InputException::requiredField('entity'); 35 | } 36 | 37 | return $this->createActionResult( 38 | [ArgumentReader::ERASE_ENTITY => $this->eraseManagement->process($eraseEntity)] 39 | ); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Model/Action/Export/ArgumentReader.php: -------------------------------------------------------------------------------- 1 | getParameters()[self::EXPORT_ENTITY] ?? null; 21 | } 22 | 23 | public static function getFileName(ActionContextInterface $actionContext): ?string 24 | { 25 | return $actionContext->getParameters()[self::EXPORT_FILE_NAME] ?? null; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Model/Action/PerformedBy/AdminUser.php: -------------------------------------------------------------------------------- 1 | authSession = $authSession; 29 | $this->attributeName = $attributeName; 30 | } 31 | 32 | public function get(): string 33 | { 34 | return self::PERFORMED_BY . $this->resolveUserName(); 35 | } 36 | 37 | private function resolveUserName(): string 38 | { 39 | return $this->authSession->getUser() ? $this->authSession->getUser()->getData($this->attributeName) : 'Unknown'; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Model/Action/PerformedBy/Console.php: -------------------------------------------------------------------------------- 1 | customerSession = $customerSession; 28 | $this->attributeName = $attributeName; 29 | } 30 | 31 | public function get(): string 32 | { 33 | return $this->customerSession->isLoggedIn() 34 | ? $this->customerSession->getCustomer()->getData($this->attributeName) 35 | : ''; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Model/Action/PerformedBy/Guest.php: -------------------------------------------------------------------------------- 1 | coreRegistry = $coreRegistry; 26 | $this->attributeName = $attributeName; 27 | } 28 | 29 | public function get(): string 30 | { 31 | $order = $this->coreRegistry->registry('current_order'); 32 | 33 | return $order && $order instanceof Order ? $order->getData($this->attributeName) : ''; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Model/Action/PerformedBy/NotEmptyStrategy.php: -------------------------------------------------------------------------------- 1 | performedByList = $performedByList; 25 | } 26 | 27 | public function get(): string 28 | { 29 | $performer = self::PERFORMED_BY; 30 | 31 | foreach ($this->performedByList as $performedBy) { 32 | $performer = $performedBy->get() ?: $performer; 33 | } 34 | 35 | return $performer; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Model/Action/PerformedByInterface.php: -------------------------------------------------------------------------------- 1 | performedAt = $performedAt; 33 | $this->state = $state; 34 | $this->message = $message; 35 | $this->result = $result; 36 | } 37 | 38 | public function getPerformedAt(): DateTime 39 | { 40 | return $this->performedAt; 41 | } 42 | 43 | public function getState(): string 44 | { 45 | return $this->state; 46 | } 47 | 48 | public function getMessage(): string 49 | { 50 | return $this->message; 51 | } 52 | 53 | public function getResult(): array 54 | { 55 | return $this->result; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Model/Action/ResultBuilder.php: -------------------------------------------------------------------------------- 1 | actionResultFactory = $actionResultFactory; 30 | $this->data = []; 31 | } 32 | 33 | public function setPerformedAt(DateTime $performedAt): ResultBuilder 34 | { 35 | $this->data['performedAt'] = $performedAt; 36 | 37 | return $this; 38 | } 39 | 40 | public function setState(string $state): ResultBuilder 41 | { 42 | $this->data['state'] = $state; 43 | 44 | return $this; 45 | } 46 | 47 | public function setMessage(string $message): ResultBuilder 48 | { 49 | $this->data['message'] = $message; 50 | 51 | return $this; 52 | } 53 | 54 | public function setResult(array $result): ResultBuilder 55 | { 56 | $this->data['result'] = $result; 57 | 58 | return $this; 59 | } 60 | 61 | public function create(): ActionResultInterface 62 | { 63 | /** @var ActionResultInterface $result */ 64 | $result = $this->actionResultFactory->create($this->data); 65 | $this->data = []; 66 | 67 | return $result; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Model/Archive/Zip.php: -------------------------------------------------------------------------------- 1 | filesystem = $filesystem; 34 | $this->zip = $zip; 35 | } 36 | 37 | public function pack($source, $destination): string 38 | { 39 | $directoryRead = $this->filesystem->getDirectoryReadByPath($source); 40 | 41 | $zip = new ZipArchive(); 42 | $zip->open($destination, ZipArchive::CREATE); 43 | $zip->addFile($source, $directoryRead->isDirectory($source) ? '' : basename($source)); 44 | $zip->close(); 45 | 46 | return $destination; 47 | } 48 | 49 | public function unpack($source, $destination): string 50 | { 51 | return $this->zip->unpack($source, $destination); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Model/Config/Source/OrderPendingStates.php: -------------------------------------------------------------------------------- 1 | collectionFactory = $collectionFactory; 26 | } 27 | 28 | public function toOptionArray(): array 29 | { 30 | return $this->options ??= $this->collectionFactory->create()->joinStates()->toOptionArray(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Model/Config/Source/VirtualCustomerAttributes.php: -------------------------------------------------------------------------------- 1 | metadata = $metadata; 24 | $this->options = []; 25 | } 26 | 27 | public function toOptionArray(): array 28 | { 29 | if (!$this->options) { 30 | try { 31 | $attributes = $this->metadata->getAllAttributesMetadata(); 32 | } catch (LocalizedException $e) { 33 | $attributes = []; 34 | } 35 | 36 | foreach ($attributes as $attribute) { 37 | $this->options[] = [ 38 | 'value' => $attribute->getAttributeCode(), 39 | 'label' => $attribute->getFrontendLabel(), 40 | ]; 41 | } 42 | } 43 | 44 | return $this->options; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Model/Config/Source/VirtualEntityAttributes.php: -------------------------------------------------------------------------------- 1 | attributeProvider = $attributeProvider; 35 | $this->entityType = $entityType; 36 | $this->options = []; 37 | } 38 | 39 | public function toOptionArray(): array 40 | { 41 | if (!$this->options) { 42 | foreach (array_keys($this->attributeProvider->getAttributes($this->entityType)) as $attribute) { 43 | $this->options[] = ['value' => $attribute, 'label' => $attribute]; 44 | } 45 | } 46 | 47 | return $this->options; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Model/Customer/Anonymize/Processor/CustomerAddressDataProcessor.php: -------------------------------------------------------------------------------- 1 | anonymizer = $anonymizer; 33 | $this->addressRepository = $addressRepository; 34 | $this->criteriaBuilder = $criteriaBuilder; 35 | } 36 | 37 | /** 38 | * @inheritdoc 39 | * @throws LocalizedException 40 | */ 41 | public function execute(int $customerId): bool 42 | { 43 | $this->criteriaBuilder->addFilter('parent_id', $customerId); 44 | $addressList = $this->addressRepository->getList($this->criteriaBuilder->create()); 45 | 46 | foreach ($addressList->getItems() as $address) { 47 | $this->addressRepository->save($this->anonymizer->anonymize($address)); 48 | } 49 | 50 | return true; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Model/Customer/Anonymize/Processor/SubscriberDataProcessor.php: -------------------------------------------------------------------------------- 1 | anonymizer = $anonymizer; 31 | $this->subscriberFactory = $subscriberFactory; 32 | $this->subscriberResource = $subscriberResource; 33 | } 34 | 35 | /** 36 | * @inheritdoc 37 | * @throws Exception 38 | */ 39 | public function execute(int $customerId): bool 40 | { 41 | /** @var Subscriber $subscriber */ 42 | $subscriber = $this->subscriberFactory->create(); 43 | $subscriber->loadByCustomerId($customerId); 44 | $this->anonymizer->anonymize($subscriber); 45 | $this->subscriberResource->save($subscriber->getRealSubscriber()); 46 | 47 | return true; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Model/Customer/CustomerChecker.php: -------------------------------------------------------------------------------- 1 | orderRepository = $orderRepository; 35 | $this->criteriaBuilder = $criteriaBuilder; 36 | $this->config = $config; 37 | $this->cache = []; 38 | } 39 | 40 | public function canErase(int $customerId): bool 41 | { 42 | if (!isset($this->cache[$customerId])) { 43 | $this->criteriaBuilder->addFilter(OrderInterface::STATE, $this->config->getAllowedStatesToErase(), 'nin'); 44 | $this->criteriaBuilder->addFilter(OrderInterface::CUSTOMER_ID, $customerId); 45 | $orderList = $this->orderRepository->getList($this->criteriaBuilder->create()); 46 | 47 | $this->cache[$customerId] = !$orderList->getTotalCount(); 48 | } 49 | 50 | return $this->cache[$customerId]; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Model/Customer/Delete/Processor/CustomerAddressDataProcessor.php: -------------------------------------------------------------------------------- 1 | addressRepository = $addressRepository; 29 | $this->criteriaBuilder = $criteriaBuilder; 30 | } 31 | 32 | /** 33 | * @inheritdoc 34 | * @throws LocalizedException 35 | */ 36 | public function execute(int $customerId): bool 37 | { 38 | $this->criteriaBuilder->addFilter('parent_id', $customerId); 39 | $addressList = $this->addressRepository->getList($this->criteriaBuilder->create()); 40 | 41 | foreach ($addressList->getItems() as $address) { 42 | $this->addressRepository->delete($address); 43 | } 44 | 45 | return true; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Model/Customer/Delete/Processor/CustomerDataProcessor.php: -------------------------------------------------------------------------------- 1 | customerRepository = $customerRepository; 33 | $this->sessionCleaner = $sessionCleaner; 34 | } 35 | 36 | /** 37 | * @inheritdoc 38 | * @throws LocalizedException 39 | */ 40 | public function execute(int $customerId): bool 41 | { 42 | $this->sessionCleaner->clearFor($customerId); 43 | 44 | try { 45 | $this->customerRepository->deleteById($customerId); 46 | } catch (NoSuchEntityException $e) { 47 | /** Silence is golden */ 48 | } 49 | 50 | return true; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Model/Customer/Delete/Processor/QuoteDataProcessor.php: -------------------------------------------------------------------------------- 1 | quoteRepository = $quoteRepository; 25 | $this->criteriaBuilder = $criteriaBuilder; 26 | } 27 | 28 | public function execute(int $customerId): bool 29 | { 30 | $this->criteriaBuilder->addFilter('customer_id', $customerId); 31 | $quoteList = $this->quoteRepository->getList($this->criteriaBuilder->create()); 32 | 33 | foreach ($quoteList->getItems() as $quote) { 34 | $this->quoteRepository->delete($quote); 35 | } 36 | 37 | return true; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Model/Customer/Delete/Processor/SubscriberDataProcessor.php: -------------------------------------------------------------------------------- 1 | subscriberFactory = $subscriberFactory; 27 | $this->subscriberResource = $subscriberResource; 28 | } 29 | 30 | /** 31 | * @inheritdoc 32 | * @throws Exception 33 | */ 34 | public function execute(int $customerId): bool 35 | { 36 | /** @var Subscriber $subscriber */ 37 | $subscriber = $this->subscriberFactory->create(); 38 | $subscriber->loadByCustomerId($customerId); 39 | $this->subscriberResource->delete($subscriber); 40 | 41 | return true; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Model/Customer/Export/Notifier.php: -------------------------------------------------------------------------------- 1 | senders = $senders; 32 | $this->customerRepository = $customerRepository; 33 | $this->logger = $logger; 34 | } 35 | 36 | /** 37 | * @inheritdoc 38 | * @throws LocalizedException 39 | */ 40 | public function notify(ExportEntityInterface $exportEntity): void 41 | { 42 | $customer = $this->customerRepository->getById($exportEntity->getEntityId()); 43 | 44 | foreach ($this->senders as $sender) { 45 | try { 46 | $sender->send($customer); 47 | } catch (LocalizedException $e) { 48 | $this->logger->error($e->getLogMessage(), $e->getTrace()); 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Model/Customer/Export/Processor/CustomerDataProcessor.php: -------------------------------------------------------------------------------- 1 | customerRepository = $customerRepository; 28 | parent::__construct($dataCollector); 29 | } 30 | 31 | /** 32 | * @inheritdoc 33 | * @throws NoSuchEntityException 34 | * @throws LocalizedException 35 | */ 36 | public function execute(int $customerId, array $data): array 37 | { 38 | $data['customer'] = $this->collectData($this->customerRepository->getById($customerId)); 39 | 40 | return $data; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Model/Customer/Export/Processor/SubscriberDataProcessor.php: -------------------------------------------------------------------------------- 1 | subscriberFactory = $subscriberFactory; 24 | parent::__construct($dataCollector); 25 | } 26 | 27 | public function execute(int $customerId, array $data): array 28 | { 29 | /** @var Subscriber $subscriber */ 30 | $subscriber = $this->subscriberFactory->create(); 31 | $subscriber->loadByCustomerId($customerId); 32 | $data['subscriber'] = $this->collectData($subscriber); 33 | 34 | return $data; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Model/Customer/Notifier/SenderInterface.php: -------------------------------------------------------------------------------- 1 | customers[$customerId] ?? null; 22 | } 23 | 24 | public function set(CustomerInterface $customer): void 25 | { 26 | $this->customers[(int) $customer->getId()] = $customer; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Model/Entity/DataCollector.php: -------------------------------------------------------------------------------- 1 | entityIterator = $entityIterator; 27 | $this->document = $document; 28 | } 29 | 30 | public function collect(object $entity): array 31 | { 32 | $this->entityIterator->iterate($entity); 33 | $data = $this->document->getData(); 34 | $this->document->setData([]); 35 | 36 | return $data; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Model/Entity/DataCollectorGeneric.php: -------------------------------------------------------------------------------- 1 | typeResolver = $typeResolver; 29 | $this->dataCollectors = $dataCollectors; 30 | } 31 | 32 | /** 33 | * @inheritdoc 34 | * @throws Exception 35 | */ 36 | public function collect(object $entity): array 37 | { 38 | $entityType = $this->typeResolver->resolve($entity); 39 | 40 | if (!isset($this->dataCollectors[$entityType])) { 41 | throw new LogicException( 42 | sprintf('There is no registered data collector for the entity type "%s".', $entityType) 43 | ); 44 | } 45 | 46 | return $this->dataCollectors[$entityType]->collect($entity); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Model/Entity/DataCollectorInterface.php: -------------------------------------------------------------------------------- 1 | data = $data; 17 | } 18 | 19 | public function setData(array $data): void 20 | { 21 | $this->data = $data; 22 | } 23 | 24 | public function addData(string $key, $value): void 25 | { 26 | $this->data[$key] = $value; 27 | } 28 | 29 | public function getData(): array 30 | { 31 | return $this->data; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Model/Entity/DocumentInterface.php: -------------------------------------------------------------------------------- 1 | checkers = $checkers; 35 | $this->objectManager = $objectManager; 36 | } 37 | 38 | public function get(string $entityType): EntityCheckerInterface 39 | { 40 | if (!isset($this->checkers[$entityType])) { 41 | throw new InvalidArgumentException(sprintf('Unknown checker for entity type "%s".', $entityType)); 42 | } 43 | 44 | return $this->objectManager->get($this->checkers[$entityType]); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Model/Entity/EntityCheckerInterface.php: -------------------------------------------------------------------------------- 1 | hydratorPool = $hydratorPool; 28 | $this->typeResolver = $typeResolver; 29 | $this->processor = $processor; 30 | } 31 | 32 | /** 33 | * @inheritdoc 34 | * @throws Exception 35 | */ 36 | public function iterate(object $entity): void 37 | { 38 | $values = $this->hydratorPool->getHydrator($this->typeResolver->resolve($entity))->extract($entity); 39 | 40 | foreach ($values as $key => $value) { 41 | $this->processor->process($key, $value); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Model/Entity/EntityIteratorInterface.php: -------------------------------------------------------------------------------- 1 | list = $list; 32 | } 33 | 34 | public function getList(): array 35 | { 36 | return $this->list; 37 | } 38 | 39 | public function getEntityTypes(): array 40 | { 41 | $entityTypes = []; 42 | 43 | foreach ($this->getList() as $types) { 44 | $entityTypes[] = array_keys($types); 45 | } 46 | 47 | return $this->entityTypes ??= array_merge([], ...$entityTypes); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Model/Entity/EntityTypeResolver.php: -------------------------------------------------------------------------------- 1 | typeResolver = $typeResolver; 27 | $this->entityTypeList = $entityTypeList; 28 | } 29 | 30 | /** 31 | * @param object $entity 32 | * @return string[] 33 | * @throws Exception 34 | */ 35 | public function resolve(object $entity): array 36 | { 37 | return $this->entityTypeList->getList()[$this->typeResolver->resolve($entity)] ?? []; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Model/Entity/EntityValue/CustomAttributesProcessor.php: -------------------------------------------------------------------------------- 1 | processor = $processor; 22 | } 23 | 24 | public function process(string $key, $values): void 25 | { 26 | if ($key === CustomAttributesDataInterface::CUSTOM_ATTRIBUTES && is_iterable($values)) { 27 | foreach ($values as $value) { 28 | $this->processor->process($key, $value); 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Model/Entity/EntityValue/ExtensibleDataProcessor.php: -------------------------------------------------------------------------------- 1 | processor = $processor; 22 | } 23 | 24 | public function process(string $key, $values): void 25 | { 26 | if ($key === ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY && is_iterable($values)) { 27 | foreach ($values as $value) { 28 | $this->processor->process($key, $value); 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Model/Entity/EntityValue/StrategyProcessor.php: -------------------------------------------------------------------------------- 1 | processors = $processors; 23 | } 24 | 25 | public function process(string $key, $value): void 26 | { 27 | ($this->processors[$key] ?? $this->processors['default'])->process($key, $value); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Model/Entity/EntityValueProcessorInterface.php: -------------------------------------------------------------------------------- 1 | scopeConfig = $scopeConfig; 27 | $this->configPath = $configPath; 28 | $this->scopeType = $scopeType; 29 | } 30 | 31 | public function getAttributes(?string $scopeCode = null): array 32 | { 33 | return explode(',', $this->scopeConfig->getValue($this->configPath, $this->scopeType, $scopeCode) ?? ''); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Model/Entity/MetadataInterface.php: -------------------------------------------------------------------------------- 1 | filterIdentifier = $filterIdentifier; 25 | $this->fieldToFilter = $fieldToFilter; 26 | } 27 | 28 | /** 29 | * @inheritdoc 30 | * @throws LocalizedException 31 | */ 32 | public function apply(Collection $collection, Filter $filter): void 33 | { 34 | if ($filter->getField() === $this->filterIdentifier) { 35 | $collection->addFieldToFilter( 36 | $this->fieldToFilter, 37 | [$filter->getConditionType() => $filter->getValue()] 38 | ); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Model/Entity/SourceProvider/ModifierComposite.php: -------------------------------------------------------------------------------- 1 | modifiers = $modifiers; 27 | } 28 | 29 | public function apply(Collection $collection, Filter $filter): void 30 | { 31 | foreach ($this->modifiers as $modifier) { 32 | $modifier->apply($collection, $filter); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Model/Entity/SourceProvider/ModifierFactory.php: -------------------------------------------------------------------------------- 1 | modifiers = $modifiers; 33 | $this->objectManager = $objectManager; 34 | } 35 | 36 | public function get(string $entityType): ModifierInterface 37 | { 38 | return $this->objectManager->get($this->modifiers[$entityType] ?? $this->modifiers['default']); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Model/Entity/SourceProvider/ModifierInterface.php: -------------------------------------------------------------------------------- 1 | sourceProviders = $sourceProviders; 36 | $this->objectManager = $objectManager; 37 | } 38 | 39 | public function create(string $entityType): Collection 40 | { 41 | if (!isset($this->sourceProviders[$entityType])) { 42 | throw new InvalidArgumentException(sprintf('Unknown source provider for entity type "%s".', $entityType)); 43 | } 44 | 45 | return $this->objectManager->create($this->sourceProviders[$entityType]); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Model/Erase/NotifierInterface.php: -------------------------------------------------------------------------------- 1 | exportRepository = $exportRepository; 22 | } 23 | 24 | public function exists(int $entityId, string $entityType): bool 25 | { 26 | try { 27 | return (bool) $this->exportRepository->getByEntity($entityId, $entityType)->getExportId(); 28 | } catch (NoSuchEntityException $e) { 29 | return false; 30 | } 31 | } 32 | 33 | public function isExported(int $entityId, string $entityType): bool 34 | { 35 | try { 36 | $entity = $this->exportRepository->getByEntity($entityId, $entityType); 37 | } catch (NoSuchEntityException $e) { 38 | return false; 39 | } 40 | 41 | return $entity->getExportedAt() !== null && $entity->getFilePath() !== null; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Model/Newsletter/Subscriber.php: -------------------------------------------------------------------------------- 1 | subscriber = $subscriberFactory->create(['data' => $data]); 28 | } 29 | 30 | public function getRealSubscriber(): SubscriberModel 31 | { 32 | return $this->subscriber; 33 | } 34 | 35 | public function __call($method, $args) 36 | { 37 | return $this->subscriber->{$method}(...$args); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Model/Order/Delete/Processor/OrderDataProcessor.php: -------------------------------------------------------------------------------- 1 | orderRepository = $orderRepository; 27 | $this->salesInformation = $salesInformation; 28 | } 29 | 30 | /** 31 | * @inheritdoc 32 | * @throws Exception 33 | */ 34 | public function execute(int $orderId): bool 35 | { 36 | $order = $this->orderRepository->get($orderId); 37 | $lastActive = new DateTime($order->getUpdatedAt()); 38 | 39 | if ($this->salesInformation->isAlive($lastActive)) { 40 | $this->salesInformation->scheduleEraseEntity((int) $order->getEntityId(), 'order', $lastActive); 41 | 42 | return true; 43 | } 44 | 45 | return $this->orderRepository->delete($order); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Model/Order/Delete/Processor/QuoteDataProcessor.php: -------------------------------------------------------------------------------- 1 | orderRepository = $orderRepository; 26 | $this->quoteRepository = $quoteRepository; 27 | } 28 | 29 | public function execute(int $orderId): bool 30 | { 31 | try { 32 | $order = $this->orderRepository->get($orderId); 33 | $this->quoteRepository->delete($this->quoteRepository->get($order->getQuoteId())); 34 | } catch (NoSuchEntityException $e) { 35 | /** Silence is golden */ 36 | } 37 | 38 | return true; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Model/Order/Erase/Notifier.php: -------------------------------------------------------------------------------- 1 | senders = $senders; 32 | $this->orderRepository = $orderRepository; 33 | $this->logger = $logger; 34 | } 35 | 36 | public function notify(EraseEntityInterface $eraseEntity): void 37 | { 38 | $order = $this->orderRepository->get($eraseEntity->getEntityId()); 39 | 40 | foreach ($this->senders as $sender) { 41 | try { 42 | $sender->send($order); 43 | } catch (LocalizedException $e) { 44 | $this->logger->error($e->getLogMessage(), $e->getTrace()); 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Model/Order/Export/Notifier.php: -------------------------------------------------------------------------------- 1 | senders = $senders; 32 | $this->orderRepository = $orderRepository; 33 | $this->logger = $logger; 34 | } 35 | 36 | /** 37 | * @inheritdoc 38 | */ 39 | public function notify(ExportEntityInterface $exportEntity): void 40 | { 41 | $order = $this->orderRepository->get($exportEntity->getEntityId()); 42 | 43 | foreach ($this->senders as $sender) { 44 | try { 45 | $sender->send($order); 46 | } catch (LocalizedException $e) { 47 | $this->logger->error($e->getLogMessage(), $e->getTrace()); 48 | } 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Model/Order/Export/Processor/AbstractDataProcessor.php: -------------------------------------------------------------------------------- 1 | orderRepository = $orderRepository; 24 | parent::__construct($dataCollector); 25 | } 26 | 27 | public function execute(int $entityId, array $data): array 28 | { 29 | return $this->export($this->orderRepository->get($entityId), $data); 30 | } 31 | 32 | /** 33 | * Execute the export processor for the given order entity. 34 | * It allows to retrieve the related data as an array. 35 | * 36 | * @param OrderInterface $order 37 | * @param array $ata 38 | * @return array 39 | */ 40 | abstract protected function export(OrderInterface $order, array $ata): array; 41 | } 42 | -------------------------------------------------------------------------------- /Model/Order/Export/Processor/OrderDataProcessor.php: -------------------------------------------------------------------------------- 1 | getEntityId(); 20 | $data['orders'][$key] = $this->collectData($order); 21 | 22 | /** @var OrderAddressInterface|null $orderAddress */ 23 | foreach ([$order->getBillingAddress(), $order->getShippingAddress()] as $orderAddress) { 24 | if ($orderAddress) { 25 | $data['orders'][$key][$orderAddress->getAddressType()] = $this->collectData($orderAddress); 26 | } 27 | } 28 | 29 | return $data; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Model/Order/Export/Processor/SubscriberDataProcessor.php: -------------------------------------------------------------------------------- 1 | subscriberFactory = $subscriberFactory; 26 | parent::__construct($orderRepository, $dataCollector); 27 | } 28 | 29 | protected function export(OrderInterface $order, array $data): array 30 | { 31 | /** @var Subscriber $subscriber */ 32 | $subscriber = $this->subscriberFactory->create(); 33 | $subscriber->loadByEmail($order->getCustomerEmail()); 34 | $data['subscriber'] = $this->collectData($subscriber); 35 | 36 | return $data; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Model/Order/Notifier/SenderInterface.php: -------------------------------------------------------------------------------- 1 | orderRepository = $orderRepository; 26 | $this->config = $config; 27 | } 28 | 29 | public function canErase(int $orderId): bool 30 | { 31 | $order = $this->orderRepository->get($orderId); 32 | 33 | return in_array($order->getState(), $this->config->getAllowedStatesToErase(), true); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Model/Order/SourceProvider/GuestFilterModifier.php: -------------------------------------------------------------------------------- 1 | config = $config; 24 | } 25 | 26 | /** 27 | * @inheritdoc 28 | * @throws LocalizedException 29 | */ 30 | public function apply(Collection $collection, Filter $filter): void 31 | { 32 | $collection->addFieldToFilter(OrderInterface::CUSTOMER_ID, ['null' => true]); 33 | $collection->addFieldToFilter(OrderInterface::CUSTOMER_IS_GUEST, ['eq' => 1]); 34 | $collection->addFieldToFilter(OrderInterface::STATE, ['in' => $this->config->getAllowedStatesToErase()]); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Model/ResourceModel/ActionEntity.php: -------------------------------------------------------------------------------- 1 | validator = $validator; 32 | parent::__construct($context, $entitySnapshot, $relationComposite, $connectionName); 33 | } 34 | 35 | protected function _construct(): void 36 | { 37 | $this->_init(self::TABLE, ActionEntityInterface::ID); 38 | $this->_serializableFields = [ActionEntityInterface::PARAMETERS => [[], []]]; 39 | } 40 | 41 | public function getValidationRulesBeforeSave(): ValidatorInterface 42 | { 43 | return $this->validator; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Model/ResourceModel/ActionEntity/Collection.php: -------------------------------------------------------------------------------- 1 | _init(ActionEntity::class, ActionEntityResourceModel::class); 20 | $this->_setIdFieldName(ActionEntityInterface::ID); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Model/ResourceModel/ActionEntity/Validator.php: -------------------------------------------------------------------------------- 1 | validators = $validators; 24 | } 25 | 26 | public function isValid($value): bool 27 | { 28 | $this->_clearMessages(); 29 | 30 | foreach ($this->validators as $validator) { 31 | if (!$validator->isValid($value)) { 32 | $this->_addMessages($validator->getMessages()); 33 | } 34 | } 35 | 36 | return !$this->hasMessages(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Model/ResourceModel/ActionEntity/Validator/StateValidator.php: -------------------------------------------------------------------------------- 1 | actionStates = $actionStates; 25 | } 26 | 27 | /** 28 | * @param ActionEntityInterface $actionEntity 29 | * @return bool 30 | */ 31 | public function isValid($actionEntity): bool 32 | { 33 | $this->_clearMessages(); 34 | $isValid = in_array( 35 | $actionEntity->getState(), 36 | array_column($this->actionStates->toOptionArray(), 'value'), 37 | true 38 | ); 39 | 40 | if (!$isValid) { 41 | $this->_addMessages([ 42 | 'state' => new Phrase('State "%1" does not exists.', [$actionEntity->getState()]) 43 | ]); 44 | } 45 | 46 | return $isValid; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Model/ResourceModel/EraseEntity.php: -------------------------------------------------------------------------------- 1 | _init(self::TABLE, EraseEntityInterface::ID); 25 | } 26 | 27 | /** 28 | * @inheritdoc 29 | * @param string|array $field 30 | * @param mixed $value 31 | * @param AbstractModel $object 32 | * @return Select 33 | * @throws LocalizedException 34 | */ 35 | protected function _getLoadSelect($field, $value, $object): Select 36 | { 37 | if (!is_array($field) && !is_array($value)) { 38 | return parent::_getLoadSelect($field, $value, $object); 39 | } 40 | 41 | $select = $this->getConnection()->select()->from($this->getMainTable()); 42 | 43 | foreach ($field as $i => $identifier) { 44 | $primaryKey = $this->getConnection()->quoteIdentifier(sprintf('%s.%s', $this->getMainTable(), $identifier)); 45 | $select->where($primaryKey . '=?', $value[$i]); 46 | } 47 | 48 | return $select; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Model/ResourceModel/EraseEntity/Collection.php: -------------------------------------------------------------------------------- 1 | _init(EraseEntity::class, EraseEntityResourceModel::class); 20 | $this->_setIdFieldName(EraseEntityInterface::ID); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Model/ResourceModel/ExportEntity.php: -------------------------------------------------------------------------------- 1 | _init(self::TABLE, ExportEntityInterface::ID); 25 | } 26 | 27 | /** 28 | * @inheritdoc 29 | * @param string|array $field 30 | * @param mixed $value 31 | * @param AbstractModel $object 32 | * @return Select 33 | * @throws LocalizedException 34 | */ 35 | protected function _getLoadSelect($field, $value, $object): Select 36 | { 37 | if (!is_array($field) && !is_array($value)) { 38 | return parent::_getLoadSelect($field, $value, $object); 39 | } 40 | 41 | $select = $this->getConnection()->select()->from($this->getMainTable()); 42 | 43 | foreach ($field as $i => $identifier) { 44 | $primaryKey = $this->getConnection()->quoteIdentifier(sprintf('%s.%s', $this->getMainTable(), $identifier)); 45 | $select->where($primaryKey . '=?', $value[$i]); 46 | } 47 | 48 | return $select; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Model/ResourceModel/ExportEntity/Collection.php: -------------------------------------------------------------------------------- 1 | _init(ExportEntity::class, ExportEntityResourceModel::class); 20 | $this->_setIdFieldName(ExportEntityInterface::ID); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Service/Anonymize/Anonymizer/AlphaLower.php: -------------------------------------------------------------------------------- 1 | mathRandom = $mathRandom; 30 | $this->length = $length; 31 | } 32 | 33 | /** 34 | * @inheritdoc 35 | * @throws LocalizedException 36 | */ 37 | public function anonymize($value): ?string 38 | { 39 | return $value ? $this->mathRandom->getRandomString($this->length, Random::CHARS_LOWERS) : null; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Service/Anonymize/Anonymizer/AlphaNum.php: -------------------------------------------------------------------------------- 1 | mathRandom = $mathRandom; 30 | $this->length = $length; 31 | } 32 | 33 | /** 34 | * @inheritdoc 35 | * @throws LocalizedException 36 | */ 37 | public function anonymize($value): ?string 38 | { 39 | return $value ? $this->mathRandom->getRandomString($this->length) : null; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Service/Anonymize/Anonymizer/AlphaUpper.php: -------------------------------------------------------------------------------- 1 | mathRandom = $mathRandom; 30 | $this->length = $length; 31 | } 32 | 33 | /** 34 | * @inheritdoc 35 | * @throws LocalizedException 36 | */ 37 | public function anonymize($value): ?string 38 | { 39 | return $value ? $this->mathRandom->getRandomString($this->length, Random::CHARS_UPPERS) : null; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Service/Anonymize/Anonymizer/Anonymous.php: -------------------------------------------------------------------------------- 1 | mathRandom = $mathRandom; 30 | } 31 | 32 | /** 33 | * @inheritdoc 34 | * @throws LocalizedException 35 | */ 36 | public function anonymize($value): ?string 37 | { 38 | return $value 39 | ? (new Phrase( 40 | self::PHRASE, 41 | [ 42 | $this->mathRandom->getRandomString(self::PREFIX_LENGTH), 43 | $this->mathRandom->getRandomString(self::SUFFIX_LENGTH), 44 | ] 45 | ))->render() 46 | : null; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Service/Anonymize/Anonymizer/Date.php: -------------------------------------------------------------------------------- 1 | randomDateTime()->format(StdlibDateTime::DATETIME_PHP_FORMAT) : null; 28 | } 29 | 30 | /** 31 | * @return DateTime 32 | * @throws LocalizedException 33 | */ 34 | private function randomDateTime(): DateTime 35 | { 36 | $dateTime = new DateTime(); 37 | $dateTime->setTimestamp(Random::getRandomNumber(self::MIN_TIMESTAMP, self::MAX_TIMESTAMP)); 38 | 39 | return $dateTime; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Service/Anonymize/Anonymizer/Email.php: -------------------------------------------------------------------------------- 1 | mathRandom = $mathRandom; 30 | } 31 | 32 | /** 33 | * @inheritdoc 34 | * @throws LocalizedException 35 | */ 36 | public function anonymize($value): ?string 37 | { 38 | return $value 39 | ? (new Phrase( 40 | self::PHRASE, 41 | [ 42 | $this->mathRandom->getRandomString(self::PREFIX_LENGTH, Random::CHARS_LOWERS), 43 | $this->mathRandom->getRandomString(self::SUFFIX_LENGTH, Random::CHARS_LOWERS), 44 | ] 45 | ))->render() 46 | : null; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Service/Anonymize/Anonymizer/Entity.php: -------------------------------------------------------------------------------- 1 | dataCollector = $dataCollector; 34 | $this->typeResolver = $typeResolver; 35 | $this->hydratorPool = $hydratorPool; 36 | } 37 | 38 | /** 39 | * @inheritdoc 40 | * @throws Exception 41 | */ 42 | public function anonymize($entity): object 43 | { 44 | if (!is_object($entity)) { 45 | throw new InvalidArgumentException( 46 | sprintf('Argument "$entity" must be an object, type "%s" given.', gettype($entity)) 47 | ); 48 | } 49 | 50 | $hydrator = $this->hydratorPool->getHydrator($this->typeResolver->resolve($entity)); 51 | $hydrator->hydrate($entity, $this->dataCollector->collect($entity)); 52 | 53 | return $entity; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Service/Anonymize/Anonymizer/NullValue.php: -------------------------------------------------------------------------------- 1 | min = $min < PHP_INT_MIN ? PHP_INT_MIN : $min; 33 | $this->max = $max !== null && $max > PHP_INT_MAX ? PHP_INT_MAX : $max; 34 | } 35 | 36 | /** 37 | * @inheritdoc 38 | * @throws LocalizedException 39 | */ 40 | public function anonymize($value): ?int 41 | { 42 | return $value ? Random::getRandomNumber($this->min, $this->max) : null; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Service/Anonymize/Anonymizer/Phone.php: -------------------------------------------------------------------------------- 1 | random = $random; 30 | } 31 | 32 | /** 33 | * @throws LocalizedException 34 | */ 35 | public function anonymize($value): array 36 | { 37 | return [sprintf( 38 | '%s %s', 39 | Random::getRandomNumber(self::MIN_NUM, self::MAX_NUM), 40 | $this->random->getRandomString(self::STREET_LENGTH) 41 | )]; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Service/Anonymize/AnonymizerFactory.php: -------------------------------------------------------------------------------- 1 | anonymizers = $anonymizers; 30 | $this->objectManager = $objectManager; 31 | } 32 | 33 | public function get(string $anonymizerCode): AnonymizerInterface 34 | { 35 | if (!isset($this->anonymizers[$anonymizerCode])) { 36 | throw new InvalidArgumentException(sprintf('Unknown anonymizer type "%s".', $anonymizerCode)); 37 | } 38 | 39 | return $this->objectManager->get($this->anonymizers[$anonymizerCode]); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Service/Anonymize/AnonymizerInterface.php: -------------------------------------------------------------------------------- 1 | document = $document; 33 | $this->metadata = $metadata; 34 | $this->anonymizer = $anonymizer; 35 | } 36 | 37 | public function process(string $key, $value): void 38 | { 39 | if (in_array($key, $this->metadata->getAttributes(), true)) { 40 | $this->document->addData($key, $this->anonymizer->anonymize($value)); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Service/Anonymize/Processor/Entity/EntityValue/SmartProcessor.php: -------------------------------------------------------------------------------- 1 | document = $document; 36 | $this->metadata = $metadata; 37 | $this->anonymizerFactory = $anonymizerFactory; 38 | } 39 | 40 | public function process(string $key, $value): void 41 | { 42 | if (in_array($key, $this->metadata->getAttributes(), true)) { 43 | $this->document->addData( 44 | $key, 45 | $this->anonymizerFactory->get( 46 | $this->metadata->getAnonymizerStrategiesByAttributes()[$key] ?? AnonymizerFactory::DEFAULT_KEY 47 | )->anonymize($value) 48 | ); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Service/Erase/MetadataInterface.php: -------------------------------------------------------------------------------- 1 | processorResolver = $processorResolver; 32 | $this->eraseComponents = $eraseComponents; 33 | } 34 | 35 | public function execute(int $entityId): bool 36 | { 37 | $components = array_column($this->eraseComponents->toOptionArray(), 'value'); 38 | 39 | foreach ($components as $component) { 40 | $processor = $this->processorResolver->resolve($component); 41 | if (!$processor->execute($entityId)) { 42 | return false; 43 | } 44 | } 45 | 46 | return true; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Service/Erase/ProcessorFactory.php: -------------------------------------------------------------------------------- 1 | erasers = $erasers; 31 | $this->objectManager = $objectManager; 32 | } 33 | 34 | public function get(string $entityType): ProcessorInterface 35 | { 36 | if (!isset($this->erasers[$entityType])) { 37 | throw new InvalidArgumentException(sprintf('Unknown eraser for entity type "%s".', $entityType)); 38 | } 39 | 40 | return $this->objectManager->get($this->erasers[$entityType]); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Service/Erase/ProcessorInterface.php: -------------------------------------------------------------------------------- 1 | processors = $processors; 30 | $this->objectManager = $objectManager; 31 | } 32 | 33 | public function resolve(string $component): ProcessorInterface 34 | { 35 | if (!isset($this->processors[$component])) { 36 | throw new InvalidArgumentException(sprintf('Unknown processor type "%s".', $component)); 37 | } 38 | 39 | return $this->objectManager->get($this->processors[$component]); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Service/Erase/ProcessorResolver/ProcessorResolverStrategy.php: -------------------------------------------------------------------------------- 1 | resolverFactory = $resolverFactory; 29 | $this->metadata = $metadata; 30 | } 31 | 32 | public function resolve(string $component): ProcessorInterface 33 | { 34 | return $this->resolverFactory->get($this->metadata->getComponentProcessor($component))->resolve($component); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Service/Erase/ProcessorResolverFactory.php: -------------------------------------------------------------------------------- 1 | processorResolvers = $processorResolvers; 35 | $this->objectManager = $objectManager; 36 | } 37 | 38 | public function get(string $processorCode): ProcessorResolverInterface 39 | { 40 | if (!isset($this->processorResolvers[$processorCode])) { 41 | throw new InvalidArgumentException(sprintf('Unknown renderer type "%s".', $processorCode)); 42 | } 43 | 44 | return $this->objectManager->get($this->processorResolvers[$processorCode]); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Service/Erase/ProcessorResolverInterface.php: -------------------------------------------------------------------------------- 1 | dataCollector = $dataCollector; 21 | } 22 | 23 | protected function collectData(object $entity): array 24 | { 25 | return $this->dataCollector->collect($entity); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Service/Export/Processor/CompositeProcessor.php: -------------------------------------------------------------------------------- 1 | processors = $processors; 24 | } 25 | 26 | public function execute(int $entityId, array $data): array 27 | { 28 | return array_reduce( 29 | $this->processors, 30 | static function (array $data, ProcessorInterface $processor) use ($entityId): array { 31 | return $processor->execute($entityId, $data); 32 | }, 33 | $data 34 | ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Service/Export/Processor/Entity/EntityValue/DataProcessor.php: -------------------------------------------------------------------------------- 1 | document = $document; 29 | $this->metadata = $metadata; 30 | } 31 | 32 | public function process(string $key, $value): void 33 | { 34 | if (in_array($key, $this->metadata->getAttributes(), true)) { 35 | $this->document->addData($key, $value); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Service/Export/Processor/Entity/EntityValue/EntityProcessor.php: -------------------------------------------------------------------------------- 1 | document = $document; 33 | $this->metadata = $metadata; 34 | $this->dataCollector = $dataCollector; 35 | } 36 | 37 | public function process(string $key, $value): void 38 | { 39 | if (in_array($key, $this->metadata->getAttributes(), true)) { 40 | $this->document->addData($key, $this->dataCollector->collect($value)); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Service/Export/ProcessorFactory.php: -------------------------------------------------------------------------------- 1 | exporters = $exporters; 35 | $this->objectManager = $objectManager; 36 | } 37 | 38 | public function get(string $entityType): ProcessorInterface 39 | { 40 | if (!isset($this->exporters[$entityType])) { 41 | throw new InvalidArgumentException(sprintf('Unknown exporter for entity type "%s".', $entityType)); 42 | } 43 | 44 | return $this->objectManager->get($this->exporters[$entityType]); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Service/Export/ProcessorInterface.php: -------------------------------------------------------------------------------- 1 | fileSystem = $filesystem; 26 | $this->fileExtension = $fileExtension; 27 | } 28 | 29 | /** 30 | * @inheritdoc 31 | * @throws FileSystemException 32 | */ 33 | public function saveData(string $fileName, array $data): string 34 | { 35 | $fileName .= '.' . $this->fileExtension; 36 | $tmpWrite = $this->fileSystem->getDirectoryWrite(DirectoryList::TMP); 37 | $tmpWrite->writeFile($fileName, $this->render($data)); 38 | 39 | return $tmpWrite->getAbsolutePath($fileName); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Service/Export/Renderer/CsvRenderer.php: -------------------------------------------------------------------------------- 1 | $value) { 29 | $csv .= is_array($value) 30 | ? $key . ',' . rtrim($this->render($value), ',') . PHP_EOL 31 | : '"' . str_replace('"', '""', $value) . '",'; 32 | } 33 | 34 | return $csv; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Service/Export/Renderer/HtmlRenderer/LayoutInitiatorInterface.php: -------------------------------------------------------------------------------- 1 | jsonSerializer = $jsonSerializer; 22 | parent::__construct($filesystem, 'json'); 23 | } 24 | 25 | public function render(array $data): string 26 | { 27 | return $this->jsonSerializer->serialize($data); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Service/Export/Renderer/PdfRenderer.php: -------------------------------------------------------------------------------- 1 | htmlRenderer = $htmlRenderer; 23 | parent::__construct($filesystem, 'pdf'); 24 | } 25 | 26 | /** 27 | * @inheritdoc 28 | * @throws Exception 29 | */ 30 | public function render(array $data): string 31 | { 32 | $pdf = new TCPDF(); 33 | $pdf->AddPage('P', 'A4'); 34 | $pdf->writeHTML($this->htmlRenderer->render($data)); 35 | 36 | return $pdf->Output('', 'S'); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Service/Export/Renderer/XmlRenderer.php: -------------------------------------------------------------------------------- 1 | convertArray = $convertArray; 28 | $this->rootName = $rootName; 29 | parent::__construct($filesystem, 'xml'); 30 | } 31 | 32 | /** 33 | * @inheritdoc 34 | * @throws LocalizedException 35 | */ 36 | public function render(array $data): string 37 | { 38 | return $this->convertArray->assocToXml($data, $this->rootName)->saveXML(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Service/Export/RendererFactory.php: -------------------------------------------------------------------------------- 1 | renderers = $renderers; 31 | $this->objectManager = $objectManager; 32 | } 33 | 34 | public function get(string $rendererCode): RendererInterface 35 | { 36 | if (!isset($this->renderers[$rendererCode])) { 37 | throw new InvalidArgumentException(sprintf('Unknown renderer type "%s".', $rendererCode)); 38 | } 39 | 40 | return $this->objectManager->get($this->renderers[$rendererCode]); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Service/Export/RendererInterface.php: -------------------------------------------------------------------------------- 1 | privacyMessage = $privacyMessage; 20 | } 21 | 22 | public function getTemplate(string $defaultTemplate, string $customTemplate): string 23 | { 24 | return $this->privacyMessage->isEnabled() ? $customTemplate : $defaultTemplate; 25 | } 26 | 27 | public function getLearnMoreUrl(): ?string 28 | { 29 | return $this->privacyMessage->getLearnMoreUrl(); 30 | } 31 | 32 | public function getNoticeHtml(): string 33 | { 34 | return $this->privacyMessage->getDisclosureInformationHtml(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /ViewModel/Customer/Guest/EraseDataProvider.php: -------------------------------------------------------------------------------- 1 | eraseEntityChecker = $eraseEntityChecker; 36 | $this->registry = $registry; 37 | } 38 | 39 | public function canCancel(): bool 40 | { 41 | return $this->canCancel ?? 42 | $this->canCancel = $this->eraseEntityChecker->canCancel($this->currentOrderId(), 'order'); 43 | } 44 | 45 | public function canCreate(): bool 46 | { 47 | return $this->canCreate ?? 48 | $this->canCreate = $this->eraseEntityChecker->canCreate($this->currentOrderId(), 'order'); 49 | } 50 | 51 | private function currentOrderId(): int 52 | { 53 | /** @var OrderInterface $order */ 54 | $order = $this->registry->registry('current_order'); 55 | 56 | return (int) $order->getEntityId(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /ViewModel/Customer/Guest/ExportDataProvider.php: -------------------------------------------------------------------------------- 1 | exportEntityChecker = $exportEntityChecker; 36 | $this->registry = $registry; 37 | } 38 | 39 | public function hasExport(): bool 40 | { 41 | return $this->isExportEntityExists ?? 42 | $this->isExportEntityExists = $this->exportEntityChecker->exists($this->currentOrderId(), 'order'); 43 | } 44 | 45 | public function isExported(): bool 46 | { 47 | return $this->isExported ?? 48 | $this->isExported = $this->exportEntityChecker->isExported($this->currentOrderId(), 'order'); 49 | } 50 | 51 | private function currentOrderId(): int 52 | { 53 | /** @var OrderInterface $order */ 54 | $order = $this->registry->registry('current_order'); 55 | 56 | return (int) $order->getEntityId(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /ViewModel/Customer/Privacy/EraseCustomerDataProvider.php: -------------------------------------------------------------------------------- 1 | eraseEntityChecker = $eraseEntityChecker; 38 | $this->session = $session; 39 | } 40 | 41 | public function canCancel(): bool 42 | { 43 | return $this->canCancel ??= $this->eraseEntityChecker->canCancel($this->currentCustomerId(), 'customer'); 44 | } 45 | 46 | public function canCreate(): bool 47 | { 48 | return $this->canCreate ??= $this->eraseEntityChecker->canCreate($this->currentCustomerId(), 'customer'); 49 | } 50 | 51 | private function currentCustomerId(): int 52 | { 53 | return (int) $this->session->getCustomerId(); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /ViewModel/Customer/Privacy/ExportCustomerDataProvider.php: -------------------------------------------------------------------------------- 1 | exportEntityChecker = $exportEntityChecker; 38 | $this->session = $session; 39 | } 40 | 41 | public function hasExport(): bool 42 | { 43 | return $this->isExportEntityExists ??= $this->exportEntityChecker->exists($this->currentCustomerId(), 'customer'); 44 | } 45 | 46 | public function isExported(): bool 47 | { 48 | return $this->isExported ??= $this->exportEntityChecker->isExported($this->currentCustomerId(), 'customer'); 49 | } 50 | 51 | private function currentCustomerId(): int 52 | { 53 | return (int) $this->session->getCustomerId(); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /ViewModel/Customer/Privacy/ExportDataProvider.php: -------------------------------------------------------------------------------- 1 | scopeConfig = $scopeConfig; 31 | $this->blockFactory = $blockFactory; 32 | } 33 | 34 | public function getExportInformationHtml(): string 35 | { 36 | return $this->exportInformation ??= $this->blockFactory->createBlock( 37 | BlockByIdentifier::class, 38 | ['data' => ['identifier' => (string) $this->scopeConfig->getValue( 39 | self::CONFIG_PATH_EXPORT_INFORMATION_BLOCK, 40 | ScopeInterface::SCOPE_STORE 41 | )]] 42 | )->toHtml(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /ViewModel/Customer/Privacy/SettingsDataProvider.php: -------------------------------------------------------------------------------- 1 | scopeConfig = $scopeConfig; 31 | $this->blockFactory = $blockFactory; 32 | } 33 | 34 | public function getPrivacyInformationHtml(): string 35 | { 36 | return $this->informationHtml ??= $this->blockFactory->createBlock( 37 | BlockByIdentifier::class, 38 | ['data' => ['identifier' => (string) $this->scopeConfig->getValue( 39 | self::CONFIG_PATH_GENERAL_INFORMATION_BLOCK, 40 | ScopeInterface::SCOPE_STORE 41 | )]] 42 | )->toHtml(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /etc/adminhtml/menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /etc/adminhtml/routes.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /etc/adminhtml/system.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /etc/adminhtml/system/action.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 |
10 | separator-top 11 | 12 | opengento_gdpr 13 | Opengento_Gdpr::config 14 | 15 | 16 | 17 |
18 |
19 | -------------------------------------------------------------------------------- /etc/cron_groups.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 10 11 | 20 12 | 10 13 | 10 14 | 60 15 | 600 16 | 0 17 | 18 | 19 | -------------------------------------------------------------------------------- /etc/crontab.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | gdpr/erasure/entity_schedule 12 | 13 | 14 | gdpr/erasure/entity_max_age_schedule 15 | 16 | 17 | gdpr/export/entity_schedule 18 | 19 | 20 | gdpr/export/entity_expired_schedule 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /etc/events.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /etc/frontend/routes.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /etc/module.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /registration.php: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /view/adminhtml/layout/gdpr_action_new.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /view/adminhtml/layout/sales_order_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /view/adminhtml/ui_component/customer_form.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 |
9 | 10 | 11 |