Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
## next feature release
* Refactor DataSourceBundle: remove eval-based EventProcessor (security), simplify driver abstraction, add PropertyAdapter strategy for flexible property storage ([PR#155](https://github.com/mapbender/mapbender-digitizer/pull/155)) **BREAKING**: Oracle/SQLite spatial support dropped, deprecated services removed — see `EVENT-MIGRATION.md`
* Migrate from jQuery UI dialogs to Mapbender.Popup with improved mobile support ([PR#149](https://github.com/mapbender/mapbender-digitizer/pull/149))
* Add dynamic expression support for labels, text fields, and popup titles (template literal syntax `${data.property}`) ([PR#149](https://github.com/mapbender/mapbender-digitizer/pull/149))
* Modernize JavaScript codebase (ES6 classes, singleton pattern for better extensibility) ([PR#149](https://github.com/mapbender/mapbender-digitizer/pull/149))
Expand Down
6 changes: 4 additions & 2 deletions src/Mapbender/DataManagerBundle/Component/SchemaFilter.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
use Mapbender\DataManagerBundle\Exception\ConfigurationErrorException;
use Mapbender\DataManagerBundle\Exception\UnknownSchemaException;
use Mapbender\DataSourceBundle\Component\DataStore;
use Mapbender\DataSourceBundle\Component\FeatureType;
use Mapbender\DataSourceBundle\Component\RepositoryRegistry;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;

Expand Down Expand Up @@ -369,6 +368,7 @@ public function getUploadPaths(Element $element, $schemaName, $fieldName)
*/
public function processSchemaBaseConfig(array $schemaConfig, $schemaName)
{
$defaults = static::getConfigDefaults();
// Re-merge "popup" sub-array
if (!empty($schemaConfig['popup']) && !empty($defaults['popup'])) {
$schemaConfig['popup'] = array_replace($defaults['popup'], $schemaConfig['popup']);
Expand Down Expand Up @@ -425,7 +425,9 @@ protected function normalizeColumnsConfigs(array $rawColumns)
protected function getExtendedUploadsBasePath($storeConfig)
{
if (null === $this->isFeatureTypeRegistry) {
$this->isFeatureTypeRegistry = (($this->registry->dataStoreFactory($storeConfig)) instanceof FeatureType);
// Detect FeatureType by config key presence instead of instantiating a repository
$this->isFeatureTypeRegistry = !empty($storeConfig['geomField'])
|| !empty($storeConfig['srid']);
}
return $this->uploadsBasePath . '/' . ($this->isFeatureTypeRegistry ? 'featureTypes' : 'ds-uploads');
}
Expand Down
71 changes: 68 additions & 3 deletions src/Mapbender/DataManagerBundle/Resources/public/MbDataManager.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
(function() {

const DEPRECATED_EVENT_HOOKS = [
'onBeforeSave', 'onAfterSave', 'onBeforeUpdate', 'onAfterUpdate',
'onBeforeInsert', 'onAfterInsert', 'onBeforeRemove', 'onAfterRemove',
'onBeforeSearch', 'onAfterSearch'
];

const DEPRECATED_EVENTS_WARNING =
'The eval-based event system (EventProcessor) was removed because it allowed\n' +
'arbitrary PHP code execution from YAML/database configuration — a significant\n' +
'security risk. Any logic in these hooks is silently ignored.\n\n' +
'MIGRATION: Use database triggers, Symfony EventDispatcher, or DataStore\n' +
'subclass overrides instead. See EVENT-MIGRATION.md for a complete guide.\n\n' +
'To suppress this warning, remove the "events" key from the dataStore/featureType\n' +
'configuration of the affected schemas.';

class MbDataManager extends MapbenderElement {
constructor(configuration, $element) {
super(configuration, $element);
Expand Down Expand Up @@ -56,6 +71,7 @@
}
}
this.tableRenderer = this._createTableRenderer();
this._warnDeprecatedEvents();
this._initializeEvents();
this._afterCreate();
}
Expand Down Expand Up @@ -165,6 +181,44 @@
this._start();
}

/**
* Checks all schema configurations for deprecated server-side event hooks
* (onBeforeSave, onAfterSave, etc.) and displays a prominent console warning.
* These eval-based PHP events were removed for security reasons and are silently
* ignored by the backend. See EVENT-MIGRATION.md for migration instructions.
* @private
*/
_warnDeprecatedEvents() {
const schemaNames = Object.keys(this.options.schemes);
const warnings = [];
for (const schemaName of schemaNames) {
const schema = this.options.schemes[schemaName];
if (schema.combine) continue;
const dsConfig = this._getDataStoreFromSchema(schema);
if (dsConfig && dsConfig.events && typeof dsConfig.events === 'object') {
const configuredHooks = Object.keys(dsConfig.events).filter(function(k) {
return DEPRECATED_EVENT_HOOKS.indexOf(k) !== -1 && dsConfig.events[k];
});
if (configuredHooks.length) {
warnings.push({schema: schemaName, hooks: configuredHooks});
}
}
}
if (warnings.length) {
const elementTitle = this.$element.attr('data-title') || this.$element.attr('id');
console.warn(
'%c⚠ DEPRECATED EVENT HOOKS DETECTED — ' + elementTitle + ' %c\n\n' +
'The following server-side event hooks are configured but will NOT be executed:\n\n' +
warnings.map(function(w) {
return ' Schema "' + w.schema + '": ' + w.hooks.join(', ');
}).join('\n') + '\n\n' +
DEPRECATED_EVENTS_WARNING,
'background: #ff6600; color: white; font-size: 14px; font-weight: bold; padding: 4px 8px;',
'color: #cc5500; font-size: 12px;'
);
}
}

/**
* Loads and displays data from initially selected schema.
* Unraveled from _create for child classes need to act after our initialization,
Expand Down Expand Up @@ -384,6 +438,7 @@
* @private
*/
_saveEvent(schema, dataItem, originalId) {
/** @var {DataManagerSaveEventData} eventData */
const eventData = {
item: dataItem,
itemId: this._getUniqueItemId(dataItem),
Expand Down Expand Up @@ -589,7 +644,7 @@
const $scope = $('.popupContent', this.$element);
const saved = widget._submitFormData(schema, $scope, dataItem);
if (saved) {
saved.then(function() {
saved.then(function () {
widget._closeCurrentPopup();
});
}
Expand All @@ -601,12 +656,22 @@
text: Mapbender.trans('mb.actions.delete'),
title: Mapbender.trans('mb.data-manager.actions.delete_tooltip'),
'class': 'btn btn-danger',
click: function() {
click: function () {
widget._closeCurrentPopup();
widget.removeData(schema, dataItem);
}
});
}
var closeText = buttons.length && 'mb.actions.cancel' || 'mb.actions.close';
var closeTooltip = buttons.length && 'mb.data-manager.actions.cancel_tooltip' || 'mb.data-manager.actions.close_tooltip';
buttons.push({
text: Mapbender.trans(closeText),
title: Mapbender.trans(closeTooltip),
'class': 'btn btn-light',
click: function () {
widget._cancelForm(schema, dataItem);
}
});
return buttons;
}

Expand Down Expand Up @@ -820,7 +885,7 @@
$loadingIndicator.css({ opacity: 0 });
});
}
jqXhr.fail(this._onAjaxError);
jqXhr.fail(this._onAjaxError.bind(this));
return jqXhr;
}

Expand Down
Loading