webexmachina / contao-personal-data-manager
Personal Data Manager bundle for Contao Open Source CMS
Installs: 186
Dependents: 4
Suggesters: 0
Security: 0
Stars: 0
Watchers: 2
Forks: 0
Type:contao-bundle
Requires
- php: ^7.4 || ^8.2
- ext-json: *
- ext-zip: *
- contao/core-bundle: ^4.13 || ^5.0
- webexmachina/contao-utils: ^2.0
Requires (Dev)
- codeception/codeception: ^4
- codeception/module-asserts: ^1.0.0
- codeception/module-phpbrowser: ^1.0.0
- codeception/module-webdriver: ^2.0
- contao/manager-plugin: ^2.0
- contao/test-case: ~4
- phpunit/phpunit: ^9.0
- rector/rector: ^1.0
Conflicts
- contao/manager-plugin: <2.0 || >=3.0
README
The purpose of this project is to allow a better handling of personal data in Contao CMS.
Warning
Be aware that this bundle alters data registered in the database. So all entities managed by this bundles will have the encrypted data version in their database tables. Retrieving those data thanks to a configured model (see below) will not make a difference as before. However, SQL queries to directly work with the database could be a problem, as they will work on encrypted data.
eg : if you configure your Member
model to be managed by this bundle, you will have to create an EventListener
on the SendNewsletterEvent
event, as it retrieves the newsletter recipients' data with an SQL query directly from tl_member
instead of using the model.
See this example.
Functionnalities
- Store personal data
- Retrieve personal data
System requirements
- Contao 4.13
Installation
Clone the extension from Packagist (Contao Manager)
Configuration
First, you will need to define an encryption key. Then, models (and their associated DCA) need to be adjusted.
Encryption key
As this bundle uses plenta/contao-encryption
, an encryption key needs to be set. When the bundle is loaded, it checks wether the encryption key plenta_contao_encryption.encryption_key
is set or not.
If not, it will look for ours, named wem_pdm_encryption_key
, in the /system/config/localconfig.php
file. And apply it to the plenta_contao_encryption.encryption_key
container parameter.
Model
Use the WEM\PersonalDataManagerBundle\Model\Traits\PersonalDataTrait
trait in your Model and define the mandatories static properties.
Eg :
<?php use WEM\PersonalDataManagerBundle\Model\Traits\PersonalDataTrait as PDMTrait; class MyModel { use PDMTrait; /** @var array Fields to be managed by the Personal Data Manager */ protected static $personalDataFieldsNames = ['myField']; /** @var array Default values for fields to be managed by the Personal Data Manager */ protected static $personalDataFieldsDefaultValues = ['myField' => 'managed_by_pdm']; /** @var array Values for fields to be managed by the Personal Data Manager when anonymized */ protected static $personalDataFieldsAnonymizedValues = ['myField' => 'Anonymized']; /** @var string Field to be used as pid by the Personal Data Manager */ protected static $personalDataPidField = 'id'; /** @var string Field to be used as email by the Personal Data Manager */ protected static $personalDataEmailField = 'email'; /** @var string ptable to be used by the Personal Data Manager */ protected static $personalDataPtable = 'tl_my_table';
This way, when saving a MyModel
object, the real value of MyField
will not be stored in the MyModel
's table but in the Personal Data Manager one, and be associated with the corresponding MyModel
's id and with the defined $personalDataPtable
. MyField
'stored value in tl_my_table
will be the one defined in MyMode::personalDataFieldsDefaultValues
('managed_by_pdm' in our example).
And when retrieving the MyModel
object from the database, the Personal Data Manager will automatically fetch the associated personal data's and fill the MyModel
's object accordingly.
Custom Table Driver
This bundles provides a Trait to allow grouping in back-end list to work. To make it work, you will need to define a custom DCA Table Driver (if you already have a custom one, you will still have to create another one, as the trait assume it works on a DCA with a model configured to use the personal data manager).
<?php declare(strict_types=1); namespace Your\Namespace; use WEM\PersonalDataManagerBundle\Dca\Driver\PDMDCTableTrait; class DC_Table extends \Contao\DC_Table { use PDMDCTableTrait; }
DCA
In your DCA, your need to add the following callbacks & driver:
use Path\To\Your\Custom\Dca\Driver\DC_Table_Custom; $GLOBALS['TL_DCA']['tl_my_table'] = [ 'config'=>[ // ... 'dataContainer' => DC_Table_Custom::class, 'ondelete_callback' => [['wem.personal_data_manager.dca.config.callback.delete', '__invoke']], 'onshow_callback' => [['wem.personal_data_manager.dca.config.callback.show', '__invoke']], 'onsubmit_callback' => [['wem.personal_data_manager.dca.config.callback.submit', '__invoke']], ], 'list'=>[ 'label' => [ // ... 'label_callback' => ['wem.personal_data_manager.dca.listing.callback.list_label_label_for_list', '__invoke'], ], ], 'fields'=>[ 'myField'=>[ // ... 'load_callback' => [['wem.personal_data_manager.dca.field.callback.load', '__invoke']], ] ] ]
This way, editing your records in back-end will work with the same as with the model.
⚠️ If the data you are working on can be edited throught the contao's Personal data
front end module, you will need to extends the load
callbacks to precise on which table & field the front end callback should work !
PHP callback
<?php declare(strict_types=1); namespace Your\Namespace\Dca\Field\Callback; use WEM\PersonalDataManagerBundle\Dca\Field\Callback\Load as PdmCallback; // or Save class Load { /** @var WEM\PersonalDataManagerBundle\Dca\Field\Callback\Load */ private $pdmCallback; /** @var string */ private $frontendField; /** @var string */ private $table; public function __construct( PdmCallback $pdmCallback, string $frontendField, string $table ) { $this->pdmCallback = $pdmCallback; $this->frontendField = $frontendField; $this->table = $table; $this->pdmCallback->setFrontendField($this->frontendField)->setTable($this->table); } public function __invoke() { return $this->pdmCallback->__invoke(...\func_get_args()); } }
YAML config file (like your/bundle/src/Resources/contao/config/services.yml
)
services: your.bundle.dca.field.callback.load.tl_my_table.my_field: class: Your\Namespace\Dca\Field\Callback\Load arguments: $pdmCallback: '@wem.personal_data_manager.dca.field.callback.load' $frontendField: 'myField' $table: 'tl_my_table' public: true
DCA file
$GLOBALS['TL_DCA']['tl_my_table']['fields']['myField']['load_callback'][] = ['your.bundle.dca.field.callback.load.tl_my_table.my_field', '__invoke'];
Usage
Both a back-end entry and a front-end module are provided to allow admin and users to show, export or anonymize their personal data.
Back-end
The user can enter an email address and all associated personal data are displayed. From there, the user can show, export or anonymize them.
Front-end
The front-end module needs to be registered in your theme.
The user has to enter an email address in the displayed form. An email containing a link to the current page with a token will be sent to the email address filled in the form. The token is valid for 5 minutes upon its creation. By clicking on the link provided in the email, the user will be redirected to the page where the front-end module lies, with the token as a GET parameter. From there, the user can show, export or anonymize their personal data.
Each action from the user make its token valid for 5 more minutes.
Hooks
Multiple hooks are available to customize the bundle. The list is available here.
Documentation
License
This extension is licensed under the terms of the Apache License 2.0. The full license text is available in the main folder.
Getting support
Visit the support page to submit an issue or just get in touch :)
Installing from Git
You can get the extension with this repository URL : Github