Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch 'master' of git@github.com:jbroadway/elefant

  • Loading branch information...
commit cceb7eb17a9b40a6606328a45945763f40b6997f 2 parents 66b089f + e834282
@jbroadway authored
View
18 apps/admin/handlers/validator.php
@@ -7,15 +7,25 @@
* validation.
*/
-if (count ($this->params) != 2) {
+if (count ($this->params) < 2) {
die ('Usage: /admin/validator/app/form');
-} elseif (! preg_match ('/^[a-zA-Z0-9_-]+$/', $this->params[0]) || ! preg_match ('/^[a-zA-Z0-9_-]+$/', $this->params[1])) {
+}
+
+$app = array_shift ($this->params);
+
+if (count ($this->params) > 1) {
+ $form = join ('/', $this->params);
+} else {
+ $form = $this->params[0];
+}
+
+if (! preg_match ('/^[a-zA-Z0-9_-]+$/', $app) || ! preg_match ('/^[a-zA-Z0-9\/_-]+$/', $form)) {
die ('Invalid app or form name');
-} elseif (! @file_exists ('apps/' . $this->params[0] . '/forms/' . $this->params[1] . '.php')) {
+} elseif (! @file_exists ('apps/' . $app . '/forms/' . $form . '.php')) {
die ('Form not found');
}
-$rules = file_get_contents ('apps/' . $this->params[0] . '/forms/' . $this->params[1] . '.php');
+$rules = file_get_contents ('apps/' . $app . '/forms/' . $form . '.php');
$rules = preg_replace ('/\$_(GET|POST|REQUEST)\[\'?(.+?)\'?\]/', '\2', $rules);
$rules = parse_ini_string ($rules, true);
View
4 apps/translator/handlers/build.php
@@ -61,8 +61,8 @@
}
} else {
// parse for i18n_getf?() syntax
- preg_match_all ('/i18n_getf? ?\([\'"](.*?)[\'"]\)/', $data, $matches);
- foreach ($matches[1] as $str) {
+ preg_match_all ('/(i18n_getf?|__) ?\([\'"](.*?)[\'"]\)/', $data, $matches);
+ foreach ($matches[2] as $str) {
$str = stripslashes ($str);
if (! isset ($list[$str])) {
$list[$str] = array (
View
74 conf/elefant
@@ -50,6 +50,7 @@ Usage:
Commands:
install Run the command line installer
+ update Check for and apply Elefant updates
backup <path> Save a backup of the site and db
export-db <file> Export the db to a file or STDOUT
import-db <file> Import a schema file into the db
@@ -703,6 +704,79 @@ if (count ($argv) > 1) {
/**
+ * This command checks for and applies updates
+ * to the Elefant CMS software. It should be
+ * used only after `./conf/elefant backup` has
+ * been run, as it will apply the updates to
+ * the current site files via the Unix patch
+ * command and `./conf/elefant import-db`.
+ */
+ case 'update':
+ echo "Not implemented yet.\n";
+ break;
+
+ // load the current version
+ require_once ('conf/version.php');
+
+ // get the major/minor version from it
+ $major_minor = preg_replace ('/\.[0-9]+$/', '', ELEFANT_VERSION);
+
+ // fetch the latest version from the server
+ $res = json_decode (
+ file_get_contents (
+ 'http://www.elefantcms.com/updates/check.php?v=' . $major_minor
+ )
+ );
+
+ // are we already up to date?
+ if ($res->latest <= ELEFANT_VERSION) {
+ echo "Already up-to-date.\n";
+ break;
+ }
+
+ // new version ready
+ $latest = $res->latest;
+ echo "New version: {$latest}\n";
+
+ // make sure conf/updates exists
+ if (! file_exists ('conf/updates')) {
+ mkdir ('conf/updates');
+ }
+
+ // check for and download new patch files
+ $res = json_decode (file_get_contents ('http://www.elefantcms.com/updates/patches.php'));
+
+ foreach ($res->patches as $patch_file) {
+ $base = basename ($patch_file);
+ if (! file_exists ('conf/updates/' . $base)) {
+ echo "Fetching new patch: {$base}\n";
+ file_put_contents (
+ 'conf/updates/' . $base,
+ file_get_contents ($patch_file)
+ );
+ // TODO: MD5 checks from 3rd party repo
+ }
+ }
+
+ foreach ($res->scripts as $script_file) {
+ $base = basename ($script_file);
+ if (! file_exists ('conf/updates/' . $base)) {
+ echo "Fetching new db update: {$base}\n";
+ file_put_contents (
+ 'conf/updates/' . $base,
+ file_get_contents ($script_file)
+ );
+ // TODO: MD5 checks from 3rd party repo
+ }
+ }
+
+ // TODO:
+ // 1. determine which patches/db updates need to be run
+ // 2. test and apply the patches and db updates in sequence
+
+
+
+ /**
* Encrypts the specified password in a compatible format
* for storage in the Elefant user table.
*/
View
2  lib/Form.php
@@ -212,7 +212,7 @@ public function __construct ($required_method = 'post', $form_rules = false, $co
// Fetch any form validation rules
if (! empty ($form_rules)) {
if (! file_exists ($form_rules)) {
- list ($app, $form) = explode ('/', $form_rules);
+ list ($app, $form) = explode ('/', $form_rules, 2);
$form_rules = 'apps/' . $app . '/forms/' . $form . '.php';
}
if (file_exists ($form_rules)) {
View
22 lib/Model.php
@@ -820,6 +820,28 @@ public static function batch ($tasks) {
}
return DB::execute ('commit');
}
+
+ /**
+ * Fetch the next incremental value for the specified field.
+ * If no field name is specified, it will use the primary key
+ * field by default.
+ */
+ public function next ($field = false) {
+ if ($field === false) {
+ $field = $this->key;
+ }
+
+ $res = DB::shift (
+ 'select (' . Model::backticks ($field) . ' + 1)' .
+ ' from ' . Model::backticks ($this->table) .
+ ' order by ' . Model::backticks ($field) . ' desc' .
+ ' limit 1'
+ );
+ if (! $res) {
+ return 1;
+ }
+ return $res;
+ }
}
?>
View
122 lib/Template.php
@@ -49,17 +49,24 @@
* {% end %}
*
* Note the use of loop_index and loop_value, which are defined for
- * you inside foreach loops by the template engine.
+ * you inside foreach loops by the template engine, or you can specify
+ * your own key and value names:
*
- * You can also test for more complex conditions, but make sure the
- * value being tested for is not preceeded by anything. For example,
- * no false checks via `{% if !some_val %}`, instead use:
+ * {% for pages as key, page %}
+ * {{ key }} - {{ page }}
+ * {% end %}
*
- * {% if some_val == false %}
- * {{ some_val }}
+ * You can also test for more complex conditions, for example:
+ *
+ * {% if ! some_val %}
+ * No value.
* {% end %}
*
- * Note that `'endif'` and `'endforeach'` are valid as well as `'end'`,
+ * {% if some_val == 'some value' %}
+ * Value: {{ some_val }}
+ * {% end %}
+ *
+ * Note that `endif` and `endforeach` are valid as well as `end`,
* if you prefer, for the sake of clarity.
*
* Here's one more example of how to loop through an array of arrays:
@@ -200,12 +207,37 @@ class Template {
public $cache_folder = 'cache';
/**
- * The controller object used to run includes.
+ * The layouts location.
+ */
+ public $layouts_folder = 'layouts';
+
+ /**
+ * The app view locations.
+ */
+ public $view_folders = 'apps/%s/views/%s';
+
+ /**
+ * Default layout filename.
+ */
+ public $default_layout = 'default';
+
+ /**
+ * File extension.
+ */
+ public $file_extension = 'html';
+
+ /**
+ * The controller object used to run includes. The controller can be
+ * any object that satisfies the following interface:
+ *
+ * interface AbstractController {
+ * public function run ($uri, $data = array ());
+ * }
*/
public $controller = null;
/**
- * Constructor method sets the charset and receives a Controller object.
+ * Constructor method sets the charset and receives a controller object.
*/
public function __construct ($charset = 'UTF-8', $controller = false) {
$this->charset = $charset;
@@ -232,19 +264,19 @@ public function render ($template, $data = array ()) {
// `layouts/default.html`
if (strstr ($template, '/')) {
list ($app, $view) = preg_split ('/\//', $template, 2);
- $file = 'apps/' . $app . '/views/' . $view . '.html';
+ $file = sprintf ($this->view_folders, $app, $view . '.' . $this->file_extension);
if (! file_exists ($file)) {
- $file = 'layouts/' . $app . '/' . $view . '.html';
+ $file = $this->layouts_folder . '/' . $app . '/' . $view . '.' . $this->file_extension;
if (! file_exists ($file)) {
- die ('Template not found: ' . $template);
+ throw new RuntimeException ('Template not found: ' . $template);
}
}
- } elseif (file_exists ('layouts/' . $template . '.html')) {
- $file = 'layouts/' . $template . '.html';
- } elseif (file_exists ('layouts/' . $template . '/' . $template . '.html')) {
- $file = 'layouts/' . $template . '/' . $template . '.html';
+ } elseif (file_exists ($this->layouts_folder . '/' . $template . '.' . $this->file_extension)) {
+ $file = $this->layouts_folder . '/' . $template . '.' . $this->file_extension;
+ } elseif (file_exists ($this->layouts_folder . '/' . $template . '/' . $template . '.' . $this->file_extension)) {
+ $file = $this->layouts_folder . '/' . $template . '/' . $template . '.' . $this->file_extension;
} else {
- $file = 'layouts/default.html';
+ $file = $this->layouts_folder . '/' . $this->default_layout . '.' . $this->file_extension;
}
// The cache file is named based on the original
@@ -255,7 +287,7 @@ public function render ($template, $data = array ()) {
$out = file_get_contents ($file);
$out = $this->parse_template ($out);
if (! file_put_contents ($cache, $out)) {
- die ('Failed to generate cached template: ' . $cache);
+ throw new RuntimeException ('Failed to generate cached template: ' . $cache);
}
}
@@ -278,7 +310,7 @@ public function render_preview ($template, $data = array ()) {
$cache_file = $this->cache_folder . '/_preview_' . md5 ($template) . '.php';
$out = $this->parse_template ($template);
if (! file_put_contents ($cache_file, $out)) {
- die ('Failed to generate cached template: ' . $cache_file);
+ throw new RuntimeException ('Failed to generate cached template: ' . $cache_file);
}
// Include the temp file, then delete it, and return the output
@@ -524,19 +556,32 @@ public static function quotes ($val) {
* {% foreach some_list %}
* {% endforeach %}
*
+ * {% foreach some_list as key, item %}
+ * {% endforeach %}
+ *
+ * {% for some_list %}
+ * {% endfor %}
+ *
+ * {% for some_list as item %}
+ * {% endfor %}
+ *
* {% if statement %}
* {% elseif statement %}
* {% else %}
* {% endif %}
*
- * You can also use `{% end %}` as an alias for both `{% endforeach %}`
- * or `{% endif %}`.
+ * Note: `for` and `endfor` are aliases of `foreach` and `endforeach`.
+ * You can also use `{% end %}` as an alias for `{% endforeach %}`,
+ * `{% endfor %}` or `{% endif %}`.
+ *
+ * If an `as` clause isn't specified, the current loop index is available
+ * via `{{ loop_index }}~ and the current loop value is available via `{{ loop_value }}`.
*
- * The current loop index is available via `{{ loop_index }}` and
- * the current loop value is available via `{{ loop_value }}`.
+ * If an `as` clause is specified without a key, the current loop index is available
+ * via `{{ loop_index }}`.
*/
public function replace_blocks ($val) {
- if ($val === 'end' || $val === 'endif' || $val === 'endforeach') {
+ if ($val === 'end' || $val === 'endif' || $val === 'endforeach' || $val === 'endfor') {
return '<?php } ?>';
}
@@ -551,6 +596,17 @@ public function replace_blocks ($val) {
return '<?php echo $this->render (\'' . $extra . '\', $data); ?>';
}
+ if (($block === 'if' || $block === 'elseif') && strpos (ltrim ($extra), '!') === 0) {
+ $not = '! ';
+ $extra = ltrim ($extra, '! ');
+ } else {
+ $not = '';
+ }
+
+ if (($block === 'foreach' || $block === 'for') && strpos ($extra, ' in ') !== false) {
+ $extra = preg_replace ('/^(.*) in (.*)$/', '\2 as \1', $extra);
+ }
+
if (strstr ($extra, '$_')) {
if (strstr ($val, '.')) {
$extra = preg_replace ('/\.([a-zA-Z0-9_]+)/', '[\'\1\']', $extra, 1);
@@ -560,16 +616,26 @@ public function replace_blocks ($val) {
} elseif (! strstr ($extra, '::') && ! strstr ($extra, '(')) {
$extra = '$data->' . $extra;
}
- if ($block === 'foreach') {
+ if ($block === 'foreach' || $block === 'for') {
+ if (strpos ($extra, ' as ') !== false) {
+ if (strpos ($extra, ', ') === false) {
+ return '<?php foreach (' . str_replace (' as ', ' as $data->loop_index => $data->', $extra) . ') { ?>';
+ }
+ return '<?php foreach (' . str_replace (
+ array (' as ', ', '),
+ array (' as $data->', ' => $data->'),
+ $extra
+ ) . ') { ?>';
+ }
return '<?php foreach (' . $extra . ' as $data->loop_index => $data->loop_value) { ?>';
} elseif ($block === 'if') {
- return '<?php if (' . $extra . ') { ?>';
+ return '<?php if (' . $not . $extra . ') { ?>';
} elseif ($block === 'elseif') {
- return '<?php } elseif (' . $extra . ') { ?>';
+ return '<?php } elseif (' . $not . $extra . ') { ?>';
} elseif ($block === 'else') {
return '<?php } else { ?>';
}
- die ('Invalid template block: ' . $val);
+ throw new LogicException ('Invalid template block: ' . $val);
}
}
View
9 lib/View.php
@@ -80,7 +80,7 @@
* // we can't pass $this to use()
* $c = $this;
*
- * echo View::render (function $params) use ($c) {
+ * echo View::render (function ($params) use ($c) {
* if (! $c->is_https ()) {
* $c->force_https ();
* }
@@ -102,7 +102,12 @@ class View {
public static $params = array ();
/**
- * Sets the template renderer.
+ * Sets the template renderer. The renderer can be any object
+ * that satisfies the following interface:
+ *
+ * interface AbstractTemplateRenderer {
+ * public function render ($template, $data = array ());
+ * }
*/
public static function init ($tpl) {
self::$tpl = $tpl;
View
11 lib/vendor/ActiveResource.php
@@ -158,15 +158,16 @@ public function __construct ($data = array ()) {
$this->_data = $data;
// Allow class-defined element name or use class name if not defined
$this->element_name = $this->element_name ? $this->element_name : strtolower (get_class ($this));
- $this->element_name_plural = $this->pluralize ($this->element_name);
// Detect for namespaces, and take just the class name
- if (stripos($this->element_name, '\\'))
- {
- $classItems = explode('\\', $this->element_name);
- $this->element_name = end($classItems);
+ if (stripos ($this->element_name, '\\')) {
+ $classItems = explode ('\\', $this->element_name);
+ $this->element_name = end ($classItems);
}
+ // Get the plural name after removing namespaces
+ $this->element_name_plural = $this->pluralize ($this->element_name);
+
// If configuration file (`config.ini.php`) exists use it (overwrite class properties/attribute values).
$config_file_path = dirname (__FILE__) . '/' . 'config.ini.php';
if (file_exists ($config_file_path)) {
View
21 tests/ModelTest.php
@@ -58,6 +58,11 @@ class Book extends Model {
);
}
+class NextTest extends Model {
+ public $table = 'next_test';
+ public $key = 'fieldname';
+}
+
class ModelTest extends PHPUnit_Framework_TestCase {
protected static $q;
@@ -110,6 +115,9 @@ static function setUpBeforeClass () {
insert into book_author (book, author) values (1, 2);
insert into book_author (book, author) values (2, 1);
insert into book_author (book, author) values (2, 2);
+ create table next_test (
+ fieldname int not null
+ );
");
foreach ($sql as $query) {
DB::execute ($query);
@@ -336,6 +344,19 @@ function test_batch () {
$this->assertEquals (4, Foo::query ()->count ());
}
+ function test_next () {
+ $nt = new NextTest;
+
+ $this->assertEquals (1, $nt->next ());
+ $this->assertEquals (1, $nt->next ('fieldname'));
+
+ $nt->fieldname = 5;
+ $nt->put ();
+
+ $this->assertEquals (6, $nt->next ());
+ $this->assertEquals (6, $nt->next ('fieldname'));
+ }
+
function test_references () {
// basic references (belongs_to)
$f = new Foo (array ('id' => 1, 'name' => 'Joe'));
View
14 tests/TemplateTest.php
@@ -30,13 +30,27 @@ function test_replace_blocks () {
$this->assertEquals ($t->replace_blocks ('end'), '<?php } ?>');
$this->assertEquals ($t->replace_blocks ('endif'), '<?php } ?>');
+ $this->assertEquals ($t->replace_blocks ('endfor'), '<?php } ?>');
$this->assertEquals ($t->replace_blocks ('endforeach'), '<?php } ?>');
$this->assertEquals ($t->replace_blocks ('else'), '<?php } else { ?>');
$this->assertEquals ($t->replace_blocks ('if foo'), '<?php if ($data->foo) { ?>');
+ $this->assertEquals ($t->replace_blocks ('if !foo'), '<?php if (! $data->foo) { ?>');
+ $this->assertEquals ($t->replace_blocks ('if ! foo'), '<?php if (! $data->foo) { ?>');
$this->assertEquals ($t->replace_blocks ('if foo.bar'), '<?php if ($GLOBALS[\'foo\']->bar) { ?>');
$this->assertEquals ($t->replace_blocks ('if $_POST.value'), '<?php if ($_POST[\'value\']) { ?>');
$this->assertEquals ($t->replace_blocks ('elseif foo'), '<?php } elseif ($data->foo) { ?>');
+ $this->assertEquals ($t->replace_blocks ('elseif !foo'), '<?php } elseif (! $data->foo) { ?>');
+ $this->assertEquals ($t->replace_blocks ('elseif ! foo'), '<?php } elseif (! $data->foo) { ?>');
$this->assertEquals ($t->replace_blocks ('foreach foo'), '<?php foreach ($data->foo as $data->loop_index => $data->loop_value) { ?>');
+ $this->assertEquals ($t->replace_blocks ('foreach foo as bar'), '<?php foreach ($data->foo as $data->loop_index => $data->bar) { ?>');
+ $this->assertEquals ($t->replace_blocks ('foreach foo as _k, _v'), '<?php foreach ($data->foo as $data->_k => $data->_v) { ?>');
+ $this->assertEquals ($t->replace_blocks ('foreach bar in foo'), '<?php foreach ($data->foo as $data->loop_index => $data->bar) { ?>');
+ $this->assertEquals ($t->replace_blocks ('foreach foo as _k, _v'), '<?php foreach ($data->foo as $data->_k => $data->_v) { ?>');
+ $this->assertEquals ($t->replace_blocks ('for foo'), '<?php foreach ($data->foo as $data->loop_index => $data->loop_value) { ?>');
+ $this->assertEquals ($t->replace_blocks ('for foo as bar'), '<?php foreach ($data->foo as $data->loop_index => $data->bar) { ?>');
+ $this->assertEquals ($t->replace_blocks ('for foo as _k, _v'), '<?php foreach ($data->foo as $data->_k => $data->_v) { ?>');
+ $this->assertEquals ($t->replace_blocks ('for bar in foo'), '<?php foreach ($data->foo as $data->loop_index => $data->bar) { ?>');
+ $this->assertEquals ($t->replace_blocks ('for _k, _v in foo'), '<?php foreach ($data->foo as $data->_k => $data->_v) { ?>');
$this->assertEquals ($t->replace_blocks ('inc foo'), '<?php echo $this->render (\'foo\', $data); ?>');
}
Please sign in to comment.
Something went wrong with that request. Please try again.