diff --git a/README.md b/README.md index 4656afa..820910f 100755 --- a/README.md +++ b/README.md @@ -1,50 +1,50 @@ -# SyncX - Component sync for MODX Evolution - -## What does it do? -How often have you modified a chunk or snippet in MODX and then wanted to go back to the previous version? Or done a round of updates which needed reverting, and cursed that your components weren't under version control? - -Curse no more. This module for MODX Evolution (tested with 1.0.5) allows components stored in the database (chunks, snippets, templates, plugins) to be copied to the file system and vice versa. This enables them to be easily edited using your favourite text editor, and also stored under version control. - -### WARNING: - -Currently MODX has no way to determine when a component in the database was modified (we have a patch on the way for that...). This script is very naive, and will overwrite all items in the database/file system regardless of which is newer. **You have been warned!** - -## To install - -Assuming you are logged into a terminal and already in your MODX site's root directory, the following commands are all you need to use: - - $ cd assets/modules - $ git clone git://github.com/mapledesign/modx-component-sync.git component-sync - -## To use - -You can either run the module from the command line as follows: - - $ cd assets/modules/component-sync/ - $ php ./cmd.php dump - -or - - $ php ./cmd.php load - -or you can install the web-based module. - -To do this, go to Modules -> Manage modules. -Click on the 'New Module' button -Give the module a name (e.g. 'Component Sync') and paste the following code in as the module code: - - include $modx->config['base_path'].'assets/modules/component-sync/module.php'; - -Run the module, and follow the on-screen prompts. - -That really is all there is to it! - -## Colophon - -SyncX was developed by Peter Bowyer and the team at Maple Design Ltd. We build custom MODX applications and add-ons like this [easy to manage photo gallery](http://www.youtube.com/watch?v=SUbM_D2GT4s) to make your clients' lives easier. [Contact us](http://www.mapledesign.co.uk/services/s/content-management-systems/modx-development/) to find out how we can help! - -This code should be considered alpha-quality. We are using it but have not extensively tested it. - -Feedback, bug reports, questions and usage scenarios we've not considered are all welcome. Please use the ticket system here on Github. - -The code is licensed under the MIT license, and eventually we'll add license headers to the code :) +# SyncX - Component sync for MODX Evolution + +## What does it do? +How often have you modified a chunk or snippet in MODX and then wanted to go back to the previous version? Or done a round of updates which needed reverting, and cursed that your components weren't under version control? + +Curse no more. This module for MODX Evolution (tested with 1.0.5) allows components stored in the database (chunks, snippets, templates, plugins) to be copied to the file system and vice versa. This enables them to be easily edited using your favourite text editor, and also stored under version control. + +### WARNING: + +Currently MODX has no way to determine when a component in the database was modified (we have a patch on the way for that...). This script is very naive, and will overwrite all items in the database/file system regardless of which is newer. **You have been warned!** + +## To install + +Assuming you are logged into a terminal and already in your MODX site's root directory, the following commands are all you need to use: + + $ cd assets/modules + $ git clone git://github.com/mapledesign/modx-component-sync.git component-sync + +## To use + +You can either run the module from the command line as follows: + + $ cd assets/modules/component-sync/ + $ php ./cmd.php dump + +or + + $ php ./cmd.php load + +or you can install the web-based module. + +To do this, go to Modules -> Manage modules. +Click on the 'New Module' button +Give the module a name (e.g. 'Component Sync') and paste the following code in as the module code: + + include $modx->config['base_path'].'assets/modules/component-sync/module.php'; + +Run the module, and follow the on-screen prompts. + +That really is all there is to it! + +## Colophon + +SyncX was developed by Peter Bowyer and the team at Maple Design Ltd. We build custom MODX applications and add-ons like this [easy to manage photo gallery](http://www.youtube.com/watch?v=SUbM_D2GT4s) to make your clients' lives easier. [Contact us](http://www.mapledesign.co.uk/services/s/content-management-systems/modx-development/) to find out how we can help! + +This code should be considered alpha-quality. We are using it but have not extensively tested it. + +Feedback, bug reports, questions and usage scenarios we've not considered are all welcome. Please use the ticket system here on Github. + +The code is licensed under the MIT license, and eventually we'll add license headers to the code :) diff --git a/classes/ComponentBase.php b/classes/ComponentBase.php index a6538fb..02476c6 100755 --- a/classes/ComponentBase.php +++ b/classes/ComponentBase.php @@ -1,55 +1,75 @@ - array( - 'tablename' => 'site_snippets', - 'col_name' => 'name', - 'col_content' => 'snippet', - ), - 'chunks' => array( - 'tablename' => 'site_htmlsnippets', - 'col_name' => 'name', - 'col_content' => 'snippet', - ), - 'plugins' => array( - 'tablename' => 'site_plugins', - 'col_name' => 'name', - 'col_content' => 'plugincode', - ), - 'templates' => array( - 'tablename' => 'site_templates', - 'col_name' => 'templatename', - 'col_content' => 'content', - ), - ); - - public function __construct(&$modx, $type = 'snippets', $foldername = '_db') - { - $this->modx = $modx; - $this->type = $type; - - $this->table = $this->modx->getFullTableName($this->component[$type]['tablename']); - - $this->dir = MODX_BASE_PATH ."assets/$type/$foldername/"; - - if (!file_exists($this->dir) && !is_dir($this->dir)) { - $ret = mkdir($this->dir, 0777, true); - if ($ret == false && !is_dir($this->dir)) { - throw new Exception("Cannot create {$this->dir}. Please create directory manually, and set permissions to 0777"); - } - } - } - - protected function statsBlock($label, $array) - { - $o = "$label:\n"; - foreach ($array as $i) { - $o .= "\t$i\n"; - } - $o .= "\n"; - return $o; - } + array( + 'tablename' => 'site_snippets', + 'col_name' => 'name', + 'col_content' => 'snippet', + ), + 'chunks' => array( + 'tablename' => 'site_htmlsnippets', + 'col_name' => 'name', + 'col_content' => 'snippet', + ), + 'plugins' => array( + 'tablename' => 'site_plugins', + 'col_name' => 'name', + 'col_content' => 'plugincode', + ), + 'templates' => array( + 'tablename' => 'site_templates', + 'col_name' => 'templatename', + 'col_content' => 'content', + ), + ); + + public function __construct(&$modx, $type = 'snippets', $foldername = '_db', $eol='') + { + $this->modx = $modx; + $this->type = $type; + + $this->table = $this->modx->getFullTableName($this->component[$type]['tablename']); + + $this->dir = MODX_BASE_PATH ."assets/$type/$foldername/"; + + $this->eol = (empty($eol) or !in_array($eol,explode(",","lf,crlf,cr")))?"":$eol; + + if (!file_exists($this->dir) && !is_dir($this->dir)) { + $ret = mkdir($this->dir, 0777, true); + if ($ret == false && !is_dir($this->dir)) { + throw new Exception("Cannot create {$this->dir}. Please create directory manually, and set permissions to 0777"); + } + } + } + + protected function statsBlock($label, $array) + { + $o = "$label:\n"; + foreach ($array as $i) { + $o .= "\t$i\n"; + } + $o .= "\n"; + return $o; + } + protected function normalizeEol($string) { + if ($this->eol) { + switch ($this->eol) { + case "lf": + $string = preg_replace("/\r\n/s", "\n", $string); + $string = preg_replace("/\r/s", "\n", $string); + break; + case "cr": + $string = preg_replace("/\r\n/s", "\r", $string); + $string = preg_replace("/\r/s", "\r", $string); + break; + case "crlf": + $string = preg_replace("/(?<=[^\r]|^)\n/s", "\r\n", $string); + break; + } + } + return $string; + } } \ No newline at end of file diff --git a/classes/ComponentDump.php b/classes/ComponentDump.php index be939e8..db424cb 100755 --- a/classes/ComponentDump.php +++ b/classes/ComponentDump.php @@ -12,9 +12,9 @@ public function run() } $res = $this->modx->db->query("SELECT * FROM $this->table"); - while ($row = mysql_fetch_assoc($res)) { - $filename = $row[$this->component[$this->type]['col_name']] .'.php'; - file_put_contents($this->dir . $filename, $row[$this->component[$this->type]['col_content']]); + while( $row = $this->modx->db->getRow( $res ) ) { + $filename = $row[$this->component[$this->type]['col_name']] .'.php'; + file_put_contents($this->dir . $filename, $this->normalizeEol($row[$this->component[$this->type]['col_content']])); $fs_items[] = $filename; } diff --git a/classes/ComponentLoad.php b/classes/ComponentLoad.php index c2376bd..a7125b0 100755 --- a/classes/ComponentLoad.php +++ b/classes/ComponentLoad.php @@ -1,77 +1,77 @@ -dir .'*.php'); - - foreach ($files as $file) { - $filename = basename($file, '.php'); - $content = file_get_contents($file); - - // Can't use REPLACE as the name column isn't indexed - #$res = $modx->db->query("REPLACE INTO $table SET {$component[$type]['col_content']} = '". mysql_real_escape_string($content, $modx->db->conn) ."' WHERE {$component[$type]['col_name']} = '". $filename ."'"); - $id = $this->modx->db->getValue("SELECT id FROM $this->table WHERE {$this->component[$this->type]['col_name']} = '". $filename ."'"); - if ($id) { - $res = $this->modx->db->query("UPDATE $this->table SET {$this->component[$this->type]['col_content']} = '". $this->modx->db->escape($content, $this->modx->db->conn) ."' WHERE {$this->component[$this->type]['col_name']} = '". $filename ."'"); - $updated_items[] = $filename; - } else { - $res = $this->modx->db->query("INSERT INTO $this->table SET {$this->component[$this->type]['col_content']} = '". $this->modx->db->escape($content, $this->modx->db->conn) ."', {$this->component[$this->type]['col_name']} = '". $filename ."'"); - $new_items[] = $filename; - } - - - $fs_items[] = $filename; - } - - // Handle items which may now be in the DB/filesystem but are no longer present in the filesystem/db - // (i.e. remove deleted resources) - - - $this->fs_items = $fs_items; - $this->new_items = $new_items; - $this->updated_items = $updated_items; - - - // Clear cache if sync'ing back to DB - as chunks etc are cached there - include_once $this->modx->config['base_path'] ."manager/processors/cache_sync.class.processor.php"; - $sync = new synccache(); - $sync->setCachepath($this->modx->config['base_path'] ."assets/cache/"); - $sync->setReport(false); - $sync->emptyCache(); // first empty the cache - } - - public function getStats() - { - $o = ''; - $o = "###################################################################\n"; - $o .= "# Processing {$this->type}\n"; - $o .= "###################################################################\n\n"; - $o .= "Loaded the following from the file system:\n"; - foreach ($this->fs_items as $i) { - $o .= "\t$i\n"; - } - $o .= "\n"; - - // So our stats method can say which were new components loaded into - // the DB, we need to list the DB contents *BEFORE* we load stuff into it - $res = $this->modx->db->query("SELECT {$this->component[$this->type]['col_name']} AS name FROM $this->table"); - $db_items = $this->modx->db->getColumn('name', $res); - - $items_in_db_not_filesystem = array_diff($db_items, $this->fs_items); - - if (count($items_in_db_not_filesystem) > 0) { - $o .= $this->statsBlock("The following are in the database but NOT the file system", $items_in_db_not_filesystem); - } - - return $o; - } +dir .'*.php'); + + foreach ($files as $file) { + $filename = basename($file, '.php'); + $content = file_get_contents($file); + + // Can't use REPLACE as the name column isn't indexed + #$res = $modx->db->query("REPLACE INTO $table SET {$component[$type]['col_content']} = '". mysql_real_escape_string($content, $modx->db->conn) ."' WHERE {$component[$type]['col_name']} = '". $filename ."'"); + $id = $this->modx->db->getValue("SELECT id FROM $this->table WHERE {$this->component[$this->type]['col_name']} = '". $filename ."'"); + if ($id) { + $res = $this->modx->db->query("UPDATE $this->table SET {$this->component[$this->type]['col_content']} = '". $this->modx->db->escape($content, $this->modx->db->conn) ."' WHERE {$this->component[$this->type]['col_name']} = '". $filename ."'"); + $updated_items[] = $filename; + } else { + $res = $this->modx->db->query("INSERT INTO $this->table SET {$this->component[$this->type]['col_content']} = '". $this->modx->db->escape($content, $this->modx->db->conn) ."', {$this->component[$this->type]['col_name']} = '". $filename ."'"); + $new_items[] = $filename; + } + + + $fs_items[] = $filename; + } + + // Handle items which may now be in the DB/filesystem but are no longer present in the filesystem/db + // (i.e. remove deleted resources) + + + $this->fs_items = $fs_items; + $this->new_items = $new_items; + $this->updated_items = $updated_items; + + + // Clear cache if sync'ing back to DB - as chunks etc are cached there + include_once $this->modx->config['base_path'] ."manager/processors/cache_sync.class.processor.php"; + $sync = new synccache(); + $sync->setCachepath($this->modx->config['base_path'] ."assets/cache/"); + $sync->setReport(false); + $sync->emptyCache(); // first empty the cache + } + + public function getStats() + { + $o = ''; + $o = "###################################################################\n"; + $o .= "# Processing {$this->type}\n"; + $o .= "###################################################################\n\n"; + $o .= "Loaded the following from the file system:\n"; + foreach ($this->fs_items as $i) { + $o .= "\t$i\n"; + } + $o .= "\n"; + + // So our stats method can say which were new components loaded into + // the DB, we need to list the DB contents *BEFORE* we load stuff into it + $res = $this->modx->db->query("SELECT {$this->component[$this->type]['col_name']} AS name FROM $this->table"); + $db_items = $this->modx->db->getColumn('name', $res); + + $items_in_db_not_filesystem = array_diff($db_items, $this->fs_items); + + if (count($items_in_db_not_filesystem) > 0) { + $o .= $this->statsBlock("The following are in the database but NOT the file system", $items_in_db_not_filesystem); + } + + return $o; + } } \ No newline at end of file diff --git a/cmd.php b/cmd.php index c95f568..5ef86d7 100755 --- a/cmd.php +++ b/cmd.php @@ -1,32 +1,34 @@ -run(); - echo $c->getStats(); - } catch (Exception $e) { - echo $e->getMessage(); - } +run(); + echo $c->getStats(); + } catch (Exception $e) { + echo $e->getMessage(); + } } \ No newline at end of file diff --git a/lang/english.php b/lang/english.php index c93dc1a..e520f03 100644 --- a/lang/english.php +++ b/lang/english.php @@ -8,6 +8,9 @@ $_lang['agree'] = 'I understand that all changes I\'ve made in the file system will be overwritten, and it is my responsibility to back them up (e.g. using version control)'; $_lang['results'] = 'Results'; $_lang['checkagree'] = 'You must tick the box!'; +$_lang['in_database'] = 'database'; +$_lang['in_filesystem'] = 'file system'; + //$_lang[''] = ''; // diff --git a/lang/russian-UTF8.php b/lang/russian-UTF8.php new file mode 100644 index 0000000..44a743d --- /dev/null +++ b/lang/russian-UTF8.php @@ -0,0 +1,21 @@ +файловой системе будут перезаписаны, и это моя обязанность, чтобы поддержать их (например, с помощью контроля версий)'; +$_lang['results'] = 'Результат'; +$_lang['checkagree'] = 'Вы должны поставить галочку!'; +$_lang['in_database'] = 'базе данных'; +$_lang['in_filesystem'] = 'файловой системе'; +//$_lang[''] = ''; +// + + + + + + + diff --git a/lang/russian.php b/lang/russian.php new file mode 100644 index 0000000..01cee28 --- /dev/null +++ b/lang/russian.php @@ -0,0 +1,9 @@ +' . $contents); + $modx_lang_attribute = 'ru'; // Manager HTML/XML Language Attribute see http://en.wikipedia.org/wiki/ISO_639-1 + $modx_manager_charset = 'windows-1251'; + setlocale (LC_ALL, 'ru_RU.CP1251'); +?> \ No newline at end of file diff --git a/module.php b/module.php index 66d704c..38e6b52 100755 --- a/module.php +++ b/module.php @@ -1,80 +1,82 @@ - -config['manager_language'] . '.php')) { - include(MODX_BASE_PATH . 'assets/modules/component-sync/lang/' . $modx->config['manager_language'] . '.php'); -} -?> - - - -
-'; - echo $c->getStats(); - echo ''; - } catch (Exception $e) { - echo '
'.$e->getMessage().''; - } -} -endif; ?> - -
'; + echo $c->getStats(); + echo ''; + } catch (Exception $e) { + echo '
'.$e->getMessage().''; + } +} +endif; ?> + +