From b1ef60411a160393c45b9ddb99b2e8fcc0cfbc2c Mon Sep 17 00:00:00 2001 From: Bert Oost Date: Sat, 15 Mar 2014 02:15:18 +0100 Subject: [PATCH] Updated for Redirector 2.0 + many (UI) fixes and new features --- _build/build.schema.php | 100 ++------ _build/build.transport.php | 57 ++++- _build/data/transport.menu.php | 2 +- _build/data/transport.plugins.php | 36 ++- _build/data/transport.settings.php | 27 ++ _build/resolvers/resolve.dbchanges.php | 28 ++ assets/components/redirector/css/mgr.css | 30 +++ assets/components/redirector/js/mgr/combos.js | 51 ++++ .../redirector/js/mgr/redirector.js | 0 .../redirector/js/mgr/sections/index.js | 0 .../js/mgr/utils/fileuploadfield.xtype.js | 184 ++++++++++++++ .../redirector/js/mgr/widgets/home.panel.js | 107 +++++++- .../js/mgr/widgets/redirects.grid.js | 239 ++++++++++++------ .../redirector/controllers/home.class.php | 19 ++ .../redirector/controllers/index.class.php | 35 +++ .../redirector/controllers/index.php | 8 - .../redirector/controllers/mgr/header.php | 18 -- .../redirector/controllers/mgr/index.php | 14 - core/components/redirector/docs/changelog.txt | 11 + .../elements/plugins/plugin.redirector.php | 151 ++++++++--- core/components/redirector/index.php | 3 - .../redirector/lexicon/de/default.inc.php | 6 +- .../redirector/lexicon/en/default.inc.php | 28 +- .../redirector/lexicon/fr/default.inc.php | 2 +- .../redirector/lexicon/nl/default.inc.php | 14 +- .../redirector/lexicon/ru/default.inc.php | 6 +- .../model/redirector/metadata.mysql.php | 8 + .../model/redirector/modredirect.class.php | 0 .../redirector/mysql/modredirect.class.php | 0 .../redirector/mysql/modredirect.map.inc.php | 71 +++++- .../model/redirector/redirector.class.php | 31 +-- .../redirectorconnectorrequest.class.php | 49 ---- .../redirectorcontrollerrequest.class.php | 56 ---- .../redirector/sqlsrv/modredirect.class.php | 0 .../redirector/sqlsrv/modredirect.map.inc.php | 35 +++ .../model/schema/redirector.mysql.schema.xml | 14 +- .../model/schema/redirector.sqlsrv.schema.xml | 12 +- .../processors/mgr/contexts/getlist.class.php | 22 ++ .../processors/mgr/import/import.class.php | 141 +++++++++++ .../processors/mgr/redirect/create.class.php | 60 +++-- .../processors/mgr/redirect/getlist.class.php | 114 +++++---- .../processors/mgr/redirect/remove.class.php | 22 +- .../processors/mgr/redirect/update.class.php | 63 +++-- .../mgr/redirect/updatefromgrid.class.php | 35 +-- .../mgr/resources/getlist.class.php | 29 +++ core/components/redirector/templates/home.tpl | 1 + 46 files changed, 1405 insertions(+), 534 deletions(-) mode change 100644 => 100755 _build/build.schema.php mode change 100644 => 100755 _build/build.transport.php mode change 100644 => 100755 _build/data/transport.menu.php mode change 100644 => 100755 _build/data/transport.plugins.php create mode 100755 _build/data/transport.settings.php create mode 100755 _build/resolvers/resolve.dbchanges.php create mode 100755 assets/components/redirector/css/mgr.css create mode 100755 assets/components/redirector/js/mgr/combos.js mode change 100644 => 100755 assets/components/redirector/js/mgr/redirector.js mode change 100644 => 100755 assets/components/redirector/js/mgr/sections/index.js create mode 100755 assets/components/redirector/js/mgr/utils/fileuploadfield.xtype.js mode change 100644 => 100755 assets/components/redirector/js/mgr/widgets/redirects.grid.js create mode 100755 core/components/redirector/controllers/home.class.php create mode 100755 core/components/redirector/controllers/index.class.php delete mode 100644 core/components/redirector/controllers/index.php delete mode 100644 core/components/redirector/controllers/mgr/header.php delete mode 100644 core/components/redirector/controllers/mgr/index.php mode change 100644 => 100755 core/components/redirector/docs/changelog.txt mode change 100644 => 100755 core/components/redirector/elements/plugins/plugin.redirector.php delete mode 100644 core/components/redirector/index.php mode change 100644 => 100755 core/components/redirector/lexicon/de/default.inc.php mode change 100644 => 100755 core/components/redirector/lexicon/en/default.inc.php mode change 100644 => 100755 core/components/redirector/lexicon/nl/default.inc.php create mode 100644 core/components/redirector/model/redirector/metadata.mysql.php mode change 100644 => 100755 core/components/redirector/model/redirector/modredirect.class.php mode change 100644 => 100755 core/components/redirector/model/redirector/mysql/modredirect.class.php mode change 100644 => 100755 core/components/redirector/model/redirector/mysql/modredirect.map.inc.php mode change 100644 => 100755 core/components/redirector/model/redirector/redirector.class.php delete mode 100644 core/components/redirector/model/redirector/request/redirectorconnectorrequest.class.php delete mode 100644 core/components/redirector/model/redirector/request/redirectorcontrollerrequest.class.php mode change 100644 => 100755 core/components/redirector/model/redirector/sqlsrv/modredirect.class.php mode change 100644 => 100755 core/components/redirector/model/redirector/sqlsrv/modredirect.map.inc.php mode change 100644 => 100755 core/components/redirector/model/schema/redirector.mysql.schema.xml mode change 100644 => 100755 core/components/redirector/model/schema/redirector.sqlsrv.schema.xml create mode 100755 core/components/redirector/processors/mgr/contexts/getlist.class.php create mode 100755 core/components/redirector/processors/mgr/import/import.class.php create mode 100755 core/components/redirector/processors/mgr/resources/getlist.class.php create mode 100755 core/components/redirector/templates/home.tpl diff --git a/_build/build.schema.php b/_build/build.schema.php old mode 100644 new mode 100755 index a46daa6..42a01d8 --- a/_build/build.schema.php +++ b/_build/build.schema.php @@ -1,103 +1,47 @@ initialize('mgr'); $modx->loadClass('transport.modPackageBuilder','',false, true); -echo '
'; /* used for nice formatting of log messages */
 $modx->setLogLevel(modX::LOG_LEVEL_INFO);
-$modx->setLogTarget('ECHO');
+$modx->setLogTarget(XPDO_CLI_MODE ? 'ECHO' : 'HTML');
 
+$dbDriver = $modx->config['dbtype'];
 $root = dirname(dirname(__FILE__)).'/';
 $sources = array(
     'root' => $root,
     'core' => $root.'core/components/redirector/',
     'model' => $root.'core/components/redirector/model/',
     'schema' => $root.'core/components/redirector/model/schema/',
-    'schema_file' => $root.'core/components/redirector/model/schema/redirector.mysql.schema.xml',
+    'schema_file' => $root.'core/components/redirector/model/schema/redirector.'.$dbDriver.'.schema.xml',
     'assets' => $root.'assets/components/redirector/',
 );
-foreach (array('mysql', 'sqlsrv') as $driver) {
-    $xpdo= new xPDO(
-        $properties["{$driver}_string_dsn_nodb"],
-        $properties["{$driver}_string_username"],
-        $properties["{$driver}_string_password"],
-        $properties["{$driver}_array_options"],
-        $properties["{$driver}_array_driverOptions"]
-    );
-    $xpdo->setPackage('modx', dirname(XPDO_CORE_PATH) . '/model/');
-    $xpdo->setDebug(true);
-
-    $manager= $xpdo->getManager();
-    $generator= $manager->getGenerator();
 
-    $manager= $xpdo->getManager();
-    $generator= $manager->getGenerator();
+$manager= $modx->getManager();
+$generator= $manager->getGenerator();
 
-$generator->classTemplate= <<__construct(\$xpdo);
-    }
-    function __construct(& \$xpdo) {
-        parent :: __construct(\$xpdo);
-    }
-}
-?>
-EOD;
-$generator->platformTemplate= <<__construct(\$xpdo);
-    }
-    function __construct(& \$xpdo) {
-        parent :: __construct(\$xpdo);
-    }
-}
-?>
-EOD;
-$generator->mapHeader= <<parseSchema($sources['model'] . 'schema/'.PKG_NAME_LOWER.'.'.$driver.'.schema.xml', $sources['model']);
+if(!is_dir($sources['model'])) {
+	$modx->log(modX::LOG_LEVEL_ERROR,'Model directory not found ('.$sources['model'].')!');
+	die();
 }
 
+if(!file_exists($sources['schema_file'])) {
+	$modx->log(modX::LOG_LEVEL_ERROR,'Schema file not found!');
+	die();
+}
 
-$mtime= microtime();
-$mtime= explode(" ", $mtime);
-$mtime= $mtime[1] + $mtime[0];
-$tend= $mtime;
-$totalTime= ($tend - $tstart);
-$totalTime= sprintf("%2.4f s", $totalTime);
+$generator->parseSchema($sources['schema_file'], $sources['model']);
 
-echo "\nExecution time: {$totalTime}\n";
+$modx->addPackage(PKG_NAME_LOWER, $sources['model']);
+$manager->createObjectContainer('modRedirect');
 
-exit ();
\ No newline at end of file
+$manager->addField('modRedirect', 'context_key', array('after' => 'target'));
+$manager->addIndex('modRedirect', 'pattern_context');
+$manager->removeIndex('modRedirect', 'pattern');
diff --git a/_build/build.transport.php b/_build/build.transport.php
old mode 100644
new mode 100755
index d1f211b..cea2ee6
--- a/_build/build.transport.php
+++ b/_build/build.transport.php
@@ -14,7 +14,7 @@
 /* define package names */
 define('PKG_NAME','Redirector');
 define('PKG_NAME_LOWER','redirector');
-define('PKG_VERSION','1.0.3');
+define('PKG_VERSION','2.0.0');
 define('PKG_RELEASE','pl');
 
 /* define build paths */
@@ -50,7 +50,7 @@
 $builder->registerNamespace(PKG_NAME_LOWER,false,true,'{core_path}components/'.PKG_NAME_LOWER.'/');
 
 /* add plugin */
-$modx->log(modX::LOG_LEVEL_INFO,'Packaging in plugin...');
+$modx->log(modX::LOG_LEVEL_INFO,'Packaging in Redirector plugin...');
 $plugin= $modx->newObject('modPlugin');
 $plugin->fromArray(array(
     'id' => 1,
@@ -58,15 +58,28 @@
     'description' => 'Handles site redirects.',
     'plugincode' => getSnippetContent($sources['elements'].'plugins/plugin.redirector.php'),
 ),'',true,true);
-    $events = array();
-    $events['OnPageNotFound']= $modx->newObject('modPluginEvent');
-    $events['OnPageNotFound']->fromArray(array(
-        'event' => 'OnPageNotFound',
-        'priority' => 0,
-        'propertyset' => 0,
-    ),'',true,true);
-    $plugin->addMany($events);
-    unset($events);
+
+$events = array();
+$events['OnPageNotFound']= $modx->newObject('modPluginEvent');
+$events['OnPageNotFound']->fromArray(array(
+    'event' => 'OnPageNotFound',
+    'priority' => 0,
+    'propertyset' => 0,
+),'',true,true);
+$events['OnDocFormRender'] = $modx->newObject('modPluginEvent');
+$events['OnDocFormRender']->fromArray(array(
+    'event' => 'OnDocFormRender',
+    'priority' => 0,
+    'propertyset' => 0,
+),'',true,true);
+$events['OnDocFormSave'] = $modx->newObject('modPluginEvent');
+$events['OnDocFormSave']->fromArray(array(
+    'event' => 'OnDocFormSave',
+    'priority' => 0,
+    'propertyset' => 0,
+),'',true,true);
+$plugin->addMany($events);
+unset($events);
 
 $attributes= array(
     xPDOTransport::UNIQUE_KEY => 'name',
@@ -94,6 +107,21 @@
 ));
 $builder->putVehicle($vehicle);
 
+/* settings */
+$settings = include_once $sources['data'].'transport.settings.php';
+$attributes= array(
+    xPDOTransport::UNIQUE_KEY => 'key',
+    xPDOTransport::PRESERVE_KEYS => true,
+    xPDOTransport::UPDATE_OBJECT => false,
+);
+if (!is_array($settings)) { $modx->log(modX::LOG_LEVEL_FATAL,'Adding settings failed.'); }
+foreach ($settings as $setting) {
+    $vehicle = $builder->createVehicle($setting,$attributes);
+    $builder->putVehicle($vehicle);
+}
+$modx->log(modX::LOG_LEVEL_INFO,'Packaged in '.count($settings).' system settings.'); flush();
+unset($settings,$setting,$attributes);
+
 /* load menu */
 $modx->log(modX::LOG_LEVEL_INFO,'Packaging in menu...');
 $menu = include $sources['data'].'transport.menu.php';
@@ -115,6 +143,9 @@
 $vehicle->resolve('php',array(
     'source' => $sources['resolvers'] . 'resolve.tables.php',
 ));
+$vehicle->resolve('php',array(
+    'source' => $sources['resolvers'] . 'resolve.dbchanges.php',
+));
 $builder->putVehicle($vehicle);
 unset($vehicle,$menu);
 
@@ -142,6 +173,4 @@
 $totalTime= ($tend - $tstart);
 $totalTime= sprintf("%2.4f s", $totalTime);
 
-$modx->log(modX::LOG_LEVEL_INFO,"\n
Package Built.
\nExecution time: {$totalTime}\n"); - -exit (); \ No newline at end of file +$modx->log(modX::LOG_LEVEL_INFO, "\nPackage Built.\nExecution time: {$totalTime}\n"); \ No newline at end of file diff --git a/_build/data/transport.menu.php b/_build/data/transport.menu.php old mode 100644 new mode 100755 index 3e76c5c..8514fd8 --- a/_build/data/transport.menu.php +++ b/_build/data/transport.menu.php @@ -10,7 +10,7 @@ 'id' => 1, 'namespace' => 'redirector', 'parent' => 0, - 'controller' => 'index', + 'controller' => 'controllers/index', 'haslayout' => true, 'lang_topics' => 'redirector:default', 'assets' => '', diff --git a/_build/data/transport.plugins.php b/_build/data/transport.plugins.php old mode 100644 new mode 100755 index 019c8d2..209d11c --- a/_build/data/transport.plugins.php +++ b/_build/data/transport.plugins.php @@ -12,14 +12,32 @@ 'description' => 'Handles site redirects.', 'plugincode' => file_get_contents($sources['elements'].'plugins/plugin.redirector.php'), ),'',true,true); - $events = array(); - $events['OnPageNotFound']= $modx->newObject('modPluginEvent'); - $events['OnPageNotFound']->fromArray(array( - 'event' => 'OnPageNotFound', - 'priority' => 0, - 'propertyset' => 0, - ),'',true,true); - $plugins[1]->addMany($events); - unset($events); + +$events = array(); +$events['OnPageNotFound']= $modx->newObject('modPluginEvent'); +$events['OnPageNotFound']->fromArray(array( + 'event' => 'OnPageNotFound', + 'priority' => 0, + 'propertyset' => 0, +),'',true,true); + +/* new OnDocFormRender event, added by cc */ +$events['OnDocFormRender'] = $modx->newObject('modPluginEvent'); +$events['OnDocFormRender']->fromArray(array( + 'event' => 'OnDocFormRender', + 'priority' => 0, + 'propertyset' => 0, +),'',true,true); + +/* new OnDocFormSave event, added by cc */ +$events['OnDocFormSave'] = $modx->newObject('modPluginEvent'); +$events['OnDocFormSave']->fromArray(array( + 'event' => 'OnDocFormSave', + 'priority' => 0, + 'propertyset' => 0, +),'',true,true); + +$plugins[1]->addMany($events); +unset($events); return $plugins; \ No newline at end of file diff --git a/_build/data/transport.settings.php b/_build/data/transport.settings.php new file mode 100755 index 0000000..82649e9 --- /dev/null +++ b/_build/data/transport.settings.php @@ -0,0 +1,27 @@ + array( + 'track_alias_updates' => false, + ), +); + +$settings = array(); +foreach ($s as $area => $sets) { + foreach ($sets as $key => $value) { + + $xtype = 'textfield'; + if(is_bool($value)) { $xtype = 'combo-boolean'; } + + $settings['redirector.'.$key] = $modx->newObject('modSystemSetting'); + $settings['redirector.'.$key]->set('key', 'redirector.'.$key); + $settings['redirector.'.$key]->fromArray(array( + 'value' => $value, + 'xtype' => $xtype, + 'namespace' => 'redirector', + 'area' => $area + )); + } +} + +return $settings; \ No newline at end of file diff --git a/_build/resolvers/resolve.dbchanges.php b/_build/resolvers/resolve.dbchanges.php new file mode 100755 index 0000000..8739138 --- /dev/null +++ b/_build/resolvers/resolve.dbchanges.php @@ -0,0 +1,28 @@ +xpdo; + +$modx->log(xPDO::LOG_LEVEL_INFO, 'Making database changes.'); +switch($options[xPDOTransport::PACKAGE_ACTION]) { + case xPDOTransport::ACTION_INSTALL: + case xPDOTransport::ACTION_UPGRADE: + + $modx =& $object->xpdo; + $modelPath = $modx->getOption('redirector.core_path', null, $modx->getOption('core_path').'components/redirector/').'model/'; + $modx->addPackage('redirector', $modelPath); + + $manager = $modx->getManager(); + + $manager->addField('modRedirect', 'context_key', array('after' => 'target')); + $manager->addIndex('modRedirect', 'pattern_context'); + $manager->removeIndex('modRedirect', 'pattern'); + + // update controller location + $modAction = $modx->getObject('modAction', array('namespace' => 'redirector', 'controller' => 'index')); + if(!empty($modAction) && is_object($modAction)) { + $modAction->set('controller', 'controllers/index'); + $modAction->save(); + } + + break; +} \ No newline at end of file diff --git a/assets/components/redirector/css/mgr.css b/assets/components/redirector/css/mgr.css new file mode 100755 index 0000000..77157af --- /dev/null +++ b/assets/components/redirector/css/mgr.css @@ -0,0 +1,30 @@ +.grid-row-invalid table tr td { background: #ffd6d3 !important; } + + +/* + * FileUploadField component styles + */ +.x-form-file-wrap { + position: relative; + height: 22px; +} +.x-form-file-wrap .x-form-file { + position: absolute; + right: 0; + -moz-opacity: 0; + filter:alpha(opacity: 0); + opacity: 0; + z-index: 2; + height: 22px; +} +.x-form-file-wrap .x-form-file-btn { + position: absolute; + right: 0; + z-index: 1; +} +.x-form-file-wrap .x-form-file-text { + position: absolute; + left: 0; + z-index: 3; + color: #777; +} \ No newline at end of file diff --git a/assets/components/redirector/js/mgr/combos.js b/assets/components/redirector/js/mgr/combos.js new file mode 100755 index 0000000..3919a6c --- /dev/null +++ b/assets/components/redirector/js/mgr/combos.js @@ -0,0 +1,51 @@ +Redi.combo.ResourceList = function(config) { + config = config || {}; + Ext.applyIf(config, { + name: 'resource', + hiddenName: 'resource', + displayField: 'pagetitle', + valueField: 'id', + fields: ['id','pagetitle'], + forceSelection: true, + typeAhead: true, + editable: true, + allowBlank: true, + autocomplete: true, + url: Redi.config.connector_url, + baseParams: { + action: 'mgr/resources/getList', + combo: true + } + }); + + Redi.combo.ResourceList.superclass.constructor.call(this, config); +}; + +Ext.extend(Redi.combo.ResourceList, MODx.combo.ComboBox); +Ext.reg('redirector-combo-resourcelist', Redi.combo.ResourceList); + +Redi.combo.ContextList = function(config) { + config = config || {}; + Ext.applyIf(config, { + name: 'context_key', + hiddenName: 'context_key', + displayField: 'key', + valueField: 'key', + fields: ['key'], + forceSelection: true, + typeAhead: true, + editable: true, + allowBlank: true, + autocomplete: true, + url: Redi.config.connector_url, + baseParams: { + action: 'mgr/contexts/getList', + combo: true + } + }); + + Redi.combo.ContextList.superclass.constructor.call(this, config); +}; + +Ext.extend(Redi.combo.ContextList, MODx.combo.ComboBox); +Ext.reg('redirector-combo-contextlist', Redi.combo.ContextList); \ No newline at end of file diff --git a/assets/components/redirector/js/mgr/redirector.js b/assets/components/redirector/js/mgr/redirector.js old mode 100644 new mode 100755 diff --git a/assets/components/redirector/js/mgr/sections/index.js b/assets/components/redirector/js/mgr/sections/index.js old mode 100644 new mode 100755 diff --git a/assets/components/redirector/js/mgr/utils/fileuploadfield.xtype.js b/assets/components/redirector/js/mgr/utils/fileuploadfield.xtype.js new file mode 100755 index 0000000..e89e91a --- /dev/null +++ b/assets/components/redirector/js/mgr/utils/fileuploadfield.xtype.js @@ -0,0 +1,184 @@ +/*! + * Ext JS Library 3.4.0 + * Copyright(c) 2006-2011 Sencha Inc. + * licensing@sencha.com + * http://www.sencha.com/license + */ +Ext.ns('Ext.ux.form'); + +/** + * @class Ext.ux.form.FileUploadField + * @extends Ext.form.TextField + * Creates a file upload field. + * @xtype fileuploadfield + */ +Ext.ux.form.FileUploadField = Ext.extend(Ext.form.TextField, { + /** + * @cfg {String} buttonText The button text to display on the upload button (defaults to + * 'Browse...'). Note that if you supply a value for {@link #buttonCfg}, the buttonCfg.text + * value will be used instead if available. + */ + buttonText: 'Browse...', + /** + * @cfg {Boolean} buttonOnly True to display the file upload field as a button with no visible + * text field (defaults to false). If true, all inherited TextField members will still be available. + */ + buttonOnly: false, + /** + * @cfg {Number} buttonOffset The number of pixels of space reserved between the button and the text field + * (defaults to 3). Note that this only applies if {@link #buttonOnly} = false. + */ + buttonOffset: 3, + /** + * @cfg {Object} buttonCfg A standard {@link Ext.Button} config object. + */ + + // private + readOnly: true, + + /** + * @hide + * @method autoSize + */ + autoSize: Ext.emptyFn, + + // private + initComponent: function(){ + Ext.ux.form.FileUploadField.superclass.initComponent.call(this); + + this.addEvents( + /** + * @event fileselected + * Fires when the underlying file input field's value has changed from the user + * selecting a new file from the system file selection dialog. + * @param {Ext.ux.form.FileUploadField} this + * @param {String} value The file value returned by the underlying file input field + */ + 'fileselected' + ); + }, + + // private + onRender : function(ct, position){ + Ext.ux.form.FileUploadField.superclass.onRender.call(this, ct, position); + + this.wrap = this.el.wrap({cls:'x-form-field-wrap x-form-file-wrap'}); + this.el.addClass('x-form-file-text'); + this.el.dom.removeAttribute('name'); + this.createFileInput(); + + var btnCfg = Ext.applyIf(this.buttonCfg || {}, { + text: this.buttonText + }); + this.button = new Ext.Button(Ext.apply(btnCfg, { + renderTo: this.wrap, + cls: 'x-form-file-btn' + (btnCfg.iconCls ? ' x-btn-icon' : '') + })); + + if(this.buttonOnly){ + this.el.hide(); + this.wrap.setWidth(this.button.getEl().getWidth()); + } + + this.bindListeners(); + this.resizeEl = this.positionEl = this.wrap; + }, + + bindListeners: function(){ + this.fileInput.on({ + scope: this, + mouseenter: function() { + this.button.addClass(['x-btn-over','x-btn-focus']) + }, + mouseleave: function(){ + this.button.removeClass(['x-btn-over','x-btn-focus','x-btn-click']) + }, + mousedown: function(){ + this.button.addClass('x-btn-click') + }, + mouseup: function(){ + this.button.removeClass(['x-btn-over','x-btn-focus','x-btn-click']) + }, + change: function(){ + var v = this.fileInput.dom.value; + this.setValue(v); + this.fireEvent('fileselected', this, v); + } + }); + }, + + createFileInput : function() { + this.fileInput = this.wrap.createChild({ + id: this.getFileInputId(), + name: this.name||this.getId(), + cls: 'x-form-file', + tag: 'input', + type: 'file', + size: 1 + }); + }, + + reset : function(){ + if (this.rendered) { + this.fileInput.remove(); + this.createFileInput(); + this.bindListeners(); + } + Ext.ux.form.FileUploadField.superclass.reset.call(this); + }, + + // private + getFileInputId: function(){ + return this.id + '-file'; + }, + + // private + onResize : function(w, h){ + Ext.ux.form.FileUploadField.superclass.onResize.call(this, w, h); + + this.wrap.setWidth(w); + + if(!this.buttonOnly){ + var w = this.wrap.getWidth() - this.button.getEl().getWidth() - this.buttonOffset; + this.el.setWidth(w); + } + }, + + // private + onDestroy: function(){ + Ext.ux.form.FileUploadField.superclass.onDestroy.call(this); + Ext.destroy(this.fileInput, this.button, this.wrap); + }, + + onDisable: function(){ + Ext.ux.form.FileUploadField.superclass.onDisable.call(this); + this.doDisable(true); + }, + + onEnable: function(){ + Ext.ux.form.FileUploadField.superclass.onEnable.call(this); + this.doDisable(false); + + }, + + // private + doDisable: function(disabled){ + this.fileInput.dom.disabled = disabled; + this.button.setDisabled(disabled); + }, + + + // private + preFocus : Ext.emptyFn, + + // private + alignErrorIcon : function(){ + this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]); + } + +}); + +Ext.reg('fileuploadfield', Ext.ux.form.FileUploadField); + +// backwards compat +Ext.form.FileUploadField = Ext.ux.form.FileUploadField; diff --git a/assets/components/redirector/js/mgr/widgets/home.panel.js b/assets/components/redirector/js/mgr/widgets/home.panel.js index e33605e..fe87af5 100755 --- a/assets/components/redirector/js/mgr/widgets/home.panel.js +++ b/assets/components/redirector/js/mgr/widgets/home.panel.js @@ -2,6 +2,14 @@ Redi.panel.Home = function(config) { config = config || {}; Ext.apply(config,{ border: false + ,id: 'redirector-import-formpanel' + + ,url: Redi.config.connectorUrl + ,baseParams: { + action: 'mgr/import/import' + } + ,fileUpload: true + ,baseCls: 'modx-formpanel' ,cls: 'container' ,items: [{ @@ -20,20 +28,107 @@ Redi.panel.Home = function(config) { } ,items: [{ title: _('redirector.redirects') - ,defaults: { autoHeight: true } + ,defaults: { border: false ,autoHeight: true } ,items: [{ - html: _('redirector.desc') - ,border: false + html: '

'+_('redirector.desc')+'

' ,bodyCssClass: 'panel-desc' },{ xtype: 'redirector-grid-redirects' - ,preventRender: true ,cls: 'main-wrapper' + ,preventRender: true }] + },{ + title: _('redirector.import') + ,defaults: { border: false ,autoHeight: true } + ,items: this.getImportPanelItems(config) }] }] }); Redi.panel.Home.superclass.constructor.call(this,config); }; -Ext.extend(Redi.panel.Home,MODx.Panel); -Ext.reg('redirector-panel-home',Redi.panel.Home); +Ext.extend(Redi.panel.Home, MODx.FormPanel, { + getImportPanelItems: function(config) { + var it = []; + it.push({ + html: '

'+_('redirector.import_desc')+'
'+_('redirector.import.csv_desc', MODx.config)+'

' + ,bodyCssClass: 'panel-desc' + }); + + it.push({ + layout: 'form' + ,bodyCssClass: 'tab-panel-wrapper main-wrapper' + ,cls: 'modx-resource-tab' + + ,anchor: '80%' + ,labelAlign: 'top' + ,labelSeparator: '' + ,defaults: { msgTarget: 'under', anchor: '100%' } + ,items: [{ + xtype: 'fileuploadfield' + ,id: 'redirector-import-fileupload' + ,fieldLabel: _('redirector.import.csv_file') + ,name: 'csv_data_file' + ,listeners: { + 'fileselected': { + fn: function(fld, e) { + var btn = Ext.getCmp('redirector-import-do-button'); + if(!Ext.isEmpty(fld.getValue())) { + btn.setDisabled(false); + } else { + btn.setDisabled(true); + } + } + ,scope: this + } + } + },{ + html: '
' + ,border: false + },{ + xtype: 'textarea' + ,id: 'redirector-import-rawcsv' + ,fieldLabel: _('redirector.import.raw_csv') + ,name: 'csv_data_raw' + ,height: 250 + ,enableKeyEvents: true + ,listeners: { + 'keyup': { + fn: function(fld, e) { + var btn = Ext.getCmp('redirector-import-do-button'); + if(!Ext.isEmpty(fld.getValue())) { + btn.setDisabled(false); + } else { + btn.setDisabled(true); + } + } + ,scope: this + } + } + },{ + xtype: 'button' + ,id: 'redirector-import-do-button' + ,text: _('redirector.import.do') + ,anchor: 'auto' + ,disabled: true + ,handler: function() { + var formObj = Ext.getCmp('redirector-import-formpanel'); + if(formObj.isValid()) { + formObj.getForm().submit({ + waitMsg: config.saveMsg || _('redirector.import.doing') + ,scope: this + ,failure: function(form, response) { + Ext.MessageBox.alert(_('redirector.import'), response.result.message); + } + ,success: function(form, response) { + Ext.MessageBox.alert(_('redirector.import'), response.result.message); + } + }); + } + } + }] + }); + + return it; + } +}); +Ext.reg('redirector-panel-home', Redi.panel.Home); \ No newline at end of file diff --git a/assets/components/redirector/js/mgr/widgets/redirects.grid.js b/assets/components/redirector/js/mgr/widgets/redirects.grid.js old mode 100644 new mode 100755 index 455f7be..b947c52 --- a/assets/components/redirector/js/mgr/widgets/redirects.grid.js +++ b/assets/components/redirector/js/mgr/widgets/redirects.grid.js @@ -1,5 +1,6 @@ Redi.grid.Redirects = function(config) { config = config || {}; + var cb = new Ext.ux.grid.CheckColumn({ header: _('redirector.active') ,dataIndex: 'active' @@ -7,38 +8,74 @@ Redi.grid.Redirects = function(config) { ,sortable: true ,onMouseDown: this.saveCheckbox }); + Ext.applyIf(config,{ id: 'redirector-grid-redirects' ,url: Redi.config.connector_url ,baseParams: { action: 'mgr/redirect/getList' } + ,fields: ['id','pattern','target','context_key','valid','resource_id','resource_ctx','active'] ,save_action: 'mgr/redirect/updateFromGrid' - ,fields: ['id','pattern','target','active','menu'] - ,paging: true ,autosave: true + ,paging: true ,remoteSort: true + + ,viewConfig: { + forceFit: true + ,scrollOffset: 0 + ,autoFill: true + ,showPreview: true + ,getRowClass : function(rec){ + var cls = ((!rec.data.valid) ? 'grid-row-invalid' : 'grid-row-valid'); + return cls; + } + ,emptyText: _('redirector.nothing_found') + } + ,anchor: '97%' ,autoExpandColumn: 'name' ,plugins: [cb] ,columns: [{ + header: _('id') + ,dataIndex: 'id' + ,sortable: true + ,width: 25 + ,hidden: true + },{ header: _('redirector.pattern') ,dataIndex: 'pattern' ,sortable: true - ,width: 200 ,editor: { xtype: 'textfield' } + ,renderer: this.renderPattern.createDelegate(this,[this],true) },{ header: _('redirector.target') ,dataIndex: 'target' - ,sortable: false - ,width: 200 + ,sortable: true ,editor: { xtype: 'textfield' } + },{ + header: _('redirector.context') + ,dataIndex: 'context_key' + ,sortable: true + ,width: 50 + ,editor: { xtype: 'redirector-combo-contextlist' } },cb] ,tbar: [{ + text: _('redirector.redirect_create') + ,handler: { xtype: 'redirector-window-redirect-createupdate' ,blankValues: true ,update: false } + },'->',{ + xtype: 'redirector-combo-contextlist' + ,id: 'redirector-context-filter' + ,emptyText: _('redirector.context') + ,listeners: { + 'select': { fn: this.searchContext ,scope: this } + ,'change': { fn: this.searchContext ,scope: this } + } + },'-',{ xtype: 'textfield' ,id: 'redirector-search-filter' ,emptyText: _('redirector.search...') ,listeners: { - 'change': {fn:this.search,scope:this} - ,'render': {fn: function(cmp) { + 'change': { fn: this.search ,scope: this } + ,'render': { fn: function(cmp) { new Ext.KeyMap(cmp.getEl(), { key: Ext.EventObject.ENTER ,fn: function() { @@ -47,11 +84,8 @@ Redi.grid.Redirects = function(config) { return true; } ,scope: cmp }); - },scope:this} + } ,scope: this } } - },{ - text: _('redirector.redirect_create') - ,handler: { xtype: 'redirector-window-redirect-create' ,blankValues: true } }] }); Redi.grid.Redirects.superclass.constructor.call(this,config) @@ -59,10 +93,27 @@ Redi.grid.Redirects = function(config) { Ext.extend(Redi.grid.Redirects,MODx.grid.Grid,{ search: function(tf,nv,ov) { var s = this.getStore(); - s.baseParams.query = tf.getValue(); + s.baseParams.query = tf.getValue(); this.getBottomToolbar().changePage(1); this.refresh(); } + ,searchContext: function(tf,nv,ov) { + var s = this.getStore(); + s.baseParams.context = tf.getValue(); + this.getBottomToolbar().changePage(1); + this.refresh(); + } + ,getMenu: function(g,ri) { + var m = []; + m.push({ + text: _('redirector.redirect_update') + ,handler: this.updateRedirect + },'-',{ + text: _('redirector.redirect_remove') + ,handler: this.removeRedirect + }); + return m; + } ,saveCheckbox: function(e, t){ var rowData = false; /* checks/unchecks */ @@ -93,19 +144,20 @@ Ext.extend(Redi.grid.Redirects,MODx.grid.Grid,{ }); } ,updateRedirect: function(btn,e) { - if (!this.updateRedirectWindow) { - this.updateRedirectWindow = MODx.load({ - xtype: 'redirector-window-redirect-update' - ,record: this.menu.record - ,listeners: { - 'success': {fn:this.refresh,scope:this} - } - }); - } - this.updateRedirectWindow.setValues(this.menu.record); - this.updateRedirectWindow.show(e.target); + var w = MODx.load({ + xtype: 'redirector-window-redirect-createupdate' + ,record: this.menu.record + ,update: true + ,listeners: { + 'success': { fn: this.refresh, scope: this } + ,'hide': { fn: function() { this.destroy(); }} + } + }); + w.setValues(this.menu.record); + w.show(e.target, function() { + Ext.isSafari ? w.setPosition(null,30) : w.center(); + }, this); } - ,removeRedirect: function() { MODx.msg.confirm({ title: _('redirector.redirect_remove') @@ -120,71 +172,104 @@ Ext.extend(Redi.grid.Redirects,MODx.grid.Grid,{ } }); } + /** RENDERERS **/ + ,renderPattern: function(v,md,rec,ri,ci,s,g) { + var r = s.getAt(ri).data; + if(!Ext.isEmpty(r.resource_id)) { + v += ' (' + _('resource') + ': ' + r.resource_id + ' - ' + r.resource_ctx + ')'; + } + return v; + } }); Ext.reg('redirector-grid-redirects',Redi.grid.Redirects); -Redi.window.CreateRedirect = function(config) { +Redi.window.CreateUpdateRedirect = function(config) { config = config || {}; - Ext.applyIf(config,{ - title: _('redirector.redirect_create') - ,url: Redi.config.connector_url - ,baseParams: { - action: 'mgr/redirect/create' - } - ,fields: [{ - xtype: 'textfield' - ,fieldLabel: _('redirector.pattern') - ,name: 'pattern' - ,width: 300 - },{ - xtype: 'textfield' - ,fieldLabel: _('redirector.target') - ,name: 'target' - ,width: 300 - },{ - xtype: 'checkbox' - ,fieldLabel: _('redirector.active') - ,name: 'active' - ,inputValue: 1 - ,checked: true - }] - }); - Redi.window.CreateRedirect.superclass.constructor.call(this,config); -}; -Ext.extend(Redi.window.CreateRedirect,MODx.Window); -Ext.reg('redirector-window-redirect-create',Redi.window.CreateRedirect); - + this.ident = config.ident || Ext.id(); -Redi.window.UpdateRedirect = function(config) { - config = config || {}; Ext.applyIf(config,{ - title: _('redirector.redirect_update') + title: _('redirector.redirect_create') ,url: Redi.config.connector_url - ,baseParams: { - action: 'mgr/redirect/update' - } + ,baseParams: { action: ((config.update) ? 'mgr/redirect/update' : 'mgr/redirect/create') } + ,modal: true + ,width: 750 ,fields: [{ xtype: 'hidden' ,name: 'id' },{ - xtype: 'textfield' - ,fieldLabel: _('redirector.pattern') - ,name: 'pattern' - ,width: 300 - },{ - xtype: 'textfield' - ,fieldLabel: _('redirector.target') - ,name: 'target' - ,width: 300 - },{ - xtype: 'checkbox' - ,fieldLabel: _('redirector.active') - ,name: 'active' - ,inputValue: 1 + layout: 'column' + ,border: false + ,defaults: { msgTarget: 'under' ,border: false } + ,items: [{ + layout: 'form' + ,columnWidth: .5 + ,defaults: { msgTarget: 'under' ,border: false } + ,items: [{ + xtype: 'textfield' + ,fieldLabel: _('redirector.pattern') + ,name: 'pattern' + ,anchor: '100%' + ,allowBlank: false + },{ + xtype: 'redirector-combo-contextlist' + ,fieldLabel: _('redirector.context') + ,name: 'context_key' + ,anchor: '100%' + },{ + layout: 'column' + ,border: false + ,defaults: { msgTarget: 'under' ,border: false } + ,items: [{ + layout: 'form' + ,columnWidth: .6 + ,defaults: { msgTarget: 'under' ,border: false } + ,items: [{ + xtype: 'textfield' + ,id: 'redirector-createupdate-window-target-'+this.ident + ,fieldLabel: _('redirector.target') + ,name: 'target' + ,anchor: '100%' + ,allowBlank: false + }] + },{ + layout: 'form' + ,columnWidth: .4 + ,defaults: { msgTarget: 'under' ,border: false } + ,items: [{ + xtype: 'redirector-combo-resourcelist' + ,fieldLabel: _('resource') + ,anchor: '100%' + ,listeners: { + 'select': { + fn: function(cb, e) { + var targetField = Ext.getCmp('redirector-createupdate-window-target-'+this.ident); + targetField.setValue('[[~' + cb.getValue() + ']]'); + } ,scope: this + } + } + }] + }] + },{ + xtype: 'xcheckbox' + ,hideLabel: true + ,boxLabel: _('redirector.active') + ,name: 'active' + ,inputValue: 1 + ,checked: true + }] + },{ + columnWidth: .5 + ,defaults: { msgTarget: 'under' ,border: false } + ,items: [{ + html: Ext.util.Format.nl2br(_('redirector.regex_explain')) + ,border: false + ,bodyStyle: 'font-size: 0.9em; line-height: 15px;' + }] + }] }] }); - Redi.window.UpdateRedirect.superclass.constructor.call(this,config); + Redi.window.CreateUpdateRedirect.superclass.constructor.call(this,config); }; -Ext.extend(Redi.window.UpdateRedirect,MODx.Window); -Ext.reg('redirector-window-redirect-update',Redi.window.UpdateRedirect); \ No newline at end of file +Ext.extend(Redi.window.CreateUpdateRedirect,MODx.Window); +Ext.reg('redirector-window-redirect-createupdate',Redi.window.CreateUpdateRedirect); \ No newline at end of file diff --git a/core/components/redirector/controllers/home.class.php b/core/components/redirector/controllers/home.class.php new file mode 100755 index 0000000..ce86470 --- /dev/null +++ b/core/components/redirector/controllers/home.class.php @@ -0,0 +1,19 @@ +modx->lexicon('redirector'); } + + public function loadCustomCssJs() { + $this->addJavascript($this->redirector->config['jsUrl'].'mgr/utils/fileuploadfield.xtype.js'); + + $this->addJavascript($this->redirector->config['jsUrl'].'mgr/widgets/redirects.grid.js'); + $this->addJavascript($this->redirector->config['jsUrl'].'mgr/widgets/home.panel.js'); + $this->addLastJavascript($this->redirector->config['jsUrl'].'mgr/sections/index.js'); + } + + public function getTemplateFile() { return $this->redirector->config['templatesPath'].'home.tpl'; } +} \ No newline at end of file diff --git a/core/components/redirector/controllers/index.class.php b/core/components/redirector/controllers/index.class.php new file mode 100755 index 0000000..cb75c35 --- /dev/null +++ b/core/components/redirector/controllers/index.class.php @@ -0,0 +1,35 @@ +redirector = new Redirector($this->modx); + + $this->addCss($this->redirector->config['cssUrl'].'mgr.css'); + $this->addJavascript($this->redirector->config['jsUrl'].'mgr/redirector.js'); + $this->addJavascript($this->redirector->config['jsUrl'].'mgr/combos.js'); + $this->addHtml(''); + return parent::initialize(); + } + + public function getLanguageTopics() { + return array('redirector:default'); + } + + public function checkPermissions() { return true;} +} + +class ControllersIndexManagerController extends RedirectorManagerController { + public static function getDefaultController() { return 'home'; } +} \ No newline at end of file diff --git a/core/components/redirector/controllers/index.php b/core/components/redirector/controllers/index.php deleted file mode 100644 index c7b19f4..0000000 --- a/core/components/redirector/controllers/index.php +++ /dev/null @@ -1,8 +0,0 @@ -initialize('mgr'); \ No newline at end of file diff --git a/core/components/redirector/controllers/mgr/header.php b/core/components/redirector/controllers/mgr/header.php deleted file mode 100644 index 162f623..0000000 --- a/core/components/redirector/controllers/mgr/header.php +++ /dev/null @@ -1,18 +0,0 @@ -regClientStartupScript($redirector->config['jsUrl'].'mgr/redirector.js'); -$modx->regClientStartupHTMLBlock(''); - - -return ''; \ No newline at end of file diff --git a/core/components/redirector/controllers/mgr/index.php b/core/components/redirector/controllers/mgr/index.php deleted file mode 100644 index 131a998..0000000 --- a/core/components/redirector/controllers/mgr/index.php +++ /dev/null @@ -1,14 +0,0 @@ -regClientStartupScript($redirector->config['jsUrl'].'mgr/widgets/redirects.grid.js'); -$modx->regClientStartupScript($redirector->config['jsUrl'].'mgr/widgets/home.panel.js'); -$modx->regClientStartupScript($redirector->config['jsUrl'].'mgr/sections/index.js'); - -$output = '
'; - -return $output; diff --git a/core/components/redirector/docs/changelog.txt b/core/components/redirector/docs/changelog.txt old mode 100644 new mode 100755 index 8f1194f..caa7728 --- a/core/components/redirector/docs/changelog.txt +++ b/core/components/redirector/docs/changelog.txt @@ -1,5 +1,16 @@ Changelog file for Redirector component. +Redirector 2.0.0 +==================================== +- New feature: possibility to import from CSV files and raw data +- Added visible view (red bar) when a redirect is invalid (pattern or target) +- Redirect created on URI update. Enable/disable via System Settings (Thanks to chrischerrett) +- Added support for regular expressions in pattern and replaces in target (preg_replace, Thanks to eprochasson) +- Added support for context specific rules +- Added support for contexts-as-subfolder (Thanks to jkenters) +- UI fixes for MODX 2.2+ +- Code compatible with MODX 2.2+ + Redirector 1.0.3 ==================================== - Add sqlsrv support diff --git a/core/components/redirector/elements/plugins/plugin.redirector.php b/core/components/redirector/elements/plugins/plugin.redirector.php old mode 100644 new mode 100755 index 2803f8c..1bc4361 --- a/core/components/redirector/elements/plugins/plugin.redirector.php +++ b/core/components/redirector/elements/plugins/plugin.redirector.php @@ -7,48 +7,121 @@ $redirector = $modx->getService('redirector','Redirector',$corePath.'model/redirector/',$scriptProperties); if (!($redirector instanceof Redirector)) return ''; -/* handle redirects */ -$search = $_SERVER['REQUEST_URI']; -$baseUrl = $modx->getOption('base_url',null,MODX_BASE_URL); -if (!empty($baseUrl) && $baseUrl != '/' && $baseUrl != ' ' && $baseUrl != '/'.$modx->context->get('key').'/') { - $search = str_replace($baseUrl,'',$search); -} -$search = ltrim($search,'/'); -$extPos = strrpos($search, '.'); -if ($extPos) { - if ($search) { - $redirect = $modx->getObject('modRedirect', array( - 'pattern' => $search, - 'active' => 1, - )); - if ($redirect) { - $target = $redirect->get('target'); - $modx->parser->processElementTags('', $target, true, true); - if ($target != $modx->resourceIdentifier && $target != $search) { - if (!strpos($target, '://')) { - $target = $modx->getOption('site_url').$target; +$eventName = $modx->event->name; +switch($eventName) { + case 'OnPageNotFound': + + /* handle redirects */ + $search = $_SERVER['REQUEST_URI']; + $baseUrl = $modx->getOption('base_url',null,MODX_BASE_URL); + if (!empty($baseUrl) && $baseUrl != '/' && $baseUrl != ' ' && $baseUrl != '/'.$modx->context->get('key').'/') { + $search = str_replace($baseUrl,'',$search); + } + $search = ltrim($search,'/'); + $extPos = strrpos($search, '.'); + if ($extPos) { + if ($search) { + + $redirect = $modx->getObject('modRedirect', array( + "(`modRedirect`.`pattern` = '".$search."' OR '".$search."' REGEXP `modRedirect`.`pattern`)", + "(`modRedirect`.`context_key` = '".$modx->context->get('key')."' OR `modRedirect`.`context_key` IS NULL OR `modRedirect`.`context_key` = '')", + 'active' => true, + )); + + if ($redirect) { + $target = $redirect->get('target'); + $modx->parser->processElementTags('', $target, true, true); + if ($target != $modx->resourceIdentifier && $target != $search) { + if (strpos($target, '$') !== false) { + $pattern = $redirect->get('pattern'); + $target = preg_replace('/'.$pattern.'/', $target, $search); + } + if (!strpos($target, '://')) { + $target = $modx->getOption('site_url').$target; + } + $modx->log(modX::LOG_LEVEL_INFO, 'Redirector plugin redirecting request for ' . $search . ' to ' . $target); + + $options = array('responseCode' => 'HTTP/1.1 301 Moved Permanently'); + $modx->sendRedirect($target, $options); + } } - $modx->log(modX::LOG_LEVEL_INFO, 'Redirector plugin redirecting request for ' . $search . ' to ' . $target); - header('HTTP/1.1 301 Moved Permanently'); - $modx->sendRedirect($target); } + + $search = substr($search, 0, $extPos); } - } - $search = substr($search, 0, $extPos); -} -if ($search) { - $redirect = $modx->getObject('modRedirect', array('pattern' => $search, 'active' => 1)); - if ($redirect) { - $target = $redirect->get('target'); - $modx->parser->processElementTags('', $target, true, true); - if ($target != $modx->resourceIdentifier && $target != $search) { - if (!strpos($target, '://')) { - $target = $modx->getOption('site_url').$target; + + if ($search) { + + $redirect = $modx->getObject('modRedirect', array( + "(`modRedirect`.`pattern` = '".$search."' OR '".$search."' REGEXP `modRedirect`.`pattern`)", + "(`modRedirect`.`context_key` = '".$modx->context->get('key')."' OR `modRedirect`.`context_key` IS NULL OR `modRedirect`.`context_key` = '')", + 'active' => true, + )); + + if ($redirect) { + $target = $redirect->get('target'); + $modx->parser->processElementTags('', $target, true, true); + if ($target != $modx->resourceIdentifier && $target != $search) { + if (strpos($target, '$') !== false) { + $pattern = $redirect->get('pattern'); + $target = preg_replace('/'.$pattern.'/', $target, $search); + } + if (!strpos($target, '://')) { + $target = $modx->getOption('site_url').$target; + } + $modx->log(modX::LOG_LEVEL_INFO, 'Redirector plugin redirecting request for ' . $search . ' to ' . $target); + + $options = array('responseCode' => 'HTTP/1.1 301 Moved Permanently'); + $modx->sendRedirect($target, $options); + } + } + } + + break; + + case 'OnDocFormRender': + + $track_uri_updates = $modx->getOption('redirector.track_uri_updates', null, true); + if ($mode == 'upd' && $track_uri_updates) { + $_SESSION['modx_resource_uri'] = $resource->get('uri'); + } + + break; + + case 'OnDocFormSave': + + /* if uri has changed, add to redirects */ + $track_uri_updates = $modx->getOption('redirector.track_uri_updates', null, true); + $context_key = $resource->get('context_key'); + $new_uri = $resource->get('uri'); + + if ($mode == 'upd' && $track_uri_updates) { + $old_uri = $_SESSION['modx_resource_uri']; + if ($old_uri != $new_uri) { + + /* uri changed */ + $redirect = $modx->getObject('modRedirect', array('pattern' => $old_uri, 'context_key' => $context_key, 'active' => true)); + if (empty($redirect)) { + + /* no record for old uri */ + $new_redirect = $modx->newObject('modRedirect'); + $new_redirect->fromArray(array( + 'pattern' => $old_uri, + 'target' => $new_uri, + 'context_key' => $context_key, + 'active' => true, + )); + + if ($new_redirect->save() == false) { + return $modx->error->failure($modx->lexicon('redirector.redirect_err_save')); + } + } } - $modx->log(modX::LOG_LEVEL_INFO, 'Redirector plugin redirecting request for ' . $search . ' to ' . $target); - header('HTTP/1.1 301 Moved Permanently'); - $modx->sendRedirect($target); + + $_SESSION['modx_resource_uri'] = $new_uri; } - } + + break; } -return; + +return ''; \ No newline at end of file diff --git a/core/components/redirector/index.php b/core/components/redirector/index.php deleted file mode 100644 index ef27b5a..0000000 --- a/core/components/redirector/index.php +++ /dev/null @@ -1,3 +0,0 @@ -Also; use relative URLs, not include [[+site_url]] or similar ones.'; +$_lang['redirector.import.csv_file'] = 'CSV File selection'; +$_lang['redirector.import.raw_csv'] = 'Paste raw CSV data here'; +$_lang['redirector.import.do'] = 'Start Import!'; +$_lang['redirector.import.doing'] = 'Busy with importing CSV data...'; +$_lang['redirector.import.success'] = 'Total [[+total]] records found. Imported: [[+succeed]] successful and [[+failed]] failed!'; +$_lang['redirector.import.failed'] = 'Failed importing CSV data... Try again!'; + +$_lang['redirector.regex_explain'] = 'You can use regular expressions in the pattern and retrieve your replacements back in your target URL. + +For example; you have many old URLs like "shop/category-{name}/" and you want to redirect all those URLs to the new "webshop/{name}/" structure, no problem! +Enter these values: + +Pattern: ^shop\/category-(.*)\/$ +Target: webshop/$1/ + +You can also apply more wildcards (.*) and use $2, $3 etc. And as you can see, you need to escape the forward slashes and define a ^ for the start and $ for the end position.'; + +// settings +$_lang['setting_redirector.track_uri_updates'] = 'Track URI Updates'; +$_lang['setting_redirector.track_uri_updates_desc'] = 'If enabled, this will keep track on resource URI updates. Automatically created redirects for old > new URIs.'; diff --git a/core/components/redirector/lexicon/fr/default.inc.php b/core/components/redirector/lexicon/fr/default.inc.php index 8bdbde1..3a1caa0 100755 --- a/core/components/redirector/lexicon/fr/default.inc.php +++ b/core/components/redirector/lexicon/fr/default.inc.php @@ -7,7 +7,7 @@ */ $_lang['redirector'] = 'Redirector'; $_lang['redirector.active'] = 'Actif'; -$_lang['redirector.desc'] = 'Gérez les redirections de votre site internet.'; +$_lang['redirector.desc'] = 'Gérez les redirections de votre site internet. Red lines means that the pattern URL is still exists OR target URL doesn\'t exists for a resource and will not be redirected.'; $_lang['redirector.description'] = 'Description'; $_lang['redirector.redirect_err_ae'] = 'Une redirection portant ce nom existe déjà.'; $_lang['redirector.redirect_err_nf'] = 'Redirection non trouvée.'; diff --git a/core/components/redirector/lexicon/nl/default.inc.php b/core/components/redirector/lexicon/nl/default.inc.php old mode 100644 new mode 100755 index 34a5e48..92c995e --- a/core/components/redirector/lexicon/nl/default.inc.php +++ b/core/components/redirector/lexicon/nl/default.inc.php @@ -7,7 +7,8 @@ */ $_lang['redirector'] = 'Redirector'; $_lang['redirector.active'] = 'Actief'; -$_lang['redirector.desc'] = 'Beheer verwijzingen voor je website.'; +$_lang['redirector.desc'] = 'Beheer verwijzingen voor je website. Rode regels betekenen dat het patroon nog altijd een bestaande URL is OF dat de target niet bestaat, als resource en dat deze niet geredirect wordt.'; +$_lang['redirector.nothing_found'] = 'Nog geen verwijzingen gevonden!'; $_lang['redirector.description'] = 'Beschrijving'; $_lang['redirector.redirect_err_ae'] = 'Er bestaat al een verwijzing met deze naam.'; $_lang['redirector.redirect_err_nf'] = 'Verwijzing niet gevonden.'; @@ -25,4 +26,15 @@ $_lang['redirector.pattern'] = 'Patroon'; $_lang['redirector.search...'] = 'Zoeken...'; $_lang['redirector.target'] = 'Doel'; +$_lang['redirector.context'] = 'Context'; +$_lang['redirector.context_desc'] = 'Als context ingesteld is, zal de redirect alleen plaatsvinden als deze geladen is.'; +$_lang['redirector.import'] = 'Importeer CSV'; +$_lang['redirector.import_desc'] = 'Hier kunt u nieuwe verwijs regels importeren middels CSV formaat. U kunt een CSV bestand uploaden of ruwe CSV in het textveld hieronder plaatsen.'; +$_lang['redirector.import.csv_desc'] = 'Let op: het formaat van de CSV moet "pattern;target;context" zijn, waar "context" overgeslagen of leeg mag zijn.
Daarnaast: gebruik relatieve URLs, gebruik geen [[+site_url]] of vergelijkbare waarden.'; +$_lang['redirector.import.csv_file'] = 'CSV Bestand selecteren'; +$_lang['redirector.import.raw_csv'] = 'Plak ruwe CSV data hier'; +$_lang['redirector.import.do'] = 'Start Import!'; +$_lang['redirector.import.doing'] = 'Bezig met importeren CSV data...'; +$_lang['redirector.import.success'] = 'Totaal [[+total]] records gevonden. Geimporteerd: [[+succeed]] met succes en [[+failed]] mislukt!'; +$_lang['redirector.import.failed'] = 'Mislukt CSV te importeren... Probeer het nog eens!'; \ No newline at end of file diff --git a/core/components/redirector/lexicon/ru/default.inc.php b/core/components/redirector/lexicon/ru/default.inc.php index cfb8ffe..e9743ff 100755 --- a/core/components/redirector/lexicon/ru/default.inc.php +++ b/core/components/redirector/lexicon/ru/default.inc.php @@ -7,7 +7,8 @@ */ $_lang['redirector'] = 'Redirector'; $_lang['redirector.active'] = 'Включён'; -$_lang['redirector.desc'] = 'Управление редиректами на вашем сайте.'; +$_lang['redirector.desc'] = 'Управление редиректами на вашем сайте. Red lines means that the pattern URL is still exists OR target URL doesn\'t exists for a resource and will not be redirected.'; +$_lang['redirector.nothing_found'] = 'No redirects found yet!'; $_lang['redirector.description'] = 'Описание'; $_lang['redirector.redirect_err_ae'] = 'Редирект с таким именем уже есть.'; $_lang['redirector.redirect_err_nf'] = 'Редирект не найден.'; @@ -25,4 +26,5 @@ $_lang['redirector.pattern'] = 'Шаблон'; $_lang['redirector.search...'] = 'Поиск...'; $_lang['redirector.target'] = 'Цель'; - +$_lang['redirector.context'] = 'Context'; +$_lang['redirector.context_desc'] = 'If context is set, redirect only affects on loaded context.'; \ No newline at end of file diff --git a/core/components/redirector/model/redirector/metadata.mysql.php b/core/components/redirector/model/redirector/metadata.mysql.php new file mode 100644 index 0000000..1ce2540 --- /dev/null +++ b/core/components/redirector/model/redirector/metadata.mysql.php @@ -0,0 +1,8 @@ + + array ( + 0 => 'modRedirect', + ), +); \ No newline at end of file diff --git a/core/components/redirector/model/redirector/modredirect.class.php b/core/components/redirector/model/redirector/modredirect.class.php old mode 100644 new mode 100755 diff --git a/core/components/redirector/model/redirector/mysql/modredirect.class.php b/core/components/redirector/model/redirector/mysql/modredirect.class.php old mode 100644 new mode 100755 diff --git a/core/components/redirector/model/redirector/mysql/modredirect.map.inc.php b/core/components/redirector/model/redirector/mysql/modredirect.map.inc.php old mode 100644 new mode 100755 index 26e89b4..3349a06 --- a/core/components/redirector/model/redirector/mysql/modredirect.map.inc.php +++ b/core/components/redirector/model/redirector/mysql/modredirect.map.inc.php @@ -1,14 +1,14 @@ 'redirector', + 'version' => NULL, 'table' => 'redirects', + 'extends' => 'xPDOSimpleObject', 'fields' => array ( 'pattern' => '', 'target' => '', + 'context_key' => NULL, 'active' => 1, ), 'fieldMeta' => @@ -20,7 +20,8 @@ 'phptype' => 'string', 'null' => false, 'default' => '', - 'index' => 'unique', + 'index' => 'index', + 'indexgrp' => 'pattern_context', ), 'target' => array ( @@ -31,6 +32,16 @@ 'default' => '', 'index' => 'index', ), + 'context_key' => + array ( + 'dbtype' => 'varchar', + 'precision' => '255', + 'phptype' => 'string', + 'null' => true, + 'default' => NULL, + 'index' => 'index', + 'indexgrp' => 'pattern_context', + ), 'active' => array ( 'dbtype' => 'tinyint', @@ -42,4 +53,56 @@ 'index' => 'index', ), ), + 'indexes' => + array ( + 'pattern_context' => + array ( + 'alias' => 'pattern_context', + 'primary' => false, + 'unique' => true, + 'type' => 'BTREE', + 'columns' => + array ( + 'pattern' => + array ( + 'length' => '100', + 'collation' => 'A', + 'null' => false, + ), + 'context_key' => + array ( + 'length' => '100', + 'collation' => 'A', + 'null' => false, + ), + ), + ), + ), + 'aggregates' => + array ( + 'PatternResource' => + array ( + 'class' => 'modResource', + 'local' => 'pattern', + 'foreign' => 'uri', + 'cardinality' => 'one', + 'owner' => 'foreign', + ), + 'TargetResource' => + array ( + 'class' => 'modResource', + 'local' => 'target', + 'foreign' => 'uri', + 'cardinality' => 'one', + 'owner' => 'foreign', + ), + 'Context' => + array ( + 'class' => 'modContext', + 'local' => 'context_key', + 'foreign' => 'key', + 'cardinality' => 'one', + 'owner' => 'foreign', + ), + ), ); diff --git a/core/components/redirector/model/redirector/redirector.class.php b/core/components/redirector/model/redirector/redirector.class.php old mode 100644 new mode 100755 index 2bea1aa..cb28013 --- a/core/components/redirector/model/redirector/redirector.class.php +++ b/core/components/redirector/model/redirector/redirector.class.php @@ -14,12 +14,14 @@ function __construct(modX &$modx,array $config = array()) { $basePath = $this->modx->getOption('redirector.core_path',$config,$this->modx->getOption('core_path').'components/redirector/'); $assetsUrl = $this->modx->getOption('redirector.assets_url',$config,$this->modx->getOption('assets_url').'components/redirector/'); + $this->config = array_merge(array( 'basePath' => $basePath, 'corePath' => $basePath, 'modelPath' => $basePath.'model/', 'processorsPath' => $basePath.'processors/', 'chunksPath' => $basePath.'elements/chunks/', + 'templatesPath' => $basePath.'templates/', 'jsUrl' => $assetsUrl.'js/', 'cssUrl' => $assetsUrl.'css/', 'assetsUrl' => $assetsUrl, @@ -29,35 +31,6 @@ function __construct(modX &$modx,array $config = array()) { $this->modx->addPackage('redirector',$this->config['modelPath']); } - /** - * Initializes the class into the proper context - * - * @access public - * @param string $ctx - */ - public function initialize($ctx = 'web') { - switch ($ctx) { - case 'mgr': - $this->modx->lexicon->load('redirector:default'); - - if (!$this->modx->loadClass('redirector.request.redirectorControllerRequest',$this->config['modelPath'],true,true)) { - return 'Could not load controller request handler.'; - } - $this->request = new redirectorControllerRequest($this); - return $this->request->handleRequest(); - break; - case 'connector': - if (!$this->modx->loadClass('redirector.request.redirectorConnectorRequest',$this->config['modelPath'],true,true)) { - echo 'Could not load connector request handler.'; die(); - } - $this->request = new redirectorConnectorRequest($this); - return $this->request->handle(); - break; - default: break; - } - return true; - } - /** * Gets a Chunk and caches it; also falls back to file-based templates * for easier debugging. diff --git a/core/components/redirector/model/redirector/request/redirectorconnectorrequest.class.php b/core/components/redirector/model/redirector/request/redirectorconnectorrequest.class.php deleted file mode 100644 index 2f635cd..0000000 --- a/core/components/redirector/model/redirector/request/redirectorconnectorrequest.class.php +++ /dev/null @@ -1,49 +0,0 @@ -modx,$config); - $this->redirector =& $redirector; - } - - public function handle($action = '') { - if (empty($action) && !empty($_REQUEST['action'])) $action = $_REQUEST['action']; - if (!isset($this->modx->error)) $this->loadErrorHandler(); - - $path = $this->redirector->config['processorsPath'].strtolower($action).'.php'; - $processorOutput = false; - if (file_exists($path)) { - $this->modx->lexicon->load('redirector:default'); - $modx =& $this->modx; - $redirector =& $this->redirector; - - $scriptProperties = $_REQUEST; - - $processorOutput = include $path; - } else { - $processorOutput = $this->modx->error->failure('Action not found: '.print_r($_POST,true)); - } - if (is_array($processorOutput)) { - $processorOutput = $this->modx->toJSON(array( - 'success' => isset($processorOutput['success']) ? $processorOutput['success'] : 0, - 'message' => isset($processorOutput['message']) ? $processorOutput['message'] : $this->modx->lexicon('error'), - 'total' => (isset($processorOutput['total']) && $processorOutput['total'] > 0) - ? intval($processorOutput['total']) - : (isset($processorOutput['errors']) - ? count($processorOutput['errors']) - : 1), - 'data' => isset($processorOutput['errors']) ? $processorOutput['errors'] : array(), - 'object' => isset($processorOutput['object']) ? $processorOutput['object'] : array(), - )); - } - - if (!isset($_FILES) && empty($_FILES)) { - header("Content-Type: text/json; charset=UTF-8"); - } - return $processorOutput; - } -} \ No newline at end of file diff --git a/core/components/redirector/model/redirector/request/redirectorcontrollerrequest.class.php b/core/components/redirector/model/redirector/request/redirectorcontrollerrequest.class.php deleted file mode 100644 index 4307dfe..0000000 --- a/core/components/redirector/model/redirector/request/redirectorcontrollerrequest.class.php +++ /dev/null @@ -1,56 +0,0 @@ -modx); - $this->redirector =& $redirector; - } - - /** - * Extends modRequest::handleRequest and loads the proper error handler and - * actionVar value. - * - * {@inheritdoc} - */ - public function handleRequest() { - $this->loadErrorHandler(); - - /* save page to manager object. allow custom actionVar choice for extending classes. */ - $this->action = isset($_REQUEST[$this->actionVar]) ? $_REQUEST[$this->actionVar] : $this->defaultAction; - - return $this->_prepareResponse(); - } - - /** - * Prepares the MODx response to a mgr request that is being handled. - * - * @access public - * @return boolean True if the response is properly prepared. - */ - protected function _prepareResponse() { - $modx =& $this->modx; - $redirector =& $this->redirector; - $viewHeader = include $this->redirector->config['corePath'].'controllers/mgr/header.php'; - - $f = $this->redirector->config['corePath'].'controllers/mgr/'.$this->action.'.php'; - if (file_exists($f)) { - $viewOutput = include $f; - } else { - $viewOutput = 'Action not found: '.$f; - } - - return $viewHeader.$viewOutput; - } -} \ No newline at end of file diff --git a/core/components/redirector/model/redirector/sqlsrv/modredirect.class.php b/core/components/redirector/model/redirector/sqlsrv/modredirect.class.php old mode 100644 new mode 100755 diff --git a/core/components/redirector/model/redirector/sqlsrv/modredirect.map.inc.php b/core/components/redirector/model/redirector/sqlsrv/modredirect.map.inc.php old mode 100644 new mode 100755 index cc0098d..4b807d2 --- a/core/components/redirector/model/redirector/sqlsrv/modredirect.map.inc.php +++ b/core/components/redirector/model/redirector/sqlsrv/modredirect.map.inc.php @@ -9,6 +9,7 @@ array ( 'pattern' => '', 'target' => '', + 'context_key' => '', 'active' => 1, ), 'fieldMeta' => @@ -31,6 +32,15 @@ 'default' => '', 'index' => 'index', ), + 'context_key' => + array ( + 'dbtype' => 'nvarchar', + 'precision' => '255', + 'phptype' => 'string', + 'null' => true, + 'default' => null, + 'index' => 'index', + ), 'active' => array ( 'dbtype' => 'bit', @@ -40,4 +50,29 @@ 'index' => 'index', ), ), + 'indexes' => + array( + 'pattern_context' => + array ( + 'alias' => 'pattern_context', + 'primary' => true, + 'unique' => true, + 'type' => 'BTREE', + 'columns' => + array ( + 'pattern' => + array ( + 'length' => '100', + 'collation' => 'A', + 'null' => false, + ), + 'context_key' => + array ( + 'length' => '100', + 'collation' => 'A', + 'null' => false, + ), + ), + ), + ), ); diff --git a/core/components/redirector/model/schema/redirector.mysql.schema.xml b/core/components/redirector/model/schema/redirector.mysql.schema.xml old mode 100644 new mode 100755 index 7aeb785..b728ac5 --- a/core/components/redirector/model/schema/redirector.mysql.schema.xml +++ b/core/components/redirector/model/schema/redirector.mysql.schema.xml @@ -1,8 +1,18 @@ - + - + + + + + + + + + + + \ No newline at end of file diff --git a/core/components/redirector/model/schema/redirector.sqlsrv.schema.xml b/core/components/redirector/model/schema/redirector.sqlsrv.schema.xml old mode 100644 new mode 100755 index cba3ef4..546bf97 --- a/core/components/redirector/model/schema/redirector.sqlsrv.schema.xml +++ b/core/components/redirector/model/schema/redirector.sqlsrv.schema.xml @@ -1,8 +1,18 @@ - + + + + + + + + + + + \ No newline at end of file diff --git a/core/components/redirector/processors/mgr/contexts/getlist.class.php b/core/components/redirector/processors/mgr/contexts/getlist.class.php new file mode 100755 index 0000000..c236d90 --- /dev/null +++ b/core/components/redirector/processors/mgr/contexts/getlist.class.php @@ -0,0 +1,22 @@ +where(array('key:!=' => 'mgr')); + + $query = $this->getProperty('query'); + if(!empty($query)) { + $c->andCondition(array( + 'key:LIKE' => '%'.$query.'%' + )); + } + return $c; + } +} +return 'ContextsGetListProcessor'; \ No newline at end of file diff --git a/core/components/redirector/processors/mgr/import/import.class.php b/core/components/redirector/processors/mgr/import/import.class.php new file mode 100755 index 0000000..1217718 --- /dev/null +++ b/core/components/redirector/processors/mgr/import/import.class.php @@ -0,0 +1,141 @@ +getProperty('csv_data_file'); + $csvData = $this->getProperty('csv_data_raw'); + $allData = array(); + + // raw data csv + if(!empty($csvData)) { + $data = str_getcsv($csvData, "\n"); + foreach($data as $line) { + $line = str_getcsv($line, ';', ''); + $allData[] = $line; + } + } + + // file data csv + if(!empty($csvFile) && $csvFile['size'] > 0) { + $fh = fopen($csvFile['tmp_name'], "r"); + while (($line = fgetcsv($fh, 1000, ";")) !== FALSE) { + $allData[] = $line; + } + } + + $total = count($allData); + $succeed = $failed = 0; + foreach($allData as $line) { + + // figure out context + $context = ((isset($line[2]) && !empty($line[2])) ? $line[2] : ''); + + // validate pattern + $valid = $this->validate('pattern', $line[0], $context); + if(!$valid) { + $failed++; + $this->modx->log(modX::LOG_LEVEL_ERROR, '[REDIRECTOR] Pattern URI already exists for "'.$line[0].'"'); + continue; + } + + // validate target + $valid = $this->validate('target', $line[1], $context); + if(!$valid) { + $failed++; + $this->modx->log(modX::LOG_LEVEL_ERROR, '[REDIRECTOR] Target URI not-exists for "'.$line[0].'"'); + continue; + } + + // create entry + $saved = $this->createRedirect($line); + if(!$saved) { + $failed++; + $this->modx->log(modX::LOG_LEVEL_ERROR, '[REDIRECTOR] Failed to import redirect: "'.$line[0].'" > "'.$line[1].'"'); + continue; + } + + $succeed++; + } + + if(empty($total)) { + return $this->failure($this->modx->lexicon('redirector.import.failed')); + } + return $this->success($this->modx->lexicon('redirector.import.success', array( + 'total' => $total, + 'succeed' => $succeed, + 'failed' => $failed, + ))); + } + + private function createRedirect($data=array()) { + + // when necessary info is empty + if((isset($data[0]) && empty($data[0])) || (isset($data[1]) && empty($data[1]))) { + return false; + } + + /** @var modRedirect $redirect */ + $redirect = $this->modx->newObject('modRedirect'); + $redirect->fromArray(array( + 'pattern' => ltrim($data[0], '/'), + 'target' => ltrim($data[1], '/'), + )); + + // figure out context key + if(isset($data[2]) && !empty($data[2])) { + + $contextKey = null; + if(in_array($data[2], $this->loadedContexts)) { + $contextKey = $data[2]; + } else { + $context = $this->modx->getObject('modContext', array('key' => strtolower($data[2]))); + if(!empty($context) && is_object($context)) { + $this->loadedContexts[] = $contextKey = $context->get('key'); + } + } + + $redirect->set('context_key', $contextKey); + } + + return $redirect->save(); + } + + private function validate($type='pattern', $uri, $context='') { + + switch($type) { + case 'target': + $target = $this->getProperty('target'); + $this->modx->getParser(); + $this->modx->parser->processElementTags('', $target, true, true); + + $criteria = array('uri' => $uri); + if(!empty($context)) { $criteria['context_key'] = $context; } + $resource = $this->modx->getObject('modResource', $criteria); + if(empty($resource) || !is_object($resource)) { + return false; + } + break; + + case 'pattern': + default: + $criteria = array('uri' => $uri); + if(!empty($context)) { $criteria['context_key'] = $context; } + $resource = $this->modx->getObject('modResource', $criteria); + if(!empty($resource) && is_object($resource)) { + return false; + } + break; + } + return true; + } +} + +return 'RedirectorImportCSVProcessor'; \ No newline at end of file diff --git a/core/components/redirector/processors/mgr/redirect/create.class.php b/core/components/redirector/processors/mgr/redirect/create.class.php index 57f27ac..bcd3d03 100755 --- a/core/components/redirector/processors/mgr/redirect/create.class.php +++ b/core/components/redirector/processors/mgr/redirect/create.class.php @@ -1,21 +1,41 @@ -properties)) { - $this->setProperty('active', '0'); - } - return parent::beforeSet(); - } -} +getProperty('context_key'); + if(empty($context)) { + $this->setProperty('context_key', NULL); + } + + // check if pattern is an existing resource + $criteria = array('uri' => $this->getProperty('pattern')); + if(!empty($context)) { $criteria['context_key'] = $context; } + $resource = $this->modx->getObject('modResource', $criteria); + if(!empty($resource) && is_object($resource)) { + $this->addFieldError('pattern', 'URI exists for Resource ID '.$resource->get('id').' in "'.$resource->get('context_key').'" context... Redirect will not work!'); + } + + // check if target is an NON existing resource + $target = $this->getProperty('target'); + if(!strpos($target, '://') && !strpos($target, '$')) { + + $this->modx->getParser(); + $this->modx->parser->processElementTags('', $target, true, true); + + $criteria = array('uri' => $target); + if(!empty($context)) { $criteria['context_key'] = $context; } + $resource = $this->modx->getObject('modResource', $criteria); + if(empty($resource) || !is_object($resource)) { + $this->addFieldError('target', 'Resource doesn\'t exists! Redirect won\'t work...'); + } + } + + return parent::beforeSet(); + } +} + return 'RedirectorCreateProcessor'; \ No newline at end of file diff --git a/core/components/redirector/processors/mgr/redirect/getlist.class.php b/core/components/redirector/processors/mgr/redirect/getlist.class.php index e1d9536..a6942eb 100755 --- a/core/components/redirector/processors/mgr/redirect/getlist.class.php +++ b/core/components/redirector/processors/mgr/redirect/getlist.class.php @@ -1,48 +1,66 @@ -getProperty('query'); - if (!empty($query)) { - $c->where(array( - 'pattern:LIKE' => '%'.$query.'%', - )); - $c->orCondition(array( - 'target:LIKE' => '%'.$query.'%', - )); - } - - return $c; - } - - public function prepareRow(xPDOObject $object) { - $objectArray = $object->toArray(); - - $objectArray['menu'] = array(); - $objectArray['menu'][] = array( - 'text' => $this->modx->lexicon('redirector.redirect_update'), - 'handler' => 'this.updateRedirect', - ); - $objectArray['menu'][] = '-'; - $objectArray['menu'][] = array( - 'text' => $this->modx->lexicon('redirector.redirect_remove'), - 'handler' => 'this.removeRedirect', - ); - - return $objectArray; - } -} -return 'RedirectorGetListProcessor'; +getProperty('query'); + if(!empty($query)) { + $c->andCondition(array( + 'pattern:LIKE' => '%'.$query.'%', + 'OR:target:LIKE' => '%'.$query.'%', + )); + } + + $context = $this->getProperty('context'); + if(!empty($context)) { + $c->andCondition(array( + 'context_key:LIKE' => '%'.$context.'%', + )); + } + + return $c; + } + + public function prepareRow(xPDOObject $object) { + $arr = $object->toArray(); + $arr['valid'] = true; + $arr['resource_id'] = ''; + $arr['resource_ctx'] = ''; + + // find out if pattern URI exists + $criteria = array('uri' => $object->get('pattern')); + if(!empty($arr['context_key'])) { + $criteria['context_key'] = $object->get('context_key'); + } + + $resource = $this->modx->getObject('modResource', $criteria); + if(!empty($resource) && is_object($resource)) { + $arr['resource_id'] = $resource->get('id'); + $arr['resource_ctx'] = $resource->get('context_key'); + $arr['valid'] = false; + } + + // OR target not exists + if(!strpos($arr['target'], '://') && !strpos($arr['target'], '$')) { + $criteria = array('uri' => $object->get('target')); + if(!empty($arr['context_key'])) { + $criteria['context_key'] = $object->get('context_key'); + } + + $resource = $this->modx->getObject('modResource', $criteria); + if(empty($resource) || !is_object($resource)) { + $arr['valid'] = false; + } + } + + return $arr; + } +} + +return 'RedirectorGetListProcessor'; \ No newline at end of file diff --git a/core/components/redirector/processors/mgr/redirect/remove.class.php b/core/components/redirector/processors/mgr/redirect/remove.class.php index 98da8c1..745925f 100755 --- a/core/components/redirector/processors/mgr/redirect/remove.class.php +++ b/core/components/redirector/processors/mgr/redirect/remove.class.php @@ -1,13 +1,9 @@ -properties)) { - $this->setProperty('active', '0'); - } - return parent::beforeSet(); - } -} -return 'RedirectorUpdateProcessor'; +getProperty('context_key'); + if(empty($context)) { + $this->setProperty('context_key', NULL); + } + $context = $this->getProperty('context_key'); + + // check if pattern is an existing resource + $criteria = array('uri' => $this->getProperty('pattern')); + if(!empty($context)) { $criteria['context_key'] = $context; } + $resource = $this->modx->getObject('modResource', $criteria); + if(!empty($resource) && is_object($resource)) { + $this->addFieldError('pattern', 'URI exists for Resource ID '.$resource->get('id').' in "'.$resource->get('context_key').'" context... Redirect will not work!'); + } + + // check if target is an NON existing resource + $target = $this->getProperty('target'); + if(!strpos($target, '://') && !strpos($target, '$')) { + + $this->modx->getParser(); + $this->modx->parser->processElementTags('', $target, true, true); + + $criteria = array('uri' => $target); + if(!empty($context)) { $criteria['context_key'] = $context; } + $resource = $this->modx->getObject('modResource', $criteria); + if(empty($resource) || !is_object($resource)) { + $this->addFieldError('target', 'Resource doesn\'t exists! Redirect won\'t work...'); + } + } + + return parent::beforeSet(); + } +} + +return 'RedirectorUpdateProcessor'; \ No newline at end of file diff --git a/core/components/redirector/processors/mgr/redirect/updatefromgrid.class.php b/core/components/redirector/processors/mgr/redirect/updatefromgrid.class.php index f37f715..ae70a01 100755 --- a/core/components/redirector/processors/mgr/redirect/updatefromgrid.class.php +++ b/core/components/redirector/processors/mgr/redirect/updatefromgrid.class.php @@ -1,17 +1,18 @@ -modx->fromJSON($this->getProperty('data')); - if (!is_array($data)) return $this->modx->error->failure('Invalid data.'); - $this->setProperties($data); - $this->unsetProperty('data'); - - return parent::initialize(); - } -} -return 'RedirectorUpdateFromGridProcessor'; +getProperty('data'); + if (empty($data)) return $this->modx->lexicon('invalid_data'); + $data = $this->modx->fromJSON($data); + if (empty($data)) return $this->modx->lexicon('invalid_data'); + $this->setProperties($data); + $this->unsetProperty('data'); + + return parent::initialize(); + } +} + +return 'RedirectorUpdateFromGridProcessor'; \ No newline at end of file diff --git a/core/components/redirector/processors/mgr/resources/getlist.class.php b/core/components/redirector/processors/mgr/resources/getlist.class.php new file mode 100755 index 0000000..da74b91 --- /dev/null +++ b/core/components/redirector/processors/mgr/resources/getlist.class.php @@ -0,0 +1,29 @@ +getProperty('query'); + if(!empty($query)) { + $c->andCondition(array( + 'id' => $query, + 'OR:pagetitle:LIKE' => '%'.$query.'%', + )); + } + return $c; + } + + public function prepareRow(xPDOObject $object) { + $arr = $object->toArray(); + $arr['pagetitle'] .= ' ('.$object->get('context_key').', '.$object->get('id').')'; + + return $arr; + } +} +return 'ResourcesGetListProcessor'; \ No newline at end of file diff --git a/core/components/redirector/templates/home.tpl b/core/components/redirector/templates/home.tpl new file mode 100755 index 0000000..24527e1 --- /dev/null +++ b/core/components/redirector/templates/home.tpl @@ -0,0 +1 @@ +
\ No newline at end of file