Merge branch 'MDL-47200-master' of git://github.com/jleyva/moodle
authorDan Poltawski <dan@moodle.com>
Tue, 30 Sep 2014 07:35:19 +0000 (08:35 +0100)
committerDan Poltawski <dan@moodle.com>
Tue, 30 Sep 2014 07:35:19 +0000 (08:35 +0100)
Conflicts:
version.php

307 files changed:
.gitignore
admin/renderer.php
admin/settings/grades.php
availability/classes/tree.php
availability/condition/completion/classes/condition.php
availability/condition/date/classes/condition.php
availability/condition/grade/classes/condition.php
availability/condition/profile/classes/condition.php
availability/tests/tree_test.php
availability/yui/build/moodle-core_availability-form/moodle-core_availability-form-debug.js
availability/yui/build/moodle-core_availability-form/moodle-core_availability-form-min.js
availability/yui/build/moodle-core_availability-form/moodle-core_availability-form.js
availability/yui/src/form/js/form.js
badges/edit.php
badges/index.php
badges/newbadge.php
badges/view.php
blocks/community/communitycourse.php
calendar/lib.php [changed mode: 0644->0755]
course/classes/management_renderer.php
course/info.php
course/modlib.php
course/publish/backup.php
course/publish/hubselector.php
course/publish/index.php
course/publish/metadata.php
course/resources.php
course/tests/courselib_test.php
enrol/index.php
enrol/locallib.php
enrol/users.php
files/coursefilesedit.php
files/index.php
grade/edit/tree/category_form.php
grade/edit/tree/item_form.php
grade/edit/tree/lib.php
grade/report/grader/lib.php
grade/report/grader/module.js
grade/report/grader/preferences_form.php
grade/report/grader/settings.php
grade/report/history/classes/output/tablelog.php
grade/tests/behat/grade_UI_settings.feature [new file with mode: 0644]
lang/en/grades.php
lang/en/moodle.php
lang/en/plugin.php
lib/adodb/adodb-active-record.inc.php
lib/adodb/adodb-active-recordx.inc.php
lib/adodb/adodb-csvlib.inc.php
lib/adodb/adodb-datadict.inc.php
lib/adodb/adodb-error.inc.php
lib/adodb/adodb-errorhandler.inc.php
lib/adodb/adodb-errorpear.inc.php
lib/adodb/adodb-exceptions.inc.php
lib/adodb/adodb-iterator.inc.php
lib/adodb/adodb-lib.inc.php
lib/adodb/adodb-memcache.lib.inc.php
lib/adodb/adodb-pager.inc.php
lib/adodb/adodb-pear.inc.php
lib/adodb/adodb-perf.inc.php
lib/adodb/adodb-php4.inc.php
lib/adodb/adodb-time.inc.php
lib/adodb/adodb-xmlschema.inc.php
lib/adodb/adodb-xmlschema03.inc.php
lib/adodb/adodb.inc.php
lib/adodb/datadict/datadict-access.inc.php [new file with mode: 0644]
lib/adodb/datadict/datadict-db2.inc.php [new file with mode: 0644]
lib/adodb/datadict/datadict-firebird.inc.php [new file with mode: 0644]
lib/adodb/datadict/datadict-generic.inc.php [new file with mode: 0644]
lib/adodb/datadict/datadict-ibase.inc.php [new file with mode: 0644]
lib/adodb/datadict/datadict-informix.inc.php [new file with mode: 0644]
lib/adodb/datadict/datadict-mssql.inc.php [new file with mode: 0644]
lib/adodb/datadict/datadict-mssqlnative.inc.php [new file with mode: 0644]
lib/adodb/datadict/datadict-mysql.inc.php [new file with mode: 0644]
lib/adodb/datadict/datadict-oci8.inc.php [new file with mode: 0644]
lib/adodb/datadict/datadict-postgres.inc.php [new file with mode: 0644]
lib/adodb/datadict/datadict-sapdb.inc.php [new file with mode: 0644]
lib/adodb/datadict/datadict-sqlite.inc.php [new file with mode: 0644]
lib/adodb/datadict/datadict-sybase.inc.php [new file with mode: 0644]
lib/adodb/drivers/adodb-access.inc.php
lib/adodb/drivers/adodb-ado.inc.php
lib/adodb/drivers/adodb-ado5.inc.php
lib/adodb/drivers/adodb-ado_access.inc.php
lib/adodb/drivers/adodb-ado_mssql.inc.php
lib/adodb/drivers/adodb-ads.inc.php
lib/adodb/drivers/adodb-borland_ibase.inc.php
lib/adodb/drivers/adodb-csv.inc.php
lib/adodb/drivers/adodb-db2.inc.php
lib/adodb/drivers/adodb-db2oci.inc.php
lib/adodb/drivers/adodb-db2ora.inc.php
lib/adodb/drivers/adodb-fbsql.inc.php
lib/adodb/drivers/adodb-firebird.inc.php
lib/adodb/drivers/adodb-ibase.inc.php
lib/adodb/drivers/adodb-informix.inc.php
lib/adodb/drivers/adodb-informix72.inc.php
lib/adodb/drivers/adodb-ldap.inc.php
lib/adodb/drivers/adodb-mssql.inc.php
lib/adodb/drivers/adodb-mssql_n.inc.php
lib/adodb/drivers/adodb-mssqlnative.inc.php
lib/adodb/drivers/adodb-mssqlpo.inc.php
lib/adodb/drivers/adodb-mysql.inc.php
lib/adodb/drivers/adodb-mysqli.inc.php
lib/adodb/drivers/adodb-mysqlpo.inc.php
lib/adodb/drivers/adodb-mysqlt.inc.php
lib/adodb/drivers/adodb-netezza.inc.php
lib/adodb/drivers/adodb-oci8.inc.php
lib/adodb/drivers/adodb-oci805.inc.php
lib/adodb/drivers/adodb-oci8po.inc.php
lib/adodb/drivers/adodb-oci8quercus.inc.php [new file with mode: 0644]
lib/adodb/drivers/adodb-odbc.inc.php
lib/adodb/drivers/adodb-odbc_db2.inc.php
lib/adodb/drivers/adodb-odbc_mssql.inc.php
lib/adodb/drivers/adodb-odbc_oracle.inc.php
lib/adodb/drivers/adodb-odbtp.inc.php
lib/adodb/drivers/adodb-odbtp_unicode.inc.php
lib/adodb/drivers/adodb-oracle.inc.php
lib/adodb/drivers/adodb-pdo.inc.php
lib/adodb/drivers/adodb-pdo_mssql.inc.php
lib/adodb/drivers/adodb-pdo_mysql.inc.php
lib/adodb/drivers/adodb-pdo_oci.inc.php
lib/adodb/drivers/adodb-pdo_pgsql.inc.php
lib/adodb/drivers/adodb-pdo_sqlite.inc.php
lib/adodb/drivers/adodb-postgres.inc.php
lib/adodb/drivers/adodb-postgres64.inc.php
lib/adodb/drivers/adodb-postgres7.inc.php
lib/adodb/drivers/adodb-postgres8.inc.php
lib/adodb/drivers/adodb-postgres9.inc.php
lib/adodb/drivers/adodb-proxy.inc.php
lib/adodb/drivers/adodb-sapdb.inc.php
lib/adodb/drivers/adodb-sqlanywhere.inc.php
lib/adodb/drivers/adodb-sqlite.inc.php
lib/adodb/drivers/adodb-sqlite3.inc.php
lib/adodb/drivers/adodb-sqlitepo.inc.php
lib/adodb/drivers/adodb-sybase.inc.php
lib/adodb/drivers/adodb-sybase_ase.inc.php
lib/adodb/drivers/adodb-vfp.inc.php
lib/adodb/lang/adodb-en.inc.php
lib/adodb/license.txt
lib/adodb/perf/perf-db2.inc.php
lib/adodb/perf/perf-informix.inc.php
lib/adodb/perf/perf-mssql.inc.php
lib/adodb/perf/perf-mssqlnative.inc.php
lib/adodb/perf/perf-mysql.inc.php
lib/adodb/perf/perf-oci8.inc.php
lib/adodb/perf/perf-postgres.inc.php
lib/adodb/pivottable.inc.php
lib/adodb/readme_moodle.txt
lib/adodb/rsfilter.inc.php
lib/adodb/toexport.inc.php
lib/adodb/tohtml.inc.php
lib/adodb/xmlschema.dtd
lib/adodb/xmlschema03.dtd
lib/adodb/xsl/convert-0.1-0.2.xsl
lib/adodb/xsl/convert-0.1-0.3.xsl
lib/adodb/xsl/convert-0.2-0.1.xsl
lib/adodb/xsl/convert-0.2-0.3.xsl
lib/adodb/xsl/remove-0.2.xsl
lib/adodb/xsl/remove-0.3.xsl
lib/classes/plugin_manager.php
lib/classes/update/deployer.php
lib/clilib.php
lib/editor/tinymce/readme_moodle.txt
lib/editor/tinymce/tiny_mce/3.5.10/themes/advanced/skins/moodle/content.css
lib/editor/tinymce/version.php
lib/filelib.php
lib/grade/grade_category.php
lib/grade/grade_grade.php
lib/grade/grade_item.php
lib/markdown/License.md
lib/markdown/Markdown.php
lib/markdown/MarkdownExtra.php
lib/markdown/MarkdownInterface.php
lib/markdown/Readme.md
lib/moodlelib.php
lib/outputcomponents.php
lib/outputrenderers.php
lib/pdflib.php
lib/tcpdf/CHANGELOG.TXT
lib/tcpdf/README.TXT
lib/tcpdf/composer.json
lib/tcpdf/config/tcpdf_config.php
lib/tcpdf/fonts/freemono.php
lib/tcpdf/fonts/freemono.z
lib/tcpdf/fonts/freemonob.ctg.z
lib/tcpdf/fonts/freemonob.php
lib/tcpdf/fonts/freemonob.z
lib/tcpdf/fonts/freemonobi.ctg.z
lib/tcpdf/fonts/freemonobi.php
lib/tcpdf/fonts/freemonobi.z
lib/tcpdf/fonts/freemonoi.ctg.z
lib/tcpdf/fonts/freemonoi.php
lib/tcpdf/fonts/freemonoi.z
lib/tcpdf/fonts/freesans.ctg.z
lib/tcpdf/fonts/freesans.php
lib/tcpdf/fonts/freesans.z
lib/tcpdf/fonts/freesansb.ctg.z
lib/tcpdf/fonts/freesansb.php
lib/tcpdf/fonts/freesansb.z
lib/tcpdf/fonts/freesansbi.ctg.z
lib/tcpdf/fonts/freesansbi.php
lib/tcpdf/fonts/freesansbi.z
lib/tcpdf/fonts/freesansi.ctg.z
lib/tcpdf/fonts/freesansi.php
lib/tcpdf/fonts/freesansi.z
lib/tcpdf/fonts/freeserif.ctg.z
lib/tcpdf/fonts/freeserif.php
lib/tcpdf/fonts/freeserif.z
lib/tcpdf/fonts/freeserifb.ctg.z
lib/tcpdf/fonts/freeserifb.php
lib/tcpdf/fonts/freeserifb.z
lib/tcpdf/fonts/freeserifbi.ctg.z
lib/tcpdf/fonts/freeserifbi.php
lib/tcpdf/fonts/freeserifbi.z
lib/tcpdf/fonts/freeserifi.ctg.z
lib/tcpdf/fonts/freeserifi.php
lib/tcpdf/fonts/freeserifi.z
lib/tcpdf/include/barcodes/datamatrix.php
lib/tcpdf/include/barcodes/pdf417.php
lib/tcpdf/include/sRGB.icc
lib/tcpdf/include/tcpdf_colors.php
lib/tcpdf/include/tcpdf_filters.php
lib/tcpdf/include/tcpdf_fonts.php
lib/tcpdf/include/tcpdf_images.php
lib/tcpdf/include/tcpdf_static.php
lib/tcpdf/readme_moodle.txt
lib/tcpdf/tcpdf.php
lib/tcpdf/tcpdf_autoconfig.php
lib/tcpdf/tcpdf_barcodes_1d.php
lib/tcpdf/tcpdf_barcodes_2d.php
lib/testing/generator/data_generator.php
lib/testing/tests/generator_test.php
lib/tests/moodlelib_test.php
lib/tests/other/pdflibtestpage.php
lib/tests/outputcomponents_test.php
lib/thirdpartylibs.xml
lib/yui/build/moodle-core-notification-dialogue/moodle-core-notification-dialogue-debug.js
lib/yui/build/moodle-core-notification-dialogue/moodle-core-notification-dialogue-min.js
lib/yui/build/moodle-core-notification-dialogue/moodle-core-notification-dialogue.js
lib/yui/src/notification/js/dialogue.js
lib/yuilib/2in3/2.9.0/build/yui2-calendar/yui2-calendar-debug.js
lib/yuilib/2in3/2.9.0/build/yui2-calendar/yui2-calendar-min.js
lib/yuilib/2in3/2.9.0/build/yui2-calendar/yui2-calendar.js
message/index.php
message/output/airnotifier/message_output_airnotifier.php
mod/assign/backup/moodle2/backup_assign_stepslib.php
mod/assign/backup/moodle2/restore_assign_stepslib.php
mod/assign/db/access.php [changed mode: 0644->0755]
mod/assign/db/install.xml [changed mode: 0644->0755]
mod/assign/db/log.php [changed mode: 0644->0755]
mod/assign/db/messages.php [changed mode: 0644->0755]
mod/assign/db/services.php [changed mode: 0644->0755]
mod/assign/db/subplugins.php [changed mode: 0644->0755]
mod/assign/db/upgrade.php [changed mode: 0644->0755]
mod/assign/externallib.php
mod/assign/gradingtable.php
mod/assign/lib.php
mod/assign/locallib.php
mod/assign/mod_form.php
mod/assign/renderer.php
mod/assign/tests/externallib_test.php
mod/assign/tests/lib_test.php
mod/assign/tests/locallib_test.php
mod/assign/upgrade.txt
mod/assign/upgradelib.php
mod/assign/version.php
mod/forum/discuss.php
mod/forum/lib.php
mod/forum/tests/behat/discussion_subscriptions.feature
mod/glossary/showentry.php
mod/lesson/backup/moodle2/backup_lesson_stepslib.php
mod/lesson/backup/moodle2/restore_lesson_activity_task.class.php
mod/lesson/backup/moodle2/restore_lesson_stepslib.php
mod/lesson/editpage.php
mod/lesson/lang/en/lesson.php
mod/lesson/lib.php
mod/lesson/locallib.php
mod/lesson/pagetypes/matching.php
mod/lesson/pagetypes/multichoice.php
mod/lesson/pagetypes/truefalse.php
mod/lesson/tests/behat/questions_images.feature [new file with mode: 0644]
mod/lesson/tests/fixtures/moodle_logo.jpg [new file with mode: 0644]
notes/index.php
question/format/gift/tests/behat/import.feature
question/format/webct/tests/behat/import.feature
question/format/xml/tests/behat/import.feature
theme/base/layout/frontpage.php
theme/base/layout/general.php
theme/base/style/core.css
theme/bootstrapbase/layout/columns1.php
theme/bootstrapbase/layout/columns2.php
theme/bootstrapbase/layout/columns3.php
theme/bootstrapbase/layout/popup.php
theme/bootstrapbase/less/moodle/core.less
theme/bootstrapbase/less/moodle/modules.less
theme/bootstrapbase/less/moodle/responsive.less
theme/bootstrapbase/style/moodle.css
theme/bootstrapbase/yui/build/moodle-theme_bootstrapbase-bootstrap/moodle-theme_bootstrapbase-bootstrap-debug.js
theme/bootstrapbase/yui/build/moodle-theme_bootstrapbase-bootstrap/moodle-theme_bootstrapbase-bootstrap-min.js
theme/bootstrapbase/yui/build/moodle-theme_bootstrapbase-bootstrap/moodle-theme_bootstrapbase-bootstrap.js
theme/bootstrapbase/yui/src/bootstrap/js/bootstrap.js
theme/clean/layout/columns1.php
theme/clean/layout/columns2.php
theme/clean/layout/columns3.php
user/index.php
user/lib.php
user/profile.php
user/view.php
version.php

index 3aced1e..8b976bb 100644 (file)
@@ -35,3 +35,4 @@ composer.lock
 /lib/yuilib/*/build/*/*-coverage.js
 # lib/yuilib/version/module/module-coverage.js
 /lib/yuilib/*/*/*-coverage.js
+atlassian-ide-plugin.xml
index eb3925c..26afb90 100644 (file)
@@ -1039,19 +1039,28 @@ class core_admin_renderer extends plugin_renderer_base {
         }
 
         foreach ($plugin->get_other_required_plugins() as $component => $requiredversion) {
-            $ok = true;
             $otherplugin = $pluginman->get_plugin_info($component);
+            $actions = array();
 
             if (is_null($otherplugin)) {
-                $ok = false;
+                // The required plugin is not installed.
+                $class = 'requires-failed requires-missing';
+                $installurl = new moodle_url('https://moodle.org/plugins/view.php', array('plugin' => $component));
+                $uploadurl = new moodle_url('/admin/tool/installaddon/');
+                $actions[] = html_writer::link($installurl, get_string('dependencyinstall', 'core_plugin'));
+                $actions[] = html_writer::link($uploadurl, get_string('dependencyupload', 'core_plugin'));
+
             } else if ($requiredversion != ANY_VERSION and $otherplugin->versiondisk < $requiredversion) {
-                $ok = false;
-            }
+                // The required plugin is installed but needs to be updated.
+                $class = 'requires-failed requires-outdated';
+                if (!$otherplugin->is_standard()) {
+                    $updateurl = new moodle_url($this->page->url, array('sesskey' => sesskey(), 'fetchupdates' => 1));
+                    $actions[] = html_writer::link($updateurl, get_string('checkforupdates', 'core_plugin'));
+                }
 
-            if ($ok) {
-                $class = 'requires-ok';
             } else {
-                $class = 'requires-failed';
+                // Already installed plugin with sufficient version.
+                $class = 'requires-ok';
             }
 
             if ($requiredversion != ANY_VERSION) {
@@ -1059,11 +1068,11 @@ class core_admin_renderer extends plugin_renderer_base {
             } else {
                 $str = 'otherplugin';
             }
-            $componenturl = new moodle_url('https://moodle.org/plugins/view.php?plugin='.$component);
-            $componenturl = html_writer::tag('a', $component, array('href' => $componenturl->out()));
+
             $requires[] = html_writer::tag('li',
-                    get_string($str, 'core_plugin',
-                            array('component' => $componenturl, 'version' => $requiredversion)),
+                    html_writer::div(get_string($str, 'core_plugin',
+                            array('component' => $component, 'version' => $requiredversion)), 'component').
+                    html_writer::div(implode(' | ', $actions), 'actions'),
                     array('class' => $class));
         }
 
index 6d12d99..2cb6122 100644 (file)
@@ -68,6 +68,10 @@ if (has_capability('moodle/grade:manage', $systemcontext)
 
         $temp->add(new admin_setting_special_gradelimiting());
 
+        $temp->add(new admin_setting_configcheckbox('grade_report_showmin',
+                                                    get_string('minimum_show', 'grades'),
+                                                    get_string('minimum_show_help', 'grades'), '1'));
+
         $temp->add(new admin_setting_special_gradepointmax());
 
         $temp->add(new admin_setting_special_gradepointdefault());
@@ -125,6 +129,9 @@ if (has_capability('moodle/grade:manage', $systemcontext)
         $defaults['forced'] = false;
         $temp->add(new admin_setting_gradecat_combo('grade_droplow', new lang_string('droplow', 'grades'),
                     new lang_string('droplow_help', 'grades'), $defaults, $options));
+
+        $temp->add(new admin_setting_configcheckbox('grade_overridecat', new lang_string('overridecat', 'grades'),
+                   new lang_string('overridecat_help', 'grades'), 1));
     }
     $ADMIN->add('grades', $temp);
 
index a7308c0..658ed5f 100644 (file)
@@ -621,6 +621,15 @@ class tree extends tree_node {
         return $result;
     }
 
+    /**
+     * Checks whether this tree is empty (contains no children).
+     *
+     * @return boolean True if empty
+     */
+    public function is_empty() {
+        return count($this->children) === 0;
+    }
+
     /**
      * Recursively gets all children of a particular class (you can use a base
      * class to get all conditions, or a specific class).
index 82d99da..d057c30 100644 (file)
@@ -74,6 +74,21 @@ class condition extends \core_availability\condition {
                 'cm' => $this->cmid, 'e' => $this->expectedcompletion);
     }
 
+    /**
+     * Returns a JSON object which corresponds to a condition of this type.
+     *
+     * Intended for unit testing, as normally the JSON values are constructed
+     * by JavaScript code.
+     *
+     * @param int $cmid Course-module id of other activity
+     * @param int $expectedcompletion Expected completion value (COMPLETION_xx)
+     * @return stdClass Object representing condition
+     */
+    public static function get_json($cmid, $expectedcompletion) {
+        return (object)array('type' => 'completion', 'cm' => (int)$cmid,
+                'e' => (int)$expectedcompletion);
+    }
+
     public function is_available($not, \core_availability\info $info, $grabthelot, $userid) {
         $modinfo = $info->get_modinfo();
         $completion = new \completion_info($modinfo->get_course());
index be3be9b..bdedc31 100644 (file)
@@ -77,6 +77,20 @@ class condition extends \core_availability\condition {
                 'd' => $this->direction, 't' => $this->time);
     }
 
+    /**
+     * Returns a JSON object which corresponds to a condition of this type.
+     *
+     * Intended for unit testing, as normally the JSON values are constructed
+     * by JavaScript code.
+     *
+     * @param string $direction DIRECTION_xx constant
+     * @param int $time Time in epoch seconds
+     * @return stdClass Object representing condition
+     */
+    public static function get_json($direction, $time) {
+        return (object)array('type' => 'date', 'd' => $direction, 't' => (int)$time);
+    }
+
     public function is_available($not, \core_availability\info $info, $grabthelot, $userid) {
         return $this->is_available_for_all($not);
     }
index 9ae6391..8a4bd5b 100644 (file)
@@ -85,6 +85,28 @@ class condition extends \core_availability\condition {
         return $result;
     }
 
+    /**
+     * Returns a JSON object which corresponds to a condition of this type.
+     *
+     * Intended for unit testing, as normally the JSON values are constructed
+     * by JavaScript code.
+     *
+     * @param int $gradeitemid Grade item id
+     * @param number|null $min Min grade (or null if no min)
+     * @param number|null $max Max grade (or null if no max)
+     * @return stdClass Object representing condition
+     */
+    public static function get_json($gradeitemid, $min = null, $max = null) {
+        $result = (object)array('type' => 'grade', 'id' => (int)$gradeitemid);
+        if (!is_null($min)) {
+            $result->min = $min;
+        }
+        if (!is_null($max)) {
+            $result->max = $max;
+        }
+        return $result;
+    }
+
     public function is_available($not, \core_availability\info $info, $grabthelot, $userid) {
         $course = $info->get_course();
         $score = $this->get_cached_grade_score($this->gradeitemid, $course->id, $grabthelot, $userid);
index 0007e87..a156e4b 100644 (file)
@@ -142,6 +142,39 @@ class condition extends \core_availability\condition {
         return $result;
     }
 
+    /**
+     * Returns a JSON object which corresponds to a condition of this type.
+     *
+     * Intended for unit testing, as normally the JSON values are constructed
+     * by JavaScript code.
+     *
+     * @param bool $customfield True if this is a custom field
+     * @param string $fieldname Field name
+     * @param string $operator Operator name (OP_xx constant)
+     * @param string|null $value Value (not required for some operator types)
+     * @return stdClass Object representing condition
+     */
+    public static function get_json($customfield, $fieldname, $operator, $value = null) {
+        $result = (object)array('type' => 'profile', 'op' => $operator);
+        if ($customfield) {
+            $result->cf = $fieldname;
+        } else {
+            $result->sf = $fieldname;
+        }
+        switch ($operator) {
+            case self::OP_IS_EMPTY:
+            case self::OP_IS_NOT_EMPTY:
+                break;
+            default:
+                if (is_null($value)) {
+                    throw new \coding_exception('Operator requires value');
+                }
+                $result->v = $value;
+                break;
+        }
+        return $result;
+    }
+
     public function is_available($not, \core_availability\info $info, $grabthelot, $userid) {
         $uservalue = $this->get_cached_user_profile_field($userid);
         $allow = self::is_field_condition_met($this->operator, $uservalue, $this->value);
index 714aa8e..b19d62c 100644 (file)
@@ -489,6 +489,21 @@ class tree_testcase extends \advanced_testcase {
                 $tree->get_full_information($info));
     }
 
+    /**
+     * Tests the is_empty() function.
+     */
+    public function test_is_empty() {
+        // Tree with nothing in should be empty.
+        $structure = tree::get_root_json(array(), tree::OP_OR);
+        $tree = new tree($structure);
+        $this->assertTrue($tree->is_empty());
+
+        // Tree with something in is not empty.
+        $structure = tree::get_root_json(array(self::mock(array('m' => '1'))), tree::OP_OR);
+        $tree = new tree($structure);
+        $this->assertFalse($tree->is_empty());
+    }
+
     /**
      * Tests the get_all_children() function.
      */
index b7c0509..185800c 100644 (file)
Binary files a/availability/yui/build/moodle-core_availability-form/moodle-core_availability-form-debug.js and b/availability/yui/build/moodle-core_availability-form/moodle-core_availability-form-debug.js differ
index 82b5c5b..9c578a0 100644 (file)
Binary files a/availability/yui/build/moodle-core_availability-form/moodle-core_availability-form-min.js and b/availability/yui/build/moodle-core_availability-form/moodle-core_availability-form-min.js differ
index b7c0509..185800c 100644 (file)
Binary files a/availability/yui/build/moodle-core_availability-form/moodle-core_availability-form.js and b/availability/yui/build/moodle-core_availability-form/moodle-core_availability-form.js differ
index 5f26ced..099fe5e 100644 (file)
@@ -926,20 +926,19 @@ M.core_availability.Item.prototype.pluginNode = null;
 M.core_availability.EyeIcon = function(individual, shown) {
     this.individual = individual;
     this.span = Y.Node.create('<a class="availability-eye" href="#" role="button">');
-    var iconBase = M.cfg.wwwroot + '/theme/image.php/' + M.cfg.theme + '/core/' + M.cfg.themerev;
     var icon = Y.Node.create('<img />');
     this.span.appendChild(icon);
 
     // Set up button text and icon.
     var suffix = individual ? '_individual' : '_all';
     var setHidden = function() {
-        icon.set('src', iconBase + '/i/show');
+        icon.set('src', M.util.image_url('i/show', 'core'));
         icon.set('alt', M.str.availability['hidden' + suffix]);
         this.span.set('title', M.str.availability['hidden' + suffix] + ' \u2022 ' +
                 M.str.availability.show_verb);
     };
     var setShown = function() {
-        icon.set('src', iconBase + '/i/hide');
+        icon.set('src', M.util.image_url('i/hide', 'core'));
         icon.set('alt', M.str.availability['shown' + suffix]);
         this.span.set('title', M.str.availability['shown' + suffix] + ' \u2022 ' +
                 M.str.availability.hide_verb);
@@ -1004,9 +1003,8 @@ M.core_availability.EyeIcon.prototype.isHidden = function() {
 M.core_availability.DeleteIcon = function(toDelete) {
     this.span = Y.Node.create('<a class="availability-delete" href="#" title="' +
             M.str.moodle['delete'] + '" role="button">');
-    var img = Y.Node.create('<img src="' +
-            M.cfg.wwwroot + '/theme/image.php/' + M.cfg.theme + '/core/' + M.cfg.themerev +
-            '/t/delete" alt="' + M.str.moodle['delete'] + '" />');
+    var img = Y.Node.create('<img src="' + M.util.image_url('t/delete', 'core') +
+            '" alt="' + M.str.moodle['delete'] + '" />');
     this.span.appendChild(img);
     var click = function(e) {
         e.preventDefault();
index fefcb99..0deb272 100644 (file)
@@ -53,7 +53,7 @@ if ($badge->type == BADGE_TYPE_COURSE) {
     }
     require_login($badge->courseid);
     $navurl = new moodle_url('/badges/index.php', array('type' => $badge->type, 'id' => $badge->courseid));
-    $PAGE->set_pagelayout('course');
+    $PAGE->set_pagelayout('incourse');
     navigation_node::override_active_url($navurl);
 } else {
     $PAGE->set_pagelayout('admin');
index ecc0d4f..a110223 100644 (file)
@@ -85,7 +85,7 @@ if ($type == BADGE_TYPE_SITE) {
     $coursecontext = context_course::instance($course->id);
     $title = get_string('coursebadges', 'badges');
     $PAGE->set_context($coursecontext);
-    $PAGE->set_pagelayout('course');
+    $PAGE->set_pagelayout('incourse');
     $PAGE->set_heading(format_string($course->fullname, true, array('context' => $coursecontext)) . ': ' . $hdr);
     navigation_node::override_active_url(
         new moodle_url('/badges/index.php', array('type' => BADGE_TYPE_COURSE, 'id' => $course->id))
index d83ce59..a6a5f59 100644 (file)
@@ -47,7 +47,7 @@ if (($type == BADGE_TYPE_COURSE) && ($course = $DB->get_record('course', array('
     require_login($course);
     $coursecontext = context_course::instance($course->id);
     $PAGE->set_context($coursecontext);
-    $PAGE->set_pagelayout('course');
+    $PAGE->set_pagelayout('incourse');
     $PAGE->set_url('/badges/newbadge.php', array('type' => $type, 'id' => $course->id));
     $heading = format_string($course->fullname, true, array('context' => $coursecontext)) . ": " . $title;
     $PAGE->set_heading($heading);
index 38c0fe9..80a3e25 100644 (file)
@@ -71,7 +71,7 @@ if ($type == BADGE_TYPE_SITE) {
     $coursename = format_string($course->fullname, true, array('context' => context_course::instance($course->id)));
     $title = $coursename . ': ' . get_string('coursebadges', 'badges');
     $PAGE->set_context(context_course::instance($course->id));
-    $PAGE->set_pagelayout('course');
+    $PAGE->set_pagelayout('incourse');
     $PAGE->set_heading($title);
 }
 
index ca55e37..c6539cc 100644 (file)
@@ -41,7 +41,7 @@ $context = context_course::instance($courseid);
 $PAGE->set_course($parentcourse);
 $PAGE->set_url('/blocks/community/communitycourse.php');
 $PAGE->set_heading($SITE->fullname);
-$PAGE->set_pagelayout('course');
+$PAGE->set_pagelayout('incourse');
 $PAGE->set_title(get_string('searchcourse', 'block_community'));
 $PAGE->navbar->add(get_string('searchcourse', 'block_community'));
 
old mode 100644 (file)
new mode 100755 (executable)
index 8bb2a63..676b26d
@@ -2888,10 +2888,11 @@ function calendar_add_subscription($sub) {
  * @param stdClass $event The RFC-2445 iCalendar event
  * @param int $courseid The course ID
  * @param int $subscriptionid The iCalendar subscription ID
+ * @param string $timezone The X-WR-TIMEZONE iCalendar property if provided
  * @throws dml_exception A DML specific exception is thrown for invalid subscriptionids.
  * @return int Code: CALENDAR_IMPORT_EVENT_UPDATED = updated,  CALENDAR_IMPORT_EVENT_INSERTED = inserted, 0 = error
  */
-function calendar_add_icalendar_event($event, $courseid, $subscriptionid) {
+function calendar_add_icalendar_event($event, $courseid, $subscriptionid, $timezone='UTC') {
     global $DB;
 
     // Probably an unsupported X-MICROSOFT-CDO-BUSYSTATUS event.
@@ -2924,15 +2925,27 @@ function calendar_add_icalendar_event($event, $courseid, $subscriptionid) {
 
     $defaulttz = date_default_timezone_get();
     $tz = isset($event->properties['DTSTART'][0]->parameters['TZID']) ? $event->properties['DTSTART'][0]->parameters['TZID'] :
-            'UTC';
+            $timezone;
     $eventrecord->timestart = strtotime($event->properties['DTSTART'][0]->value . ' ' . $tz);
     if (empty($event->properties['DTEND'])) {
         $eventrecord->timeduration = 3600; // one hour if no end time specified
     } else {
         $endtz = isset($event->properties['DTEND'][0]->parameters['TZID']) ? $event->properties['DTEND'][0]->parameters['TZID'] :
-                'UTC';
+                $timezone;
         $eventrecord->timeduration = strtotime($event->properties['DTEND'][0]->value . ' ' . $endtz) - $eventrecord->timestart;
     }
+
+    // Check to see if it should be treated as an all day event.
+    if ($eventrecord->timeduration == DAYSECS) {
+        // Check to see if the event started at Midnight on the imported calendar.
+        date_default_timezone_set($timezone);
+        if (date('H:i:s', $eventrecord->timestart) === "00:00:00") {
+            // This event should be an all day event.
+            $eventrecord->timeduration = 0;
+        }
+        date_default_timezone_set($defaulttz);
+    }
+
     $eventrecord->uuid = $event->properties['UID'][0]->value;
     $eventrecord->timemodified = time();
 
@@ -3066,8 +3079,14 @@ function calendar_import_icalendar_events($ical, $courseid, $subscriptionid = nu
         $sql = "UPDATE {event} SET timemodified = :time WHERE subscriptionid = :id";
         $DB->execute($sql, array('time' => 0, 'id' => $subscriptionid));
     }
+    // Grab the timezone from the iCalendar file to be used later.
+    if (isset($ical->properties['X-WR-TIMEZONE'][0]->value)) {
+        $timezone = $ical->properties['X-WR-TIMEZONE'][0]->value;
+    } else {
+        $timezone = 'UTC';
+    }
     foreach ($ical->components['VEVENT'] as $event) {
-        $res = calendar_add_icalendar_event($event, $courseid, $subscriptionid);
+        $res = calendar_add_icalendar_event($event, $courseid, $subscriptionid, $timezone);
         switch ($res) {
           case CALENDAR_IMPORT_EVENT_UPDATED:
             $updatecount++;
index a36227d..c48905c 100644 (file)
@@ -1216,6 +1216,15 @@ class core_course_management_renderer extends plugin_renderer_base {
                     array('class' => 'action-edit')
                 );
             }
+            // Delete.
+            if ($course->can_delete()) {
+                $actions[] = $this->output->action_icon(
+                    new moodle_url('/course/delete.php', array('id' => $course->id)),
+                    new pix_icon('t/delete', get_string('delete')),
+                    null,
+                    array('class' => 'action-delete')
+                );
+            }
             // Show/Hide.
             if ($course->can_change_visibility()) {
                     $actions[] = $this->output->action_icon(
index cce2227..2491510 100644 (file)
@@ -34,7 +34,7 @@
     }
 
     $PAGE->set_course($course);
-    $PAGE->set_pagelayout('course');
+    $PAGE->set_pagelayout('incourse');
     $PAGE->set_url('/course/info.php', array('id' => $course->id));
     $PAGE->set_title(get_string("summaryof", "", $course->fullname));
     $PAGE->set_heading(get_string('courseinfo'));
index da7292d..fa1ac35 100644 (file)
@@ -85,6 +85,15 @@ function add_moduleinfo($moduleinfo, $course, $mform = null) {
         } else if (property_exists($moduleinfo, 'availability')) {
             $newcm->availability = $moduleinfo->availability;
         }
+        // If there is any availability data, verify it.
+        if ($newcm->availability) {
+            $tree = new \core_availability\tree(json_decode($newcm->availability));
+            // Save time and database space by setting null if the only data
+            // is an empty tree.
+            if ($tree->is_empty()) {
+                $newcm->availability = null;
+            }
+        }
     }
     if (isset($moduleinfo->showdescription)) {
         $newcm->showdescription = $moduleinfo->showdescription;
@@ -494,6 +503,15 @@ function update_moduleinfo($cm, $moduleinfo, $course, $mform = null) {
         } else if (property_exists($moduleinfo, 'availability')) {
             $cm->availability = $moduleinfo->availability;
         }
+        // If there is any availability data, verify it.
+        if ($cm->availability) {
+            $tree = new \core_availability\tree(json_decode($cm->availability));
+            // Save time and database space by setting null if the only data
+            // is an empty tree.
+            if ($tree->is_empty()) {
+                $cm->availability = null;
+            }
+        }
     }
     if (isset($moduleinfo->showdescription)) {
         $cm->showdescription = $moduleinfo->showdescription;
index 15e091a..c081b73 100644 (file)
@@ -54,7 +54,7 @@ if (!has_capability('moodle/course:publish', context_course::instance($id))
 
 //page settings
 $PAGE->set_url('/course/publish/backup.php');
-$PAGE->set_pagelayout('course');
+$PAGE->set_pagelayout('incourse');
 $PAGE->set_title(get_string('course') . ': ' . $course->fullname);
 $PAGE->set_heading($course->fullname);
 
index 095e33b..c599eb6 100644 (file)
@@ -34,7 +34,7 @@ $course = $DB->get_record('course', array('id'=>$id), '*', MUST_EXIST);
 require_login($course);
 
 $PAGE->set_url('/course/publish/hubselector.php', array('id' => $course->id));
-$PAGE->set_pagelayout('course');
+$PAGE->set_pagelayout('incourse');
 $PAGE->set_title(get_string('course') . ': ' . $course->fullname);
 $PAGE->set_heading($course->fullname);
 
index 2e11f5b..1012c8d 100644 (file)
@@ -41,7 +41,7 @@ $context = context_course::instance($course->id);
 $shortname = format_string($course->shortname, true, array('context' => $context));
 
 $PAGE->set_url('/course/publish/index.php', array('id' => $course->id));
-$PAGE->set_pagelayout('course');
+$PAGE->set_pagelayout('incourse');
 $PAGE->set_title(get_string('course') . ': ' . $course->fullname);
 $PAGE->set_heading($course->fullname);
 
index 298e5f3..ee9caed 100644 (file)
@@ -45,7 +45,7 @@ require_login($course);
 
 //page settings
 $PAGE->set_url('/course/publish/metadata.php', array('id' => $course->id));
-$PAGE->set_pagelayout('course');
+$PAGE->set_pagelayout('incourse');
 $PAGE->set_title(get_string('course') . ': ' . $course->fullname);
 $PAGE->set_heading($course->fullname);
 
index af11796..400b478 100644 (file)
@@ -29,7 +29,7 @@ require_once("$CFG->libdir/resourcelib.php");
 $id = required_param('id', PARAM_INT); // course id
 
 $course = $DB->get_record('course', array('id'=>$id), '*', MUST_EXIST);
-$PAGE->set_pagelayout('course');
+$PAGE->set_pagelayout('incourse');
 require_course_login($course, true);
 
 // get list of all resource-like modules
index 9fda767..62ac25a 100644 (file)
@@ -457,13 +457,12 @@ class core_course_courselib_testcase extends advanced_testcase {
 
         // Conditional activity.
         $coursegradeitem = grade_item::fetch_course_item($moduleinfo->course); //the activity will become available only when the user reach some grade into the course itself.
-        $moduleinfo->availability = '{"op":"&","showc":[true,true],"c":[' .
-                '{"type":"date","d":">=","t":' . time() . '},' .
-                '{"type":"date","d":"<","t":' . (time() + (7 * 24 * 3600)) . '}' .
-                '{"type":"grade","id":' . $coursegradeitem->id . ',"min":10,"max":80},' .
-                '{"type":"profile","sf":"email","op":"contains","v":"@"},'.
-                '{"type":"completion","id":'. $assigncm->id . ',"e":' . COMPLETION_COMPLETE . '}' .
-                ']}';
+        $moduleinfo->availability = json_encode(\core_availability\tree::get_root_json(
+                array(\availability_date\condition::get_json('>=', time()),
+                \availability_date\condition::get_json('<', time() + (7 * 24 * 3600)),
+                \availability_grade\condition::get_json($coursegradeitem->id, 10, 80),
+                \availability_profile\condition::get_json(false, 'email', 'contains', '@'),
+                \availability_completion\condition::get_json($assigncm->id, COMPLETION_COMPLETE)), '&'));
 
         // Grading and Advanced grading.
         require_once($CFG->dirroot . '/rating/lib.php');
@@ -2509,4 +2508,43 @@ class core_course_courselib_testcase extends advanced_testcase {
             $this->assertEquals($value, $newcm->$prop);
         }
     }
+
+    /**
+     * Tests that when creating or updating a module, if the availability settings
+     * are present but set to an empty tree, availability is set to null in
+     * database.
+     */
+    public function test_empty_availability_settings() {
+        global $DB;
+        $this->setAdminUser();
+        $this->resetAfterTest();
+
+        // Enable availability.
+        set_config('enableavailability', 1);
+
+        // Test add.
+        $emptyavailability = json_encode(\core_availability\tree::get_root_json(array()));
+        $course = self::getDataGenerator()->create_course();
+        $label = self::getDataGenerator()->create_module('label', array(
+                'course' => $course, 'availability' => $emptyavailability));
+        $this->assertNull($DB->get_field('course_modules', 'availability',
+                array('id' => $label->cmid)));
+
+        // Test update.
+        $formdata = $DB->get_record('course_modules', array('id' => $label->cmid));
+        unset($formdata->availability);
+        $formdata->availabilityconditionsjson = $emptyavailability;
+        $formdata->modulename = 'label';
+        $formdata->coursemodule = $label->cmid;
+        $draftid = 0;
+        file_prepare_draft_area($draftid, context_module::instance($label->cmid)->id,
+                'mod_label', 'intro', 0);
+        $formdata->introeditor = array(
+            'itemid' => $draftid,
+            'text' => '<p>Yo</p>',
+            'format' => FORMAT_HTML);
+        update_module($formdata);
+        $this->assertNull($DB->get_field('course_modules', 'availability',
+                array('id' => $label->cmid)));
+    }
 }
index 68a12fd..2fdff2a 100644 (file)
@@ -46,7 +46,7 @@ if (!$course->visible && !has_capability('moodle/course:viewhiddencourses', cont
 }
 
 $PAGE->set_course($course);
-$PAGE->set_pagelayout('course');
+$PAGE->set_pagelayout('incourse');
 $PAGE->set_url('/enrol/index.php', array('id'=>$course->id));
 
 // do not allow enrols when in login-as session
index 03e2f6c..5e2a928 100644 (file)
@@ -1099,19 +1099,26 @@ class course_enrolment_manager {
      */
     private function prepare_user_for_display($user, $extrafields, $now) {
         $details = array(
-            'userid'    => $user->id,
-            'courseid'  => $this->get_course()->id,
-            'picture'   => new user_picture($user),
-            'firstname' => fullname($user, has_capability('moodle/site:viewfullnames', $this->get_context())),
-            'lastseen'  => get_string('never'),
+            'userid'           => $user->id,
+            'courseid'         => $this->get_course()->id,
+            'picture'          => new user_picture($user),
+            'firstname'        => fullname($user, has_capability('moodle/site:viewfullnames', $this->get_context())),
+            'lastseen'         => get_string('never'),
+            'lastcourseaccess' => get_string('never'),
         );
         foreach ($extrafields as $field) {
             $details[$field] = $user->{$field};
         }
 
+        // Last time user has accessed the site.
         if ($user->lastaccess) {
             $details['lastseen'] = format_time($now - $user->lastaccess);
         }
+
+        // Last time user has accessed the course.
+        if ($user->lastseen) {
+            $details['lastcourseaccess'] = format_time($now - $user->lastseen);
+        }
         return $details;
     }
 
index b82ebe4..49421ef 100644 (file)
@@ -186,7 +186,7 @@ foreach ($extrafields as $field) {
 
 $fields = array(
     'userdetails' => $userdetails,
-    'lastseen' => get_string('lastaccess'),
+    'lastcourseaccess' => get_string('lastcourseaccess'),
     'role' => get_string('roles', 'role'),
     'group' => get_string('groups', 'group'),
     'enrol' => get_string('enrolmentinstances', 'enrol')
@@ -196,7 +196,7 @@ $fields = array(
 if (!has_capability('moodle/course:viewhiddenuserfields', $context)) {
     $hiddenfields = array_flip(explode(',', $CFG->hiddenuserfields));
     if (isset($hiddenfields['lastaccess'])) {
-        unset($fields['lastseen']);
+        unset($fields['lastcourseaccess']);
     }
     if (isset($hiddenfields['groups'])) {
         unset($fields['group']);
index 6c85609..5608693 100644 (file)
@@ -43,7 +43,7 @@ if ($node = $PAGE->settingsnav->find('coursefiles', navigation_node::TYPE_SETTIN
 $PAGE->set_context($context);
 $PAGE->set_title($heading);
 $PAGE->set_heading($heading);
-$PAGE->set_pagelayout('course');
+$PAGE->set_pagelayout('incourse');
 
 $data = new stdClass();
 $options = array('subdirs'=>1, 'maxfiles'=>-1, 'accepted_types'=>'*', 'return_types'=>FILE_INTERNAL);
index 42cb947..5e16e59 100644 (file)
@@ -68,7 +68,7 @@ if ($node = $PAGE->settingsnav->find('coursefiles', navigation_node::TYPE_SETTIN
 
 $PAGE->set_title("$course->shortname: $strfiles");
 $PAGE->set_heading($course->fullname);
-$PAGE->set_pagelayout('course');
+$PAGE->set_pagelayout('incourse');
 
 $output = $PAGE->get_renderer('core', 'files');
 
index 950e3bf..f893091 100644 (file)
@@ -162,11 +162,13 @@ class edit_category_form extends moodleform {
         $mform->disabledIf('grade_item_grademax', 'grade_item_gradetype', 'noteq', GRADE_TYPE_VALUE);
         $mform->disabledIf('grade_item_grademax', 'aggregation', 'eq', GRADE_AGGREGATE_SUM);
 
-        $mform->addElement('text', 'grade_item_grademin', get_string('grademin', 'grades'));
-        $mform->setType('grade_item_grademin', PARAM_RAW);
-        $mform->addHelpButton('grade_item_grademin', 'grademin', 'grades');
-        $mform->disabledIf('grade_item_grademin', 'grade_item_gradetype', 'noteq', GRADE_TYPE_VALUE);
-        $mform->disabledIf('grade_item_grademin', 'aggregation', 'eq', GRADE_AGGREGATE_SUM);
+        if ((bool) get_config('moodle', 'grade_report_showmin')) {
+            $mform->addElement('text', 'grade_item_grademin', get_string('grademin', 'grades'));
+            $mform->setType('grade_item_grademin', PARAM_RAW);
+            $mform->addHelpButton('grade_item_grademin', 'grademin', 'grades');
+            $mform->disabledIf('grade_item_grademin', 'grade_item_gradetype', 'noteq', GRADE_TYPE_VALUE);
+            $mform->disabledIf('grade_item_grademin', 'aggregation', 'eq', GRADE_AGGREGATE_SUM);
+        }
 
         $mform->addElement('text', 'grade_item_gradepass', get_string('gradepass', 'grades'));
         $mform->setType('grade_item_gradepass', PARAM_RAW);
@@ -413,7 +415,9 @@ class edit_category_form extends moodleform {
             if ($grade_item->is_outcome_item()) {
                 // we have to prevent incompatible modifications of outcomes if outcomes disabled
                 $mform->removeElement('grade_item_grademax');
-                $mform->removeElement('grade_item_grademin');
+                if ($mform->elementExists('grade_item_grademin')) {
+                    $mform->removeElement('grade_item_grademin');
+                }
                 $mform->removeElement('grade_item_gradetype');
                 $mform->removeElement('grade_item_display');
                 $mform->removeElement('grade_item_decimals');
index b9dc0d2..13ad687 100644 (file)
@@ -90,10 +90,12 @@ class edit_item_form extends moodleform {
         $mform->disabledIf('grademax', 'gradetype', 'noteq', GRADE_TYPE_VALUE);
         $mform->setType('grademax', PARAM_RAW);
 
-        $mform->addElement('text', 'grademin', get_string('grademin', 'grades'));
-        $mform->addHelpButton('grademin', 'grademin', 'grades');
-        $mform->disabledIf('grademin', 'gradetype', 'noteq', GRADE_TYPE_VALUE);
-        $mform->setType('grademin', PARAM_RAW);
+        if ((bool) get_config('moodle', 'grade_report_showmin')) {
+            $mform->addElement('text', 'grademin', get_string('grademin', 'grades'));
+            $mform->addHelpButton('grademin', 'grademin', 'grades');
+            $mform->disabledIf('grademin', 'gradetype', 'noteq', GRADE_TYPE_VALUE);
+            $mform->setType('grademin', PARAM_RAW);
+        }
 
         $mform->addElement('text', 'gradepass', get_string('gradepass', 'grades'));
         $mform->addHelpButton('gradepass', 'gradepass', 'grades');
@@ -235,7 +237,9 @@ class edit_item_form extends moodleform {
             if ($grade_item->is_outcome_item()) {
                 // we have to prevent incompatible modifications of outcomes if outcomes disabled
                 $mform->removeElement('grademax');
-                $mform->removeElement('grademin');
+                if ($mform->elementExists('grademin')) {
+                    $mform->removeElement('grademin');
+                }
                 $mform->removeElement('gradetype');
                 $mform->removeElement('display');
                 $mform->removeElement('decimals');
@@ -244,7 +248,11 @@ class edit_item_form extends moodleform {
             } else {
                 if ($grade_item->is_external_item()) {
                     // following items are set up from modules and should not be overrided by user
-                    $mform->hardFreeze('itemname,gradetype,grademax,grademin,scaleid');
+                    if ($mform->elementExists('grademin')) {
+                        // The site setting grade_report_showmin may have prevented grademin being added to the form.
+                        $mform->hardFreeze('grademin');
+                    }
+                    $mform->hardFreeze('itemname,gradetype,grademax,scaleid');
                     if ($grade_item->itemnumber == 0) {
                         // the idnumber of grade itemnumber 0 is synced with course_modules
                         $mform->hardFreeze('idnumber');
@@ -316,7 +324,6 @@ class edit_item_form extends moodleform {
         }
     }
 
-
 /// perform extra validation before submission
     function validation($data, $files) {
         global $COURSE;
index 1315408..c483ff2 100644 (file)
@@ -49,12 +49,22 @@ class grade_edit_tree {
     public $table;
 
     public $categories = array();
+
+    /**
+     * Show calculator icons next to manual grade items
+     * @var bool $show_calculations
+     */
+    private $show_calculations;
+
     /**
      * Constructor
      */
     public function __construct($gtree, $moving=false, $gpr) {
         global $USER, $OUTPUT, $COURSE;
 
+        $systemdefault = get_config('moodle', 'grade_report_showcalculations');
+        $this->show_calculations = get_user_preferences('grade_report_showcalculations', $systemdefault);
+
         $this->gtree = $gtree;
         $this->moving = $moving;
         $this->gpr = $gpr;
@@ -138,7 +148,9 @@ class grade_edit_tree {
             $actions .= $this->gtree->get_edit_icon($element, $this->gpr);
         }
 
-        $actions .= $this->gtree->get_calculation_icon($element, $this->gpr);
+        if ($this->show_calculations) {
+            $actions .= $this->gtree->get_calculation_icon($element, $this->gpr);
+        }
 
         if ($element['type'] == 'item' or ($element['type'] == 'category' and $element['depth'] > 1)) {
             if ($this->element_deletable($element)) {
index 0c6e692..cf02a6e 100644 (file)
@@ -95,6 +95,12 @@ class grade_report_grader extends grade_report {
      */
     protected $feedback_trunc_length = 50;
 
+    /**
+     * Allow category grade overriding
+     * @var bool $overridecat
+     */
+    protected $overridecat;
+
     /**
      * Constructor. Sets local copies of user preferences and initialises grade_tree.
      * @param int $courseid
@@ -143,6 +149,8 @@ class grade_report_grader extends grade_report {
         $this->setup_groups();
         $this->setup_users();
         $this->setup_sortitemid();
+
+        $this->overridecat = (bool)get_config('moodle', 'grade_overridecat');
     }
 
     /**
@@ -1029,7 +1037,13 @@ class grade_report_grader extends grade_report {
                     }
 
                     if ($enableajax) {
-                        $itemcell->attributes['class'] .= ' clickable';
+                        $canoverride = true;
+                        if ($item->is_category_item() || $item->is_course_item()) {
+                            $canoverride = (bool) get_config('moodle', 'grade_overridecat');
+                        }
+                        if ($canoverride) {
+                            $itemcell->attributes['class'] .= ' clickable';
+                        }
                     }
 
                     if ($item->needsupdate) {
@@ -1485,7 +1499,16 @@ class grade_report_grader extends grade_report {
         // Init all icons
         $editicon = '';
 
-        if ($element['type'] != 'categoryitem' && $element['type'] != 'courseitem') {
+        $editable = true;
+
+        if ($element['type'] == 'grade') {
+            $item = $element['object']->grade_item;
+            if ($item->is_course_item() or $item->is_category_item()) {
+                $editable = $this->overridecat;
+            }
+        }
+
+        if ($element['type'] != 'categoryitem' && $element['type'] != 'courseitem' && $editable) {
             $editicon = $this->gtree->get_edit_icon($element, $this->gpr);
         }
 
index f67474a..6263883 100644 (file)
@@ -314,7 +314,7 @@ M.gradereport_grader.classes.ajax = function(report, cfg) {
     this.existingfields = [];
 
     if (!report.isediting) {
-        report.table.all('.cell.grade').on('makeditable|click', this.make_editable, this);
+        report.table.all('.clickable').on('click', this.make_editable, this);
     } else {
         for (var userid in report.users) {
             if (!this.existingfields[userid]) {
@@ -1043,7 +1043,7 @@ M.gradereport_grader.classes.textfield.prototype.revert = function() {
         }
     }
     this.keyevents = [];
-    this.node.on('makeditable|click', this.report.ajax.make_editable, this.report.ajax);
+    this.node.on('click', this.report.ajax.make_editable, this.report.ajax);
 };
 /**
  * Gets the grade for current cell
index ba2cb24..241adf6 100644 (file)
@@ -55,7 +55,9 @@ class grader_report_preferences_form extends moodleform {
         if (has_capability('moodle/grade:manage', $context)) {
 
             $preferences['prefshow'] = array();
-            $preferences['prefshow']['showcalculations']  = $checkbox_default;
+
+            $preferences['prefshow']['showcalculations'] = $checkbox_default;
+
             $preferences['prefshow']['showeyecons']       = $checkbox_default;
             if ($canviewhidden) {
                 $preferences['prefshow']['showaverages']  = $checkbox_default;
index d1b02af..cb70000 100644 (file)
@@ -55,8 +55,9 @@ if ($ADMIN->fulltree) {
     $settings->add(new admin_setting_configcheckbox('grade_report_enableajax', get_string('enableajax', 'grades'),
                                                 get_string('enableajax_help', 'grades'), 0));
 
-    $settings->add(new admin_setting_configcheckbox('grade_report_showcalculations', get_string('showcalculations', 'grades'),
-                                                get_string('showcalculations_help', 'grades'), 0));
+    $settings->add(new admin_setting_configcheckbox('grade_report_showcalculations',
+                                                    get_string('showcalculations', 'grades'),
+                                                    get_string('showcalculations_help', 'grades'), 1));
 
     $settings->add(new admin_setting_configcheckbox('grade_report_showeyecons', get_string('showeyecons', 'grades'),
                                                 get_string('showeyecons_help', 'grades'), 0));
index 0b1d830..3409eac 100644 (file)
@@ -209,6 +209,11 @@ class tablelog extends \table_sql implements \renderable {
      * @return string HTML to display
      */
     public function col_grader(\stdClass $history) {
+        if (empty($history->usermodified)) {
+            // Not every row has a valid usermodified.
+            return '';
+        }
+
         $grader = new \stdClass();
         $grader = username_load_fields_from_object($grader, $history, 'grader');
         $name = fullname($grader);
@@ -368,7 +373,7 @@ class tablelog extends \table_sql implements \renderable {
                    FROM {grade_grades_history} ggh
               LEFT JOIN {grade_items} gi ON gi.id = ggh.itemid
                    JOIN {user} u ON u.id = ggh.userid
-                   JOIN {user} ug ON ug.id = ggh.usermodified
+              LEFT JOIN {user} ug ON ug.id = ggh.usermodified
                   WHERE $where";
 
         // As prevgrade is a dynamic field, we need to wrap the query. This is the only filtering
@@ -382,13 +387,31 @@ class tablelog extends \table_sql implements \renderable {
         }
 
         // Add order by if needed.
-        if (!$count && $this->get_sql_sort()) {
-            $sql .= " ORDER BY " . $this->get_sql_sort();
+        if (!$count && $sqlsort = $this->get_sql_sort()) {
+            $sql .= " ORDER BY " . $sqlsort;
         }
 
         return array($sql, $params);
     }
 
+    /**
+     * Get the SQL fragment to sort by.
+     *
+     * This is overridden to sort by timemodified and ID by default. Many items happen at the same time
+     * and a second sorting by ID is valuable to distinguish the order in which the history happened.
+     *
+     * @return string SQL fragment.
+     */
+    public function get_sql_sort() {
+        $columns = $this->get_sort_columns();
+        if (count($columns) == 1 && isset($columns['timemodified']) && $columns['timemodified'] == SORT_DESC) {
+            // Add the 'id' column when we are using the default sorting.
+            $columns['id'] = SORT_DESC;
+            return self::construct_order_by($columns);
+        }
+        return parent::get_sql_sort();
+    }
+
     /**
      * Query the reader. Store results in the object for use by build_table.
      *
diff --git a/grade/tests/behat/grade_UI_settings.feature b/grade/tests/behat/grade_UI_settings.feature
new file mode 100644 (file)
index 0000000..0177e34
--- /dev/null
@@ -0,0 +1,58 @@
+@core @core_grades
+Feature: Site settings can be used to hide parts of the gradebook UI
+  In order to hide UI elements
+  As an admin
+  I need to modify gradebook related system settings
+
+  Background:
+    Given the following "courses" exist:
+      | fullname | shortname | category | format |
+      | Course 1 | C1 | 0 | topics |
+    And the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | student1 | Student | 1 | student1@asd.com | s1 |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | student1 | C1 | student |
+    And the following "activities" exist:
+      | activity | course | idnumber | name | intro |
+      | assign | C1 | assign1 | Assignment1 | Assignment 1 intro |
+    And I log in as "admin"
+    And I follow "Course 1"
+    And I follow "Grades"
+    And I turn editing mode on
+
+  @javascript
+  Scenario: Hide minimum grade
+    When I click on "Edit  assign Assignment1" "link"
+    And I should see "Minimum grade"
+    Then I navigate to "General settings" node in "Site administration > Grades"
+    And I click on "Show minimum grade" "checkbox"
+    And I press "Save changes"
+    And I follow "Home"
+    And I follow "Course 1"
+    And I follow "Grades"
+    And I click on "Edit  assign Assignment1" "link"
+    And I should not see "Minimum grade"
+
+  @javascript
+  Scenario: Hide calculation icons
+    And "Edit calculation for   Course total" "link" should exist
+    When I navigate to "Grader report" node in "Site administration > Grades > Report settings"
+    And I click on "Show calculations" "checkbox"
+    And I press "Save changes"
+    And I follow "Home"
+    And I follow "Course 1"
+    And I follow "Grades"
+    Then "Edit calculation for   Course total" "link" should not exist
+
+  @javascript
+  Scenario: Disable category overriding
+    And ".r0 .course input[type='text']" "css_element" should exist
+    Then I navigate to "Grade category settings" node in "Site administration > Grades"
+    And I click on "Allow category grades to be manually overridden" "checkbox"
+    And I press "Save changes"
+    And I follow "Home"
+    And I follow "Course 1"
+    And I follow "Grades"
+    And ".r0 .course input[type='text']" "css_element" should not exist
index dd379f8..702e278 100644 (file)
@@ -420,6 +420,8 @@ $string['meanselection'] = 'Grades selected for column averages';
 $string['meanselection_help'] = 'This setting determines whether cells with no grade should be included when calculating the average (mean) for each category or grade item.';
 $string['median'] = 'Median';
 $string['min'] = 'Lowest';
+$string['minimum_show'] = 'Show minimum grade';
+$string['minimum_show_help'] = 'Minimum grade is used in calculating grades and weights. If not shown, minimum grade will default to zero and cannot be edited.';
 $string['missingscale'] = 'Scale must be selected';
 $string['mode'] = 'Mode';
 $string['modgradeerrorbadpoint'] = 'Invalid Grade Value. This must be an integer between 0 and {$a}';
@@ -496,6 +498,8 @@ $string['outcomesstandardavailable'] = 'Available standard outcomes';
 $string['outcomestandard'] = 'Standard outcome';
 $string['outcomestandard_help'] = 'A standard outcome is available site-wide, for all courses.';
 $string['overallaverage'] = 'Overall average';
+$string['overridecat'] = 'Allow category grades to be manually overridden';
+$string['overridecat_help'] = 'Disabling this setting makes it impossible for users to override category grades.';
 $string['overridden'] = 'Overridden';
 $string['overridden_help'] = 'If ticked, the grade can no longer be changed from within the related activity.
 
@@ -603,7 +607,7 @@ $string['showallstudents'] = 'Show all Students';
 $string['showaverages'] = 'Show column averages';
 $string['showaverages_help'] = 'If enabled, the grader report will contain an additional row displaying the average (mean) for each category and grade item.';
 $string['showcalculations'] = 'Show calculations';
-$string['showcalculations_help'] = 'If enabled, when editing is turned on, a calculator icon is shown for each grade item and category, with tool tips over calculated items and a visual indicator that a column is calculated.';
+$string['showcalculations_help'] = 'If enabled, when editing, a calculator icon is shown for each grade item and category with a visual indicator that a grade item is calculated.';
 $string['showeyecons'] = 'Show show/hide icons';
 $string['showeyecons_help'] = 'If enabled, when editing is turned on, a show/hide icon is shown for each grade for controlling its visibility to the student.';
 $string['showgroups'] = 'Show groups';
@@ -683,6 +687,8 @@ $string['usenooutcome'] = 'Use no outcome';
 $string['usenoscale'] = 'Use no scale';
 $string['usepercent'] = 'Use percent';
 $string['user'] = 'User';
+$string['userfields_show'] = 'Show user fields';
+$string['userfields_show_help'] = 'Show additional user fields like email address on the grader report. The specific fields displayed are controlled by the site setting showuseridentity';
 $string['usergrade'] = 'User {$a->fullname} ({$a->useridnumber}) on item {$a->gradeidnumber}';
 $string['userid'] = 'User ID';
 $string['useridnumberwarning'] = 'Users without an ID number are excluded from the export as they cannot be imported';
index be88703..646954f 100644 (file)
@@ -779,6 +779,7 @@ $string['first'] = 'First';
 $string['firstaccess'] = 'First access';
 $string['firstname'] = 'First name';
 $string['firstnamephonetic'] = 'First name - phonetic';
+$string['firstsiteaccess'] = 'First access to site';
 $string['firsttime'] = 'Is this your first time here?';
 $string['folder'] = 'Folder';
 $string['folderclosed'] = 'Closed folder';
@@ -1007,12 +1008,14 @@ $string['language'] = 'Language';
 $string['languagegood'] = 'This language pack is up-to-date! :-)';
 $string['last'] = 'Last';
 $string['lastaccess'] = 'Last access';
+$string['lastcourseaccess'] = 'Last access to course';
 $string['lastedited'] = 'Last edited';
 $string['lastip'] = 'Last IP address';
 $string['lastlogin'] = 'Last login';
 $string['lastmodified'] = 'Last modified';
 $string['lastname'] = 'Surname';
 $string['lastnamephonetic'] = 'Surname - phonetic';
+$string['lastsiteaccess'] = 'Last access to site';
 $string['lastyear'] = 'Last year';
 $string['latestlanguagepack'] = 'Check for latest language pack on moodle.org';
 $string['layouttable'] = 'Layout table';
@@ -1034,6 +1037,7 @@ $string['locktimeout'] = 'The operation timed out while waiting for a lock.';
 $string['log_excel_date_format'] = 'yyyy mmmm d h:mm';
 $string['loggedinas'] = 'You are logged in as {$a}';
 $string['loggedinasguest'] = 'You are currently using guest access';
+$string['loggedinfrom'] = 'from {$a}';
 $string['loggedinnot'] = 'You are not logged in.';
 $string['login'] = 'Log in';
 $string['loginalready'] = 'You are already logged in';
@@ -1548,6 +1552,7 @@ $string['rolemappings'] = 'Role mappings';
 $string['rolerenaming'] = 'Role renaming';
 $string['rolerenaming_help'] = 'This setting allows the displayed names for roles used in the course to be changed. Only the displayed name is changed - role permissions are not affected.  New role names will appear on the course participants page and elsewhere within the course. If the renamed role is one that the administrator has selected as a course manager role, then the new role name will also appear as part of the course listings.';
 $string['roles'] = 'Roles';
+$string['roleviewas'] = 'You are viewing as a {$a}';
 $string['rss'] = 'RSS';
 $string['rssarticles'] = 'Number of RSS recent articles';
 $string['rsserror'] = 'Error reading RSS data';
@@ -1905,6 +1910,7 @@ $string['usernamenotfound'] = 'The username was not found in the database';
 $string['usernameoremail'] = 'Enter either username or email address';
 $string['usernotconfirmed'] = 'Could not confirm {$a}';
 $string['userpic'] = 'User picture';
+$string['userrevert'] = 'Revert to your own account';
 $string['users'] = 'Users';
 $string['userselectorautoselectunique'] = 'If only one user matches the search, select them automatically';
 $string['userselectorpreserveselected'] = 'Keep selected users, even if they no longer match the search';
index ae687b2..4216b87 100644 (file)
@@ -30,6 +30,8 @@ $string['availability'] = 'Availability';
 $string['checkforupdates'] = 'Check for available updates';
 $string['checkforupdateslast'] = 'Last check done on {$a}';
 $string['detectedmisplacedplugin'] = 'Plugin "{$a->component}" is installed in incorrect location "{$a->current}", expected location is "{$a->expected}"';
+$string['dependencyinstall'] = 'Install';
+$string['dependencyupload'] = 'Upload';
 $string['displayname'] = 'Plugin name';
 $string['err_response_curl'] = 'Unable to fetch available updates data - unexpected cURL error.';
 $string['err_response_format_version'] = 'Unexpected version of the response format. Please try to re-check for available updates.';
index ad5d0b9..607fa94 100644 (file)
@@ -1,18 +1,18 @@
 <?php
 /*
 
-@version V5.18 3 Sep 2012   (c) 2000-2012 John Lim (jlim#natsoft.com). All rights reserved.
+@version V5.19  23-Apr-2014  (c) 2000-2014 John Lim (jlim#natsoft.com). All rights reserved.
   Latest version is available at http://adodb.sourceforge.net
-  Released under both BSD license and Lesser GPL library license. 
-  Whenever there is any discrepancy between the two licenses, 
+
+  Released under both BSD license and Lesser GPL library license.
+  Whenever there is any discrepancy between the two licenses,
   the BSD license will take precedence.
-  
+
   Active Record implementation. Superset of Zend Framework's.
-  
+
   Version 0.92
-  
-  See http://www-128.ibm.com/developerworks/java/library/j-cb03076/?ca=dgr-lnxw01ActiveRecord 
+
+  See http://www-128.ibm.com/developerworks/java/library/j-cb03076/?ca=dgr-lnxw01ActiveRecord
        for info on Ruby on Rails Active Record implementation
 */
 
@@ -44,30 +44,30 @@ class ADODB_Active_Table {
 
 // $db = database connection
 // $index = name of index - can be associative, for an example see
-//    http://phplens.com/lens/lensforum/msgs.php?id=17790 
+//    http://phplens.com/lens/lensforum/msgs.php?id=17790
 // returns index into $_ADODB_ACTIVE_DBS
 function ADODB_SetDatabaseAdapter(&$db, $index=false)
 {
        global $_ADODB_ACTIVE_DBS;
-       
+
                foreach($_ADODB_ACTIVE_DBS as $k => $d) {
                        if (PHP_VERSION >= 5) {
                                if ($d->db === $db) return $k;
                        } else {
-                               if ($d->db->_connectionID === $db->_connectionID && $db->database == $d->db->database) 
+                               if ($d->db->_connectionID === $db->_connectionID && $db->database == $d->db->database)
                                        return $k;
                        }
                }
-               
+
                $obj = new ADODB_Active_DB();
                $obj->db = $db;
                $obj->tables = array();
-               
+
                if ($index == false) $index = sizeof($_ADODB_ACTIVE_DBS);
 
-               
+
                $_ADODB_ACTIVE_DBS[$index] = $obj;
-               
+
                return sizeof($_ADODB_ACTIVE_DBS)-1;
 }
 
@@ -75,8 +75,8 @@ function ADODB_SetDatabaseAdapter(&$db, $index=false)
 class ADODB_Active_Record {
        static $_changeNames = true; // dynamically pluralize table names
        static $_quoteNames = false;
-       
-       static $_foreignSuffix = '_id'; // 
+
+       static $_foreignSuffix = '_id'; //
        var $_dbat; // associative index pointing to ADODB_Active_DB eg. $ADODB_Active_DBS[_dbat]
        var $_table; // tablename, if set in class definition then use it as table name
        var $_tableat; // associative index pointing to ADODB_Active_Table, eg $ADODB_Active_DBS[_dbat]->tables[$this->_tableat]
@@ -87,8 +87,8 @@ class ADODB_Active_Record {
 
        var $foreignName; // CFR: class name when in a relationship
 
-       var $lockMode = ' for update '; // you might want to change to 
-       
+       var $lockMode = ' for update '; // you might want to change to
+
        static function UseDefaultValues($bool=null)
        {
        global $ADODB_ACTIVE_DEFVALS;
@@ -97,29 +97,29 @@ class ADODB_Active_Record {
        }
 
        // should be static
-       static function SetDatabaseAdapter(&$db, $index=false) 
+       static function SetDatabaseAdapter(&$db, $index=false)
        {
                return ADODB_SetDatabaseAdapter($db, $index);
        }
-       
-       
+
+
        public function __set($name, $value)
        {
                $name = str_replace(' ', '_', $name);
                $this->$name = $value;
        }
-       
+
        // php5 constructor
        function __construct($table = false, $pkeyarr=false, $db=false)
        {
        global $ADODB_ASSOC_CASE,$_ADODB_ACTIVE_DBS;
-       
+
                if ($db == false && is_object($pkeyarr)) {
                        $db = $pkeyarr;
                        $pkeyarr = false;
                }
-               
-               if (!$table) { 
+
+               if (!$table) {
                        if (!empty($this->_table)) $table = $this->_table;
                        else $table = $this->_pluralize(get_class($this));
                }
@@ -137,13 +137,13 @@ class ADODB_Active_Record {
 
                $this->UpdateActiveTable($pkeyarr);
        }
-       
+
        function __wakeup()
        {
                $class = get_class($this);
                new $class;
        }
-       
+
        function _pluralize($table)
        {
                if (!ADODB_Active_Record::$_changeNames) return $table;
@@ -154,26 +154,26 @@ class ADODB_Active_Record {
                $lastc2 = substr($ut,$len-2);
                switch ($lastc) {
                case 'S':
-                       return $table.'es';     
+                       return $table.'es';
                case 'Y':
                        return substr($table,0,$len-1).'ies';
-               case 'X':       
+               case 'X':
                        return $table.'es';
-               case 'H': 
+               case 'H':
                        if ($lastc2 == 'CH' || $lastc2 == 'SH')
                                return $table.'es';
                default:
                        return $table.'s';
                }
        }
-       
+
        // CFR Lamest singular inflector ever - @todo Make it real!
        // Note: There is an assumption here...and it is that the argument's length >= 4
        function _singularize($tables)
        {
-       
+
                if (!ADODB_Active_Record::$_changeNames) return $table;
-       
+
                $ut = strtoupper($tables);
                $len = strlen($tables);
                if($ut[$len-1] != 'S')
@@ -205,14 +205,14 @@ class ADODB_Active_Record {
                $table->_hasMany[$foreignRef] = $ar;
        #       $this->$foreignRef = $this->_hasMany[$foreignRef]; // WATCHME Removed assignment by ref. to please __get()
        }
-       
+
        // use when you don't want ADOdb to auto-pluralize tablename
        static function TableHasMany($table, $foreignRef, $foreignKey = false, $foreignClass = 'ADODB_Active_Record')
        {
                $ar = new ADODB_Active_Record($table);
                $ar->hasMany($foreignRef, $foreignKey, $foreignClass);
        }
-       
+
        // use when you don't want ADOdb to auto-pluralize tablename
        static function TableKeyHasMany($table, $tablePKey, $foreignRef, $foreignKey = false, $foreignClass = 'ADODB_Active_Record')
        {
@@ -220,8 +220,8 @@ class ADODB_Active_Record {
                $ar = new ADODB_Active_Record($table,$tablePKey);
                $ar->hasMany($foreignRef, $foreignKey, $foreignClass);
        }
-       
-       
+
+
        // use when you want ADOdb to auto-pluralize tablename for you. Note that the class must already be defined.
        // e.g. class Person will generate relationship for table Persons
        static function ClassHasMany($parentclass, $foreignRef, $foreignKey = false, $foreignClass = 'ADODB_Active_Record')
@@ -229,7 +229,7 @@ class ADODB_Active_Record {
                $ar = new $parentclass();
                $ar->hasMany($foreignRef, $foreignKey, $foreignClass);
        }
-       
+
 
        function belongsTo($foreignRef,$foreignKey=false, $parentKey='', $parentClass = 'ADODB_Active_Record')
        {
@@ -240,24 +240,24 @@ class ADODB_Active_Record {
                $ar->parentKey = $parentKey;
                $ar->UpdateActiveTable();
                $ar->foreignKey = ($foreignKey) ? $foreignKey : $foreignRef.ADODB_Active_Record::$_foreignSuffix;
-               
+
                $table =& $this->TableInfo();
                $table->_belongsTo[$foreignRef] = $ar;
        #       $this->$foreignRef = $this->_belongsTo[$foreignRef];
        }
-       
+
        static function ClassBelongsTo($class, $foreignRef, $foreignKey=false, $parentKey='', $parentClass = 'ADODB_Active_Record')
        {
                $ar = new $class();
                $ar->belongsTo($foreignRef, $foreignKey, $parentKey, $parentClass);
        }
-       
+
        static function TableBelongsTo($table, $foreignRef, $foreignKey=false, $parentKey='', $parentClass = 'ADODB_Active_Record')
        {
                $ar = new ADOdb_Active_Record($table);
                $ar->belongsTo($foreignRef, $foreignKey, $parentKey, $parentClass);
        }
-       
+
        static function TableKeyBelongsTo($table, $tablePKey, $foreignRef, $foreignKey=false, $parentKey='', $parentClass = 'ADODB_Active_Record')
        {
                if (!is_array($tablePKey)) $tablePKey = array($tablePKey);
@@ -268,8 +268,8 @@ class ADODB_Active_Record {
 
        /**
         * __get Access properties - used for lazy loading
-        * 
-        * @param mixed $name 
+        *
+        * @param mixed $name
         * @access protected
         * @return mixed
         */
@@ -277,9 +277,9 @@ class ADODB_Active_Record {
        {
                return $this->LoadRelations($name, '', -1, -1);
        }
-       
+
        /**
-        * @param string $name 
+        * @param string $name
         * @param string $whereOrderBy : eg. ' AND field1 = value ORDER BY field2'
         * @param offset
         * @param limit
@@ -291,12 +291,12 @@ class ADODB_Active_Record {
                $table = $this->TableInfo();
                if ($limit >= 0) $extras['limit'] = $limit;
                if ($offset >= 0) $extras['offset'] = $offset;
-               
-               if (strlen($whereOrderBy)) 
+
+               if (strlen($whereOrderBy))
                        if (!preg_match('/^[ \n\r]*AND/i',$whereOrderBy))
                                if (!preg_match('/^[ \n\r]*ORDER[ \n\r]/i',$whereOrderBy))
                                        $whereOrderBy = 'AND '.$whereOrderBy;
-                               
+
                if(!empty($table->_belongsTo[$name]))
                {
                        $obj = $table->_belongsTo[$name];
@@ -307,7 +307,7 @@ class ADODB_Active_Record {
                        {
                                if ($obj->parentKey) $key = $obj->parentKey;
                                else $key = reset($table->keys);
-                               
+
                                $arrayOfOne = $obj->Find($key.'='.$this->$columnName.' '.$whereOrderBy,false,false,$extras);
                                if ($arrayOfOne) {
                                        $this->$name = $arrayOfOne[0];
@@ -316,7 +316,7 @@ class ADODB_Active_Record {
                        }
                }
                if(!empty($table->_hasMany[$name]))
-               {       
+               {
                        $obj = $table->_hasMany[$name];
                        $key = reset($table->keys);
                        $id = @$this->$key;
@@ -329,11 +329,11 @@ class ADODB_Active_Record {
                        $this->$name = $objs;
                        return $objs;
                }
-               
+
                return array();
        }
        //////////////////////////////////
-       
+
        // update metadata
        function UpdateActiveTable($pkeys=false,$forceUpdate=false)
        {
@@ -349,7 +349,7 @@ class ADODB_Active_Record {
 
                        $acttab = $tables[$tableat];
                        foreach($acttab->flds as $name => $fld) {
-                       if ($ADODB_ACTIVE_DEFVALS && isset($fld->default_value)) 
+                       if ($ADODB_ACTIVE_DEFVALS && isset($fld->default_value))
                                $this->$name = $fld->default_value;
                        else
                                $this->$name = null;
@@ -363,19 +363,19 @@ class ADODB_Active_Record {
                        @flock($fp, LOCK_SH);
                        $acttab = unserialize(fread($fp,100000));
                        fclose($fp);
-                       if ($acttab->_created + $ADODB_ACTIVE_CACHESECS - (abs(rand()) % 16) > time()) { 
+                       if ($acttab->_created + $ADODB_ACTIVE_CACHESECS - (abs(rand()) % 16) > time()) {
                                // abs(rand()) randomizes deletion, reducing contention to delete/refresh file
                                // ideally, you should cache at least 32 secs
-                               
+
                                foreach($acttab->flds as $name => $fld) {
-                                       if ($ADODB_ACTIVE_DEFVALS && isset($fld->default_value)) 
+                                       if ($ADODB_ACTIVE_DEFVALS && isset($fld->default_value))
                                                $this->$name = $fld->default_value;
                                        else
                                                $this->$name = null;
                                }
-       
+
                                $activedb->tables[$table] = $acttab;
-                               
+
                                //if ($db->debug) ADOConnection::outp("Reading cached active record file: $fname");
                                return;
                        } else if ($db->debug) {
@@ -384,18 +384,18 @@ class ADODB_Active_Record {
                }
                $activetab = new ADODB_Active_Table();
                $activetab->name = $table;
-               
+
                $save = $ADODB_FETCH_MODE;
                $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
                if ($db->fetchMode !== false) $savem = $db->SetFetchMode(false);
-               
+
                $cols = $db->MetaColumns($table);
-               
+
                if (isset($savem)) $db->SetFetchMode($savem);
                $ADODB_FETCH_MODE = $save;
-               
+
                if (!$cols) {
-                       $this->Error("Invalid table name: $table",'UpdateActiveTable'); 
+                       $this->Error("Invalid table name: $table",'UpdateActiveTable');
                        return false;
                }
                $fld = reset($cols);
@@ -405,17 +405,17 @@ class ADODB_Active_Record {
                                foreach($cols as $name => $fld) {
                                        if (!empty($fld->primary_key)) $pkeys[] = $name;
                                }
-                       } else  
+                       } else
                                $pkeys = $this->GetPrimaryKeys($db, $table);
                }
                if (empty($pkeys)) {
                        $this->Error("No primary key found for table $table",'UpdateActiveTable');
                        return false;
                }
-               
+
                $attr = array();
                $keys = array();
-               
+
                switch($ADODB_ASSOC_CASE) {
                case 0:
                        foreach($cols as $name => $fldobj) {
@@ -430,18 +430,18 @@ class ADODB_Active_Record {
                                $keys[strtolower($name)] = strtolower($name);
                        }
                        break;
-                       
-               case 1: 
+
+               case 1:
                        foreach($cols as $name => $fldobj) {
                                $name = strtoupper($name);
-               
+
                 if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value))
                     $this->$name = $fldobj->default_value;
                 else
                                        $this->$name = null;
                                $attr[$name] = $fldobj;
                        }
-                       
+
                        foreach($pkeys as $k => $name) {
                                $keys[strtoupper($name)] = strtoupper($name);
                        }
@@ -449,7 +449,7 @@ class ADODB_Active_Record {
                default:
                        foreach($cols as $name => $fldobj) {
                                $name = ($fldobj->name);
-                
+
                 if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value))
                     $this->$name = $fldobj->default_value;
                 else
@@ -461,7 +461,7 @@ class ADODB_Active_Record {
                        }
                        break;
                }
-               
+
                $activetab->keys = $keys;
                $activetab->flds = $attr;
 
@@ -473,58 +473,58 @@ class ADODB_Active_Record {
                }
                if (isset($activedb->tables[$table])) {
                        $oldtab = $activedb->tables[$table];
-               
+
                        if ($oldtab) $activetab->_belongsTo = $oldtab->_belongsTo;
                        if ($oldtab) $activetab->_hasMany = $oldtab->_hasMany;
                }
                $activedb->tables[$table] = $activetab;
        }
-       
+
        function GetPrimaryKeys(&$db, $table)
        {
                return $db->MetaPrimaryKeys($table);
        }
-       
-       // error handler for both PHP4+5. 
+
+       // error handler for both PHP4+5.
        function Error($err,$fn)
        {
        global $_ADODB_ACTIVE_DBS;
-       
+
                $fn = get_class($this).'::'.$fn;
                $this->_lasterr = $fn.': '.$err;
-               
+
                if ($this->_dbat < 0) $db = false;
                else {
                        $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
                        $db = $activedb->db;
                }
-               
-               if (function_exists('adodb_throw')) {   
+
+               if (function_exists('adodb_throw')) {
                        if (!$db) adodb_throw('ADOdb_Active_Record', $fn, -1, $err, 0, 0, false);
                        else adodb_throw($db->databaseType, $fn, -1, $err, 0, 0, $db);
                } else
                        if (!$db || $db->debug) ADOConnection::outp($this->_lasterr);
-               
+
        }
-       
+
        // return last error message
        function ErrorMsg()
        {
                if (!function_exists('adodb_throw')) {
                        if ($this->_dbat < 0) $db = false;
                        else $db = $this->DB();
-               
+
                        // last error could be database error too
                        if ($db && $db->ErrorMsg()) return $db->ErrorMsg();
                }
                return $this->_lasterr;
        }
-       
-       function ErrorNo() 
+
+       function ErrorNo()
        {
                if ($this->_dbat < 0) return -9999; // no database connection...
                $db = $this->DB();
-               
+
                return (int) $db->ErrorNo();
        }
 
@@ -533,7 +533,7 @@ class ADODB_Active_Record {
        function DB()
        {
        global $_ADODB_ACTIVE_DBS;
-       
+
                if ($this->_dbat < 0) {
                        $false = false;
                        $this->Error("No database connection set: use ADOdb_Active_Record::SetDatabaseAdaptor(\$db)", "DB");
@@ -543,7 +543,7 @@ class ADODB_Active_Record {
                $db = $activedb->db;
                return $db;
        }
-       
+
        // retrieve ADODB_Active_Table
        function &TableInfo()
        {
@@ -552,8 +552,8 @@ class ADODB_Active_Record {
                $table = $activedb->tables[$this->_tableat];
                return $table;
        }
-       
-       
+
+
        // I have an ON INSERT trigger on a table that sets other columns in the table.
        // So, I find that for myTable, I want to reload an active record after saving it. -- Malcolm Cook
        function Reload()
@@ -564,21 +564,21 @@ class ADODB_Active_Record {
                return($this->Load($where));
        }
 
-       
+
        // set a numeric array (using natural table field ordering) as object properties
        function Set(&$row)
        {
        global $ACTIVE_RECORD_SAFETY;
-       
+
                $db = $this->DB();
-               
+
                if (!$row) {
-                       $this->_saved = false;          
+                       $this->_saved = false;
                        return false;
                }
-               
+
                $this->_saved = true;
-               
+
                $table = $this->TableInfo();
                if ($ACTIVE_RECORD_SAFETY && sizeof($table->flds) != sizeof($row)) {
             # <AP>
@@ -597,7 +597,7 @@ class ADODB_Active_Record {
                }
         else
                        $keys = array_keys($row);
-                       
+
         # <AP>
         reset($keys);
         $this->_original = array();
@@ -611,7 +611,7 @@ class ADODB_Active_Record {
         # </AP>
                return true;
        }
-       
+
        // get last inserted id for INSERT
        function LastInsertID(&$db,$fieldname)
        {
@@ -619,32 +619,32 @@ class ADODB_Active_Record {
                        $val = $db->Insert_ID($this->_table,$fieldname);
                else
                        $val = false;
-                       
+
                if (is_null($val) || $val === false) {
                        // this might not work reliably in multi-user environment
                        return $db->GetOne("select max(".$fieldname.") from ".$this->_table);
                }
                return $val;
        }
-       
+
        // quote data in where clause
        function doquote(&$db, $val,$t)
        {
                switch($t) {
                case 'L':
                        if (strpos($db->databaseType,'postgres') !== false) return $db->qstr($val);
-               case 'D':       
+               case 'D':
                case 'T':
                        if (empty($val)) return 'null';
-               
-               case 'B':       
+
+               case 'B':
                case 'N':
                case 'C':
                case 'X':
                        if (is_null($val)) return 'null';
-                       
-                       if (strlen($val)>0 && 
-                               (strncmp($val,"'",1) != 0 || substr($val,strlen($val)-1,1) != "'")) { 
+
+                       if (strlen($val)>0 &&
+                               (strncmp($val,"'",1) != 0 || substr($val,strlen($val)-1,1) != "'")) {
                                return $db->qstr($val);
                                break;
                        }
@@ -653,13 +653,13 @@ class ADODB_Active_Record {
                        break;
                }
        }
-       
+
        // generate where clause for an UPDATE/SELECT
        function GenWhere(&$db, &$table)
        {
                $keys = $table->keys;
                $parr = array();
-               
+
                foreach($keys as $k) {
                        $f = $table->flds[$k];
                        if ($f) {
@@ -668,55 +668,55 @@ class ADODB_Active_Record {
                }
                return implode(' and ', $parr);
        }
-       
-       
+
+
        function _QName($n,$db=false)
        {
                if (!ADODB_Active_Record::$_quoteNames) return $n;
                if (!$db) $db = $this->DB(); if (!$db) return false;
                return $db->nameQuote.$n.$db->nameQuote;
        }
-       
+
        //------------------------------------------------------------ Public functions below
-       
+
        function Load($where=null,$bindarr=false, $lock = false)
        {
        global $ADODB_FETCH_MODE;
-       
+
                $db = $this->DB(); if (!$db) return false;
                $this->_where = $where;
-               
+
                $save = $ADODB_FETCH_MODE;
                $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
                if ($db->fetchMode !== false) $savem = $db->SetFetchMode(false);
-               
+
                $qry = "select * from ".$this->_table;
-               
+
                if($where) {
                        $qry .= ' WHERE '.$where;
                }
                if ($lock) $qry .= $this->lockMode;
-               
+
                $row = $db->GetRow($qry,$bindarr);
-               
+
                if (isset($savem)) $db->SetFetchMode($savem);
                $ADODB_FETCH_MODE = $save;
-               
+
                return $this->Set($row);
        }
-       
+
        function LoadLocked($where=null, $bindarr=false)
        {
                $this->Load($where,$bindarr,true);
        }
-       
+
        # useful for multiple record inserts
        # see http://phplens.com/lens/lensforum/msgs.php?id=17795
        function Reset()
        {
         $this->_where=null;
-        $this->_saved = false; 
-        $this->_lasterr = false; 
+        $this->_saved = false;
+        $this->_lasterr = false;
         $this->_original = false;
         $vars=get_object_vars($this);
         foreach($vars as $k=>$v){
@@ -727,24 +727,24 @@ class ADODB_Active_Record {
         $this->foreignName=strtolower(get_class($this));
         return true;
     }
-       
+
        // false on error
        function Save()
        {
                if ($this->_saved) $ok = $this->Update();
                else $ok = $this->Insert();
-               
+
                return $ok;
        }
-       
-       
+
+
        // false on error
        function Insert()
        {
                $db = $this->DB(); if (!$db) return false;
                $cnt = 0;
                $table = $this->TableInfo();
-               
+
                $valarr = array();
                $names = array();
                $valstr = array();
@@ -758,7 +758,7 @@ class ADODB_Active_Record {
                                $cnt += 1;
                        }
                }
-               
+
                if (empty($names)){
                        foreach($table->flds as $name=>$fld) {
                                $valarr[] = null;
@@ -769,7 +769,7 @@ class ADODB_Active_Record {
                }
                $sql = 'INSERT INTO '.$this->_table."(".implode(',',$names).') VALUES ('.implode(',',$valstr).')';
                $ok = $db->Execute($sql,$valarr);
-               
+
                if ($ok) {
                        $this->_saved = true;
                        $autoinc = false;
@@ -784,23 +784,23 @@ class ADODB_Active_Record {
                                $this->$k = $this->LastInsertID($db,$k);
                        }
                }
-               
+
                $this->_original = $valarr;
                return !empty($ok);
        }
-       
+
        function Delete()
        {
                $db = $this->DB(); if (!$db) return false;
                $table = $this->TableInfo();
-               
+
                $where = $this->GenWhere($db,$table);
                $sql = 'DELETE FROM '.$this->_table.' WHERE '.$where;
                $ok = $db->Execute($sql);
-               
+
                return $ok ? true : false;
        }
-       
+
        // returns an array of active record objects
        function Find($whereOrderBy,$bindarr=false,$pkeysArr=false,$extra=array())
        {
@@ -808,17 +808,17 @@ class ADODB_Active_Record {
                $arr = $db->GetActiveRecordsClass(get_class($this),$this->_table, $whereOrderBy,$bindarr,$pkeysArr,$extra);
                return $arr;
        }
-       
+
        // returns 0 on error, 1 on update, 2 on insert
        function Replace()
        {
        global $ADODB_ASSOC_CASE;
-               
+
                $db = $this->DB(); if (!$db) return false;
                $table = $this->TableInfo();
-               
+
                $pkey = $table->keys;
-               
+
                foreach($table->flds as $name=>$fld) {
                        $val = $this->$name;
                        /*
@@ -834,24 +834,24 @@ class ADODB_Active_Record {
                        if (is_null($val) && !empty($fld->auto_increment)) {
                continue;
             }
-                       
+
                        if (is_array($val)) continue;
-                       
+
                        $t = $db->MetaType($fld->type);
                        $arr[$name] = $this->doquote($db,$val,$t);
                        $valarr[] = $val;
                }
-               
+
                if (!is_array($pkey)) $pkey = array($pkey);
-               
-               
-               if ($ADODB_ASSOC_CASE == 0) 
+
+
+               if ($ADODB_ASSOC_CASE == 0)
                        foreach($pkey as $k => $v)
                                $pkey[$k] = strtolower($v);
-               elseif ($ADODB_ASSOC_CASE == 1) 
+               elseif ($ADODB_ASSOC_CASE == 1)
                        foreach($pkey as $k => $v)
                                $pkey[$k] = strtoupper($v);
-                               
+
                $ok = $db->Replace($this->_table,$arr,$pkey);
                if ($ok) {
                        $this->_saved = true; // 1= update 2=insert
@@ -868,9 +868,9 @@ class ADODB_Active_Record {
                                        $this->$k = $this->LastInsertID($db,$k);
                                }
                        }
-                       
+
                        $this->_original = $valarr;
-               } 
+               }
                return $ok;
        }
 
@@ -879,14 +879,14 @@ class ADODB_Active_Record {
        {
                $db = $this->DB(); if (!$db) return false;
                $table = $this->TableInfo();
-               
+
                $where = $this->GenWhere($db, $table);
-               
+
                if (!$where) {
                        $this->error("Where missing for table $table", "Update");
                        return false;
                }
-               $valarr = array(); 
+               $valarr = array();
                $neworig = array();
                $pairs = array();
                $i = -1;
@@ -895,10 +895,10 @@ class ADODB_Active_Record {
                        $i += 1;
                        $val = $this->$name;
                        $neworig[] = $val;
-                       
-                       if (isset($table->keys[$name]) || is_array($val)) 
+
+                       if (isset($table->keys[$name]) || is_array($val))
                                continue;
-                       
+
                        if (is_null($val)) {
                                if (isset($fld->not_null) && $fld->not_null) {
                                        if (isset($fld->default_value) && strlen($fld->default_value)) continue;
@@ -910,15 +910,15 @@ class ADODB_Active_Record {
                        }
 
                        if (isset($this->_original[$i]) && strcmp($val,$this->_original[$i]) == 0) continue;
-                       
+
                        if (is_null($this->_original[$i]) && is_null($val)) continue;
-                       
+
                        $valarr[] = $val;
                        $pairs[] = $this->_QName($name,$db).'='.$db->Param($cnt);
                        $cnt += 1;
                }
-               
-               
+
+
                if (!$cnt) return -1;
                $sql = 'UPDATE '.$this->_table." SET ".implode(",",$pairs)." WHERE ".$where;
                $ok = $db->Execute($sql,$valarr);
@@ -928,14 +928,14 @@ class ADODB_Active_Record {
                }
                return 0;
        }
-       
+
        function GetAttributeNames()
        {
                $table = $this->TableInfo();
                if (!$table) return false;
                return array_keys($table->flds);
        }
-       
+
 };
 
 function adodb_GetActiveRecordsClass(&$db, $class, $table,$whereOrderBy,$bindarr, $primkeyArr,
@@ -943,10 +943,10 @@ function adodb_GetActiveRecordsClass(&$db, $class, $table,$whereOrderBy,$bindarr
 {
 global $_ADODB_ACTIVE_DBS;
 
-       
+
        $save = $db->SetFetchMode(ADODB_FETCH_NUM);
        $qry = "select * from ".$table;
-       
+
        if (!empty($whereOrderBy))
                $qry .= ' WHERE '.$whereOrderBy;
        if(isset($extra['limit']))
@@ -967,13 +967,13 @@ global $_ADODB_ACTIVE_DBS;
                $rows = $db->GetAll($qry,$bindarr);
 
        $db->SetFetchMode($save);
-       
+
        $false = false;
-       
-       if ($rows === false) {  
+
+       if ($rows === false) {
                return $false;
        }
-       
+
 
        if (!class_exists($class)) {
                $db->outp_throw("Unknown class $class in GetActiveRecordsClass()",'GetActiveRecordsClass');
@@ -987,7 +987,7 @@ global $_ADODB_ACTIVE_DBS;
        $arrRef = array();
        $bTos = array(); // Will store belongTo's indices if any
        foreach($rows as $row) {
-       
+
                $obj = new $class($table,$primkeyArr,$db);
                if ($obj->ErrorNo()){
                        $db->_errorMsg = $obj->ErrorMsg();
@@ -995,8 +995,7 @@ global $_ADODB_ACTIVE_DBS;
                }
                $obj->Set($row);
                $arr[] = $obj;
-       } // foreach($rows as $row) 
+       } // foreach($rows as $row)
 
        return $arr;
 }
-?>
\ No newline at end of file
index fd80749..e820144 100644 (file)
@@ -1,20 +1,20 @@
 <?php
 /*
 
-@version V5.06 29 Sept 2008   (c) 2000-2012 John Lim (jlim#natsoft.com). All rights reserved.
+@version V5.19  23-Apr-2014  (c) 2000-2014 John Lim (jlim#natsoft.com). All rights reserved.
   Latest version is available at http://adodb.sourceforge.net
-  Released under both BSD license and Lesser GPL library license. 
-  Whenever there is any discrepancy between the two licenses, 
+
+  Released under both BSD license and Lesser GPL library license.
+  Whenever there is any discrepancy between the two licenses,
   the BSD license will take precedence.
-  
+
   Active Record implementation. Superset of Zend Framework's.
-  
-  This is "Active Record eXtended" to support JOIN, WORK and LAZY mode by Chris Ravenscroft  chris#voilaweb.com 
-  
+
+  This is "Active Record eXtended" to support JOIN, WORK and LAZY mode by Chris Ravenscroft  chris#voilaweb.com
+
   Version 0.9
-  
-  See http://www-128.ibm.com/developerworks/java/library/j-cb03076/?ca=dgr-lnxw01ActiveRecord 
+
+  See http://www-128.ibm.com/developerworks/java/library/j-cb03076/?ca=dgr-lnxw01ActiveRecord
        for info on Ruby on Rails Active Record implementation
 */
 
@@ -63,29 +63,29 @@ class ADODB_Active_Table {
 function ADODB_SetDatabaseAdapter(&$db)
 {
        global $_ADODB_ACTIVE_DBS;
-       
+
                foreach($_ADODB_ACTIVE_DBS as $k => $d) {
                        if (PHP_VERSION >= 5) {
                                if ($d->db === $db) return $k;
                        } else {
-                               if ($d->db->_connectionID === $db->_connectionID && $db->database == $d->db->database) 
+                               if ($d->db->_connectionID === $db->_connectionID && $db->database == $d->db->database)
                                        return $k;
                        }
                }
-               
+
                $obj = new ADODB_Active_DB();
                $obj->db = $db;
                $obj->tables = array();
-               
+
                $_ADODB_ACTIVE_DBS[] = $obj;
-               
+
                return sizeof($_ADODB_ACTIVE_DBS)-1;
 }
 
 
 class ADODB_Active_Record {
        static $_changeNames = true; // dynamically pluralize table names
-       static $_foreignSuffix = '_id'; // 
+       static $_foreignSuffix = '_id'; //
        var $_dbat; // associative index pointing to ADODB_Active_DB eg. $ADODB_Active_DBS[_dbat]
        var $_table; // tablename, if set in class definition then use it as table name
        var $_sTable; // singularized table name
@@ -106,18 +106,18 @@ class ADODB_Active_Record {
        }
 
        // should be static
-       static function SetDatabaseAdapter(&$db) 
+       static function SetDatabaseAdapter(&$db)
        {
                return ADODB_SetDatabaseAdapter($db);
        }
-       
-       
+
+
        public function __set($name, $value)
        {
                $name = str_replace(' ', '_', $name);
                $this->$name = $value;
        }
-       
+
        // php5 constructor
        // Note: if $table is defined, then we will use it as our table name
        // Otherwise we will use our classname...
@@ -131,12 +131,12 @@ class ADODB_Active_Record {
        function __construct($table = false, $pkeyarr=false, $db=false, $options=array())
        {
        global $ADODB_ASSOC_CASE,$_ADODB_ACTIVE_DBS;
-       
+
                if ($db == false && is_object($pkeyarr)) {
                        $db = $pkeyarr;
                        $pkeyarr = false;
                }
-               
+
                if($table)
                {
                        // table argument exists. It is expected to be
@@ -159,10 +159,10 @@ class ADODB_Active_Record {
                        $this->_dbat = ADODB_Active_Record::SetDatabaseAdapter($db);
                } else
                        $this->_dbat = sizeof($_ADODB_ACTIVE_DBS)-1;
-               
-               
+
+
                if ($this->_dbat < 0) $this->Error("No database connection set; use ADOdb_Active_Record::SetDatabaseAdapter(\$db)",'ADODB_Active_Record::__constructor');
-               
+
                $this->_tableat = $this->_table; # reserved for setting the assoc value to a non-table name, eg. the sql string in future
 
                // CFR: Just added this option because UpdateActiveTable() can refresh its information
@@ -178,13 +178,13 @@ class ADODB_Active_Record {
                        $table->_belongsTo = array();
                }
        }
-       
+
        function __wakeup()
        {
                $class = get_class($this);
                new $class;
        }
-       
+
        // CFR: Constants found in Rails
        static $IrregularP = array(
                'PERSON'    => 'people',
@@ -231,26 +231,26 @@ class ADODB_Active_Record {
                $lastc2 = substr($ut,$len-2);
                switch ($lastc) {
                case 'S':
-                       return $table.'es';     
+                       return $table.'es';
                case 'Y':
                        return substr($table,0,$len-1).'ies';
-               case 'X':       
+               case 'X':
                        return $table.'es';
-               case 'H': 
+               case 'H':
                        if ($lastc2 == 'CH' || $lastc2 == 'SH')
                                return $table.'es';
                default:
                        return $table.'s';
                }
        }
-       
+
        // CFR Lamest singular inflector ever - @todo Make it real!
        // Note: There is an assumption here...and it is that the argument's length >= 4
        function _singularize($table)
        {
-       
+
                if (!ADODB_Active_Record::$_changeNames) return $table;
-       
+
                $ut = strtoupper($table);
                if(isset(self::$WeIsI[$ut]))
                {
@@ -320,7 +320,7 @@ class ADODB_Active_Record {
                $ar->foreignName = $foreignRef;
                $ar->UpdateActiveTable();
                $ar->foreignKey = ($foreignKey) ? $foreignKey : $ar->foreignName . self::$_foreignSuffix;
-               
+
                $table =& $this->TableInfo();
                if(!isset($table->_belongsTo[$foreignRef]))
                {
@@ -332,8 +332,8 @@ class ADODB_Active_Record {
 
        /**
         * __get Access properties - used for lazy loading
-        * 
-        * @param mixed $name 
+        *
+        * @param mixed $name
         * @access protected
         * @return void
         */
@@ -348,12 +348,12 @@ class ADODB_Active_Record {
                if($offset >= 0) $extras['offset'] = $offset;
                if($limit >= 0) $extras['limit'] = $limit;
                $table =& $this->TableInfo();
-               
-               if (strlen($whereOrderBy)) 
+
+               if (strlen($whereOrderBy))
                        if (!preg_match('/^[ \n\r]*AND/i',$whereOrderBy))
                                if (!preg_match('/^[ \n\r]*ORDER[ \n\r]/i',$whereOrderBy))
                                        $whereOrderBy = 'AND '.$whereOrderBy;
-                                       
+
                if(!empty($table->_belongsTo[$name]))
                {
                        $obj = $table->_belongsTo[$name];
@@ -366,7 +366,7 @@ class ADODB_Active_Record {
                                        $belongsToId = $k;
                                else
                                        $belongsToId = 'id';
-                               
+
                                $arrayOfOne =
                                        $obj->Find(
                                                $belongsToId.'='.$this->$columnName.' '.$whereOrderBy, false, false, $extras);
@@ -380,7 +380,7 @@ class ADODB_Active_Record {
                        if(($k = reset($table->keys)))
                                $hasManyId   = $k;
                        else
-                               $hasManyId   = 'id';                    
+                               $hasManyId   = 'id';
 
                        $this->$name =
                                $obj->Find(
@@ -389,7 +389,7 @@ class ADODB_Active_Record {
                }
        }
        //////////////////////////////////
-       
+
        // update metadata
        function UpdateActiveTable($pkeys=false,$forceUpdate=false)
        {
@@ -405,14 +405,14 @@ class ADODB_Active_Record {
 
                        $tobj = $tables[$tableat];
                        foreach($tobj->flds as $name => $fld) {
-                       if ($ADODB_ACTIVE_DEFVALS && isset($fld->default_value)) 
+                       if ($ADODB_ACTIVE_DEFVALS && isset($fld->default_value))
                                $this->$name = $fld->default_value;
                        else
                                $this->$name = null;
                        }
                        return;
                }
-               
+
                $db = $activedb->db;
                $fname = $ADODB_CACHE_DIR . '/adodb_' . $db->databaseType . '_active_'. $table . '.cache';
                if (!$forceUpdate && $ADODB_ACTIVE_CACHESECS && $ADODB_CACHE_DIR && file_exists($fname)) {
@@ -420,11 +420,11 @@ class ADODB_Active_Record {
                        @flock($fp, LOCK_SH);
                        $acttab = unserialize(fread($fp,100000));
                        fclose($fp);
-                       if ($acttab->_created + $ADODB_ACTIVE_CACHESECS - (abs(rand()) % 16) > time()) { 
+                       if ($acttab->_created + $ADODB_ACTIVE_CACHESECS - (abs(rand()) % 16) > time()) {
                                // abs(rand()) randomizes deletion, reducing contention to delete/refresh file
                                // ideally, you should cache at least 32 secs
                                $activedb->tables[$table] = $acttab;
-                               
+
                                //if ($db->debug) ADOConnection::outp("Reading cached active record file: $fname");
                                return;
                        } else if ($db->debug) {
@@ -433,18 +433,18 @@ class ADODB_Active_Record {
                }
                $activetab = new ADODB_Active_Table();
                $activetab->name = $table;
-               
+
                $save = $ADODB_FETCH_MODE;
                $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
                if ($db->fetchMode !== false) $savem = $db->SetFetchMode(false);
-               
+
                $cols = $db->MetaColumns($table);
-               
+
                if (isset($savem)) $db->SetFetchMode($savem);
                $ADODB_FETCH_MODE = $save;
-               
+
                if (!$cols) {
-                       $this->Error("Invalid table name: $table",'UpdateActiveTable'); 
+                       $this->Error("Invalid table name: $table",'UpdateActiveTable');
                        return false;
                }
                $fld = reset($cols);
@@ -454,17 +454,17 @@ class ADODB_Active_Record {
                                foreach($cols as $name => $fld) {
                                        if (!empty($fld->primary_key)) $pkeys[] = $name;
                                }
-                       } else  
+                       } else
                                $pkeys = $this->GetPrimaryKeys($db, $table);
                }
                if (empty($pkeys)) {
                        $this->Error("No primary key found for table $table",'UpdateActiveTable');
                        return false;
                }
-               
+
                $attr = array();
                $keys = array();
-               
+
                switch($ADODB_ASSOC_CASE) {
                case 0:
                        foreach($cols as $name => $fldobj) {
@@ -479,18 +479,18 @@ class ADODB_Active_Record {
                                $keys[strtolower($name)] = strtolower($name);
                        }
                        break;
-                       
-               case 1: 
+
+               case 1:
                        foreach($cols as $name => $fldobj) {
                                $name = strtoupper($name);
-               
+
                 if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value))
                     $this->$name = $fldobj->default_value;
                 else
                                        $this->$name = null;
                                $attr[$name] = $fldobj;
                        }
-                       
+
                        foreach($pkeys as $k => $name) {
                                $keys[strtoupper($name)] = strtoupper($name);
                        }
@@ -498,7 +498,7 @@ class ADODB_Active_Record {
                default:
                        foreach($cols as $name => $fldobj) {
                                $name = ($fldobj->name);
-                
+
                 if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value))
                     $this->$name = $fldobj->default_value;
                 else
@@ -510,7 +510,7 @@ class ADODB_Active_Record {
                        }
                        break;
                }
-               
+
                $activetab->keys = $keys;
                $activetab->flds = $attr;
                $activetab->updateColsCount();
@@ -523,58 +523,58 @@ class ADODB_Active_Record {
                }
                if (isset($activedb->tables[$table])) {
                        $oldtab = $activedb->tables[$table];
-               
+
                        if ($oldtab) $activetab->_belongsTo = $oldtab->_belongsTo;
                        if ($oldtab) $activetab->_hasMany = $oldtab->_hasMany;
                }
                $activedb->tables[$table] = $activetab;
        }
-       
+
        function GetPrimaryKeys(&$db, $table)
        {
                return $db->MetaPrimaryKeys($table);
        }
-       
-       // error handler for both PHP4+5. 
+
+       // error handler for both PHP4+5.
        function Error($err,$fn)
        {
        global $_ADODB_ACTIVE_DBS;
-       
+
                $fn = get_class($this).'::'.$fn;
                $this->_lasterr = $fn.': '.$err;
-               
+
                if ($this->_dbat < 0) $db = false;
                else {
                        $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
                        $db = $activedb->db;
                }
-               
-               if (function_exists('adodb_throw')) {   
+
+               if (function_exists('adodb_throw')) {
                        if (!$db) adodb_throw('ADOdb_Active_Record', $fn, -1, $err, 0, 0, false);
                        else adodb_throw($db->databaseType, $fn, -1, $err, 0, 0, $db);
                } else
                        if (!$db || $db->debug) ADOConnection::outp($this->_lasterr);
-               
+
        }
-       
+
        // return last error message
        function ErrorMsg()
        {
                if (!function_exists('adodb_throw')) {
                        if ($this->_dbat < 0) $db = false;
                        else $db = $this->DB();
-               
+
                        // last error could be database error too
                        if ($db && $db->ErrorMsg()) return $db->ErrorMsg();
                }
                return $this->_lasterr;
        }
-       
-       function ErrorNo() 
+
+       function ErrorNo()
        {
                if ($this->_dbat < 0) return -9999; // no database connection...
                $db = $this->DB();
-               
+
                return (int) $db->ErrorNo();
        }
 
@@ -583,7 +583,7 @@ class ADODB_Active_Record {
        function DB()
        {
        global $_ADODB_ACTIVE_DBS;
-       
+
                if ($this->_dbat < 0) {
                        $false = false;
                        $this->Error("No database connection set: use ADOdb_Active_Record::SetDatabaseAdaptor(\$db)", "DB");
@@ -593,18 +593,18 @@ class ADODB_Active_Record {
                $db = $activedb->db;
                return $db;
        }
-       
+
        // retrieve ADODB_Active_Table
        function &TableInfo()
        {
        global $_ADODB_ACTIVE_DBS;
-       
+
                $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
                $table = $activedb->tables[$this->_tableat];
                return $table;
        }
-       
-       
+
+
        // I have an ON INSERT trigger on a table that sets other columns in the table.
        // So, I find that for myTable, I want to reload an active record after saving it. -- Malcolm Cook
        function Reload()
@@ -615,21 +615,21 @@ class ADODB_Active_Record {
                return($this->Load($where));
        }
 
-       
+
        // set a numeric array (using natural table field ordering) as object properties
        function Set(&$row)
        {
        global $ACTIVE_RECORD_SAFETY;
-       
+
                $db = $this->DB();
-               
+
                if (!$row) {
-                       $this->_saved = false;          
+                       $this->_saved = false;
                        return false;
                }
-               
+
                $this->_saved = true;
-               
+
                $table = $this->TableInfo();
                $sizeofFlds = sizeof($table->flds);
                $sizeofRow  = sizeof($row);
@@ -687,7 +687,7 @@ class ADODB_Active_Record {
         # </AP>
                return true;
        }
-       
+
        // get last inserted id for INSERT
        function LastInsertID(&$db,$fieldname)
        {
@@ -695,14 +695,14 @@ class ADODB_Active_Record {
                        $val = $db->Insert_ID($this->_table,$fieldname);
                else
                        $val = false;
-                       
+
                if (is_null($val) || $val === false) {
                        // this might not work reliably in multi-user environment
                        return $db->GetOne("select max(".$fieldname.") from ".$this->_table);
                }
                return $val;
        }
-       
+
        // quote data in where clause
        function doquote(&$db, $val,$t)
        {
@@ -710,13 +710,13 @@ class ADODB_Active_Record {
                case 'D':
                case 'T':
                        if (empty($val)) return 'null';
-                       
+
                case 'C':
                case 'X':
                        if (is_null($val)) return 'null';
-                       
-                       if (strlen($val)>0 && 
-                               (strncmp($val,"'",1) != 0 || substr($val,strlen($val)-1,1) != "'")) { 
+
+                       if (strlen($val)>0 &&
+                               (strncmp($val,"'",1) != 0 || substr($val,strlen($val)-1,1) != "'")) {
                                return $db->qstr($val);
                                break;
                        }
@@ -725,13 +725,13 @@ class ADODB_Active_Record {
                        break;
                }
        }
-       
+
        // generate where clause for an UPDATE/SELECT
        function GenWhere(&$db, &$table)
        {
                $keys = $table->keys;
                $parr = array();
-               
+
                foreach($keys as $k) {
                        $f = $table->flds[$k];
                        if ($f) {
@@ -740,15 +740,15 @@ class ADODB_Active_Record {
                }
                return implode(' and ', $parr);
        }
-       
-       
+
+
        //------------------------------------------------------------ Public functions below
-       
+
        function Load($where=null,$bindarr=false)
        {
                $db = $this->DB(); if (!$db) return false;
                $this->_where = $where;
-               
+
                $save = $db->SetFetchMode(ADODB_FETCH_NUM);
                $qry = "select * from ".$this->_table;
                $table =& $this->TableInfo();
@@ -757,7 +757,7 @@ class ADODB_Active_Record {
                        $hasManyId   = $k;
                else
                        $hasManyId   = 'id';
-               
+
                foreach($table->_belongsTo as $foreignTable)
                {
                        if(($k = reset($foreignTable->TableInfo()->keys)))
@@ -780,7 +780,7 @@ class ADODB_Active_Record {
                }
                if($where)
                        $qry .= ' WHERE '.$where;
-               
+
                // Simple case: no relations. Load row and return.
                if((count($table->_hasMany) + count($table->_belongsTo)) < 1)
                {
@@ -790,7 +790,7 @@ class ADODB_Active_Record {
                        $db->SetFetchMode($save);
                        return $this->Set($row);
                }
-               
+
                // More complex case when relations have to be collated
                $rows = $db->GetAll($qry,$bindarr);
                if(!$rows)
@@ -800,7 +800,7 @@ class ADODB_Active_Record {
                        return false;
                $class = get_class($this);
                $isFirstRow = true;
-               
+
                if(($k = reset($this->TableInfo()->keys)))
                        $myId   = $k;
                else
@@ -819,7 +819,7 @@ class ADODB_Active_Record {
                }
                if(!$found)
                        $this->outp_throw("Unable to locate key $myId for $class in Load()",'Load');
-               
+
                foreach($rows as $row)
                {
                        $rowId = intval($row[$index]);
@@ -873,21 +873,21 @@ class ADODB_Active_Record {
                                                        }
                                                }
                                        }
-                               }                               
+                               }
                        }
                }
                return true;
        }
-       
+
        // false on error
        function Save()
        {
                if ($this->_saved) $ok = $this->Update();
                else $ok = $this->Insert();
-               
+
                return $ok;
        }
-       
+
        // CFR: Sometimes we may wish to consider that an object is not to be replaced but inserted.
        // Sample use case: an 'undo' command object (after a delete())
        function Dirty()
@@ -901,7 +901,7 @@ class ADODB_Active_Record {
                $db = $this->DB(); if (!$db) return false;
                $cnt = 0;
                $table = $this->TableInfo();
-               
+
                $valarr = array();
                $names = array();
                $valstr = array();
@@ -915,7 +915,7 @@ class ADODB_Active_Record {
                                $cnt += 1;
                        }
                }
-               
+
                if (empty($names)){
                        foreach($table->flds as $name=>$fld) {
                                $valarr[] = null;
@@ -926,7 +926,7 @@ class ADODB_Active_Record {
                }
                $sql = 'INSERT INTO '.$this->_table."(".implode(',',$names).') VALUES ('.implode(',',$valstr).')';
                $ok = $db->Execute($sql,$valarr);
-               
+
                if ($ok) {
                        $this->_saved = true;
                        $autoinc = false;
@@ -941,23 +941,23 @@ class ADODB_Active_Record {
                                $this->$k = $this->LastInsertID($db,$k);
                        }
                }
-               
+
                $this->_original = $valarr;
                return !empty($ok);
        }
-       
+
        function Delete()
        {
                $db = $this->DB(); if (!$db) return false;
                $table = $this->TableInfo();
-               
+
                $where = $this->GenWhere($db,$table);
                $sql = 'DELETE FROM '.$this->_table.' WHERE '.$where;
                $ok = $db->Execute($sql);
-               
+
                return $ok ? true : false;
        }
-       
+
        // returns an array of active record objects
        function Find($whereOrderBy,$bindarr=false,$pkeysArr=false,$extra=array())
        {
@@ -967,7 +967,7 @@ class ADODB_Active_Record {
                        array('foreignName'=>$this->foreignName, 'belongsTo'=>$table->_belongsTo, 'hasMany'=>$table->_hasMany));
                return $arr;
        }
-       
+
        // CFR: In introduced this method to ensure that inner workings are not disturbed by
        // subclasses...for instance when GetActiveRecordsClass invokes Find()
        // Why am I not invoking parent::Find?
@@ -985,12 +985,12 @@ class ADODB_Active_Record {
        function Replace()
        {
        global $ADODB_ASSOC_CASE;
-               
+
                $db = $this->DB(); if (!$db) return false;
                $table = $this->TableInfo();
-               
+
                $pkey = $table->keys;
-               
+
                foreach($table->flds as $name=>$fld) {
                        $val = $this->$name;
                        /*
@@ -1010,17 +1010,17 @@ class ADODB_Active_Record {
                        $arr[$name] = $this->doquote($db,$val,$t);
                        $valarr[] = $val;
                }
-               
+
                if (!is_array($pkey)) $pkey = array($pkey);
-               
-               
-               if ($ADODB_ASSOC_CASE == 0) 
+
+
+               if ($ADODB_ASSOC_CASE == 0)
                        foreach($pkey as $k => $v)
                                $pkey[$k] = strtolower($v);
-               elseif ($ADODB_ASSOC_CASE == 1) 
+               elseif ($ADODB_ASSOC_CASE == 1)
                        foreach($pkey as $k => $v)
                                $pkey[$k] = strtoupper($v);
-                               
+
                $ok = $db->Replace($this->_table,$arr,$pkey);
                if ($ok) {
                        $this->_saved = true; // 1= update 2=insert
@@ -1037,9 +1037,9 @@ class ADODB_Active_Record {
                                        $this->$k = $this->LastInsertID($db,$k);
                                }
                        }
-                       
+
                        $this->_original = $valarr;
-               } 
+               }
                return $ok;
        }
 
@@ -1048,14 +1048,14 @@ class ADODB_Active_Record {
        {
                $db = $this->DB(); if (!$db) return false;
                $table = $this->TableInfo();
-               
+
                $where = $this->GenWhere($db, $table);
-               
+
                if (!$where) {
                        $this->error("Where missing for table $table", "Update");
                        return false;
                }
-               $valarr = array(); 
+               $valarr = array();
                $neworig = array();
                $pairs = array();
                $i = -1;
@@ -1064,11 +1064,11 @@ class ADODB_Active_Record {
                        $i += 1;
                        $val = $this->$name;
                        $neworig[] = $val;
-                       
+
                        if (isset($table->keys[$name])) {
                                continue;
                        }
-                       
+
                        if (is_null($val)) {
                                if (isset($fld->not_null) && $fld->not_null) {
                                        if (isset($fld->default_value) && strlen($fld->default_value)) continue;
@@ -1078,16 +1078,16 @@ class ADODB_Active_Record {
                                        }
                                }
                        }
-                       
+
                        if (isset($this->_original[$i]) && $val == $this->_original[$i]) {
                                continue;
-                       }                       
+                       }
                        $valarr[] = $val;
                        $pairs[] = $name.'='.$db->Param($cnt);
                        $cnt += 1;
                }
-               
-               
+
+
                if (!$cnt) return -1;
                $sql = 'UPDATE '.$this->_table." SET ".implode(",",$pairs)." WHERE ".$where;
                $ok = $db->Execute($sql,$valarr);
@@ -1097,23 +1097,23 @@ class ADODB_Active_Record {
                }
                return 0;
        }
-       
+
        function GetAttributeNames()
        {
                $table = $this->TableInfo();
                if (!$table) return false;
                return array_keys($table->flds);
        }
-       
+
 };
 
 function adodb_GetActiveRecordsClass(&$db, $class, $tableObj,$whereOrderBy,$bindarr, $primkeyArr,
                        $extra, $relations)
 {
        global $_ADODB_ACTIVE_DBS;
-       
+
                if (empty($extra['loading'])) $extra['loading'] = ADODB_LAZY_AR;
-               
+
                $save = $db->SetFetchMode(ADODB_FETCH_NUM);
                $table = &$tableObj->_table;
                $tableInfo =& $tableObj->TableInfo();
@@ -1135,7 +1135,7 @@ function adodb_GetActiveRecordsClass(&$db, $class, $tableObj,$whereOrderBy,$bind
                }
                if(!$found)
                        $db->outp_throw("Unable to locate key $myId for $class in GetActiveRecordsClass()",'GetActiveRecordsClass');
-               
+
                $qry = "select * from ".$table;
                if(ADODB_JOIN_AR == $extra['loading'])
                {
@@ -1192,19 +1192,19 @@ function adodb_GetActiveRecordsClass(&$db, $class, $tableObj,$whereOrderBy,$bind
                        }
                } else
                        $rows = $db->GetAll($qry,$bindarr);
-                       
+
                $db->SetFetchMode($save);
-               
+
                $false = false;
-               
-               if ($rows === false) {  
+
+               if ($rows === false) {
                        return $false;
                }
-               
-               
+
+
                if (!isset($_ADODB_ACTIVE_DBS)) {
                        include(ADODB_DIR.'/adodb-active-record.inc.php');
-               }       
+               }
                if (!class_exists($class)) {
                        $db->outp_throw("Unknown class $class in GetActiveRecordsClass()",'GetActiveRecordsClass');
                        return $false;
@@ -1218,7 +1218,7 @@ function adodb_GetActiveRecordsClass(&$db, $class, $tableObj,$whereOrderBy,$bind
                $arrRef = array();
                $bTos = array(); // Will store belongTo's indices if any
                foreach($rows as $row) {
-               
+
                        $obj = new $class($table,$primkeyArr,$db);
                        if ($obj->ErrorNo()){
                                $db->_errorMsg = $obj->ErrorMsg();
@@ -1268,7 +1268,7 @@ function adodb_GetActiveRecordsClass(&$db, $class, $tableObj,$whereOrderBy,$bind
                        {
                                if(ADODB_JOIN_AR == $extra['loading'])
                                {
-                                       $isNewObj = !isset($uniqArr['_'.$row[0]]); 
+                                       $isNewObj = !isset($uniqArr['_'.$row[0]]);
                                        if($isNewObj)
                                                $uniqArr['_'.$row[0]] = $obj;
 
@@ -1322,7 +1322,7 @@ function adodb_GetActiveRecordsClass(&$db, $class, $tableObj,$whereOrderBy,$bind
                                                }
                                        }
                                        if(!$isNewObj)
-                                               unset($obj); // We do not need this object itself anymore and do not want it re-added to the main array                                 
+                                               unset($obj); // We do not need this object itself anymore and do not want it re-added to the main array
                                }
                                else if(ADODB_LAZY_AR == $extra['loading'])
                                {
@@ -1382,7 +1382,7 @@ function adodb_GetActiveRecordsClass(&$db, $class, $tableObj,$whereOrderBy,$bind
                                                array_push($arrRef[$obj->$dbClassRef]->$foreignName, $obj);
                                        }
                                }
-                               
+
                        }
                        if(!empty($relations['belongsTo']))
                        {
@@ -1398,7 +1398,7 @@ function adodb_GetActiveRecordsClass(&$db, $class, $tableObj,$whereOrderBy,$bind
                                        else
                                        {
                                                $belongsToId = 'id';
-                                       }                                               
+                                       }
                                        $origObjsArr = $bTos[$foreignTableRef];
                                        $bTosString = implode(',', array_keys($bTos[$foreignTableRef]));
                                        $foreignName = $foreignTable->foreignName;
@@ -1418,4 +1418,3 @@ function adodb_GetActiveRecordsClass(&$db, $class, $tableObj,$whereOrderBy,$bind
 
                return $arr;
 }
-?>
index 26618ab..d70c16f 100644 (file)
@@ -6,19 +6,19 @@ if (!defined('ADODB_DIR')) die();
 global $ADODB_INCLUDED_CSV;
 $ADODB_INCLUDED_CSV = 1;
 
-/* 
+/*
 
-  V5.18 3 Sep 2012   (c) 2000-2012 John Lim (jlim#natsoft.com). All rights reserved.
-  Released under both BSD license and Lesser GPL library license. 
-  Whenever there is any discrepancy between the two licenses, 
-  the BSD license will take precedence. See License.txt. 
+  V5.19  23-Apr-2014  (c) 2000-2014 John Lim (jlim#natsoft.com). All rights reserved.
+  Released under both BSD license and Lesser GPL library license.
+  Whenever there is any discrepancy between the two licenses,
+  the BSD license will take precedence. See License.txt.
   Set tabs to 4 for best viewing.
-  
+
   Latest version is available at http://adodb.sourceforge.net
-  
-  Library for CSV serialization. This is used by the csv/proxy driver and is the 
-  CacheExecute() serialization format. 
-  
+
+  Library for CSV serialization. This is used by the csv/proxy driver and is the
+  CacheExecute() serialization format.
+
   ==== NOTE ====
   Format documented at http://php.weblogs.com/ADODB_CSV
   ==============
@@ -34,61 +34,61 @@ $ADODB_INCLUDED_CSV = 1;
        function _rs2serialize(&$rs,$conn=false,$sql='')
        {
                $max = ($rs) ? $rs->FieldCount() : 0;
-               
+
                if ($sql) $sql = urlencode($sql);
                // metadata setup
-               
+
                if ($max <= 0 || $rs->dataProvider == 'empty') { // is insert/update/delete
                        if (is_object($conn)) {
                                $sql .= ','.$conn->Affected_Rows();
                                $sql .= ','.$conn->Insert_ID();
                        } else
                                $sql .= ',,';
-                       
+
                        $text = "====-1,0,$sql\n";
                        return $text;
                }
                $tt = ($rs->timeCreated) ? $rs->timeCreated : time();
-               
+
                ## changed format from ====0 to ====1
                $line = "====1,$tt,$sql\n";
-               
+
                if ($rs->databaseType == 'array') {
                        $rows = $rs->_array;
                } else {
                        $rows = array();
-                       while (!$rs->EOF) {     
+                       while (!$rs->EOF) {
                                $rows[] = $rs->fields;
                                $rs->MoveNext();
-                       } 
+                       }
                }
-               
+
                for($i=0; $i < $max; $i++) {
                        $o = $rs->FetchField($i);
                        $flds[] = $o;
                }
-       
+
                $savefetch = isset($rs->adodbFetchMode) ? $rs->adodbFetchMode : $rs->fetchMode;
                $class = $rs->connection->arrayClass;
                $rs2 = new $class();
                $rs2->timeCreated = $rs->timeCreated; # memcache fix
                $rs2->sql = $rs->sql;
-               $rs2->oldProvider = $rs->dataProvider; 
+               $rs2->oldProvider = $rs->dataProvider;
                $rs2->InitArrayFields($rows,$flds);
                $rs2->fetchMode = $savefetch;
                return $line.serialize($rs2);
        }
 
-       
+
 /**
-* Open CSV file and convert it into Data. 
+* Open CSV file and convert it into Data.
 *
 * @param url           file/ftp/http url
 * @param err           returns the error message
 * @param timeout       dispose if recordset has been alive for $timeout secs
 *
 * @return              recordset, or false if error occured. If no
-*                      error occurred in sql INSERT/UPDATE/DELETE, 
+*                      error occurred in sql INSERT/UPDATE/DELETE,
 *                      empty recordset is returned
 */
        function csv2rs($url,&$err,$timeout=0, $rsclass='ADORecordSet_array')
@@ -103,7 +103,7 @@ $ADODB_INCLUDED_CSV = 1;
                @flock($fp, LOCK_SH);
                $arr = array();
                $ttl = 0;
-               
+
                if ($meta = fgetcsv($fp, 32000, ",")) {
                        // check if error message
                        if (strncmp($meta[0],'****',4) === 0) {
@@ -113,10 +113,10 @@ $ADODB_INCLUDED_CSV = 1;
                        }
                        // check for meta data
                        // $meta[0] is -1 means return an empty recordset
-                       // $meta[1] contains a time 
-       
+                       // $meta[1] contains a time
+
                        if (strncmp($meta[0], '====',4) === 0) {
-                       
+
                                if ($meta[0] == "====-1") {
                                        if (sizeof($meta) < 5) {
                                                $err = "Corrupt first line for format -1";
@@ -124,12 +124,12 @@ $ADODB_INCLUDED_CSV = 1;
                                                return $false;
                                        }
                                        fclose($fp);
-                                       
+
                                        if ($timeout > 0) {
                                                $err = " Illegal Timeout $timeout ";
                                                return $false;
                                        }
-                                       
+
                                        $rs = new $rsclass($val=true);
                                        $rs->fields = array();
                                        $rs->timeCreated = $meta[1];
@@ -137,9 +137,9 @@ $ADODB_INCLUDED_CSV = 1;
                                        $rs->_numOfFields = 0;
                                        $rs->sql = urldecode($meta[2]);
                                        $rs->affectedrows = (integer)$meta[3];
-                                       $rs->insertid = $meta[4];       
+                                       $rs->insertid = $meta[4];
                                        return $rs;
-                               } 
+                               }
                        # Under high volume loads, we want only 1 thread/process to _write_file
                        # so that we don't have 50 processes queueing to write the same data.
                        # We use probabilistic timeout, ahead of time.
@@ -149,7 +149,7 @@ $ADODB_INCLUDED_CSV = 1;
                        # -1 sec after timeout give processes 1/4 chance of timing out
                        # +0 sec after timeout, give processes 100% chance of timing out
                                if (sizeof($meta) > 1) {
-                                       if($timeout >0){ 
+                                       if($timeout >0){
                                                $tdiff = (integer)( $meta[1]+$timeout - time());
                                                if ($tdiff <= 2) {
                                                        switch($tdiff) {
@@ -161,7 +161,7 @@ $ADODB_INCLUDED_CSV = 1;
                                                                        return $false;
                                                                }
                                                                break;
-                                                       case 2: 
+                                                       case 2:
                                                                if ((rand() & 15) == 0) {
                                                                        fclose($fp);
                                                                        $err = "Timeout 2";
@@ -175,12 +175,12 @@ $ADODB_INCLUDED_CSV = 1;
                                                                        return $false;
                                                                }
                                                                break;
-                                                       default: 
+                                                       default:
                                                                fclose($fp);
                                                                $err = "Timeout 0";
                                                                return $false;
                                                        } // switch
-                                                       
+
                                                } // if check flush cache
                                        }// (timeout>0)
                                        $ttl = $meta[1];
@@ -190,7 +190,7 @@ $ADODB_INCLUDED_CSV = 1;
                                if ($meta[0] === '====1') {
                                        // slurp in the data
                                        $MAXSIZE = 128000;
-                                       
+
                                        $text = fread($fp,$MAXSIZE);
                                        if (strlen($text)) {
                                                while ($txt = fread($fp,$MAXSIZE)) {
@@ -206,7 +206,7 @@ $ADODB_INCLUDED_CSV = 1;
                                        }
                                        return $rs;
                                }
-                               
+
                                $meta = false;
                                $meta = fgetcsv($fp, 32000, ",");
                                if (!$meta) {
@@ -236,15 +236,15 @@ $ADODB_INCLUDED_CSV = 1;
                        $err = "Recordset had unexpected EOF 2";
                        return $false;
                }
-               
+
                // slurp in the data
                $MAXSIZE = 128000;
-               
+
                $text = '';
                while ($txt = fread($fp,$MAXSIZE)) {
                        $text .= $txt;
                }
-                       
+
                fclose($fp);
                @$arr = unserialize($text);
                //var_dump($arr);
@@ -258,18 +258,18 @@ $ADODB_INCLUDED_CSV = 1;
                $rs->InitArrayFields($arr,$flds);
                return $rs;
        }
-       
+
 
        /**
        * Save a file $filename and its $contents (normally for caching) with file locking
        * Returns true if ok, false if fopen/fwrite error, 0 if rename error (eg. file is locked)
        */
        function adodb_write_file($filename, $contents,$debug=false)
-       { 
+       {
        # http://www.php.net/bugs.php?id=9203 Bug that flock fails on Windows
        # So to simulate locking, we assume that rename is an atomic operation.
-       # First we delete $filename, then we create a $tempfile write to it and 
-       # rename to the desired $filename. If the rename works, then we successfully 
+       # First we delete $filename, then we create a $tempfile write to it and
+       # rename to the desired $filename. If the rename works, then we successfully
        # modified the file exclusively.
        # What a stupid need - having to simulate locking.
        # Risks:
@@ -279,14 +279,14 @@ $ADODB_INCLUDED_CSV = 1;
        # 4. another process creates $filename between unlink() and rename() -- ok, rename() fails and  cache updated
                if (strncmp(PHP_OS,'WIN',3) === 0) {
                        // skip the decimal place
-                       $mtime = substr(str_replace(' ','_',microtime()),2); 
+                       $mtime = substr(str_replace(' ','_',microtime()),2);
                        // getmypid() actually returns 0 on Win98 - never mind!
                        $tmpname = $filename.uniqid($mtime).getmypid();
                        if (!($fd = @fopen($tmpname,'w'))) return false;
                        if (fwrite($fd,$contents)) $ok = true;
                        else $ok = false;
                        fclose($fd);
-                       
+
                        if ($ok) {
                                @chmod($tmpname,0644);
                                // the tricky moment
@@ -312,7 +312,6 @@ $ADODB_INCLUDED_CSV = 1;
                        if ($debug)ADOConnection::outp( " Failed acquiring lock for $filename<br>\n");
                        $ok = false;
                }
-       
+
                return $ok;
        }
-?>
\ No newline at end of file
index 3820d7d..b8b881e 100644 (file)
@@ -1,15 +1,15 @@
 <?php
 
 /**
-  V5.18 3 Sep 2012   (c) 2000-2012 John Lim (jlim#natsoft.com). All rights reserved.
-  Released under both BSD license and Lesser GPL library license. 
-  Whenever there is any discrepancy between the two licenses, 
+  V5.19  23-Apr-2014  (c) 2000-2014 John Lim (jlim#natsoft.com). All rights reserved.
+  Released under both BSD license and Lesser GPL library license.
+  Whenever there is any discrepancy between the two licenses,
   the BSD license will take precedence.
-       
+
   Set tabs to 4 for best viewing.
+
        DOCUMENTATION:
-       
+
                See adodb/tests/test-datadict.php for docs and examples.
 */
 
@@ -42,13 +42,13 @@ if (!function_exists('ctype_alnum')) {
 /**
        Parse arguments, treat "text" (text) and 'text' as quotation marks.
        To escape, use "" or '' or ))
-       
+
        Will read in "abc def" sans quotes, as: abc def
        Same with 'abc def'.
        However if `abc def`, then will read in as `abc def`
-       
+
        @param endstmtchar    Character that indicates end of statement
-       @param tokenchars     Include the following characters in tokens apart from A-Z and 0-9 
+       @param tokenchars     Include the following characters in tokens apart from A-Z and 0-9
        @returns 2 dimensional array containing parsed tokens.
 */
 function Lens_ParseArgs($args,$endstmtchar=',',$tokenchars='_.-')
@@ -62,7 +62,7 @@ function Lens_ParseArgs($args,$endstmtchar=',',$tokenchars='_.-')
        $max = strlen($args);
        $quoted = false;
        $tokarr = array();
-       
+
        while ($pos < $max) {
                $ch = substr($args,$pos,1);
                switch($ch) {
@@ -77,17 +77,17 @@ function Lens_ParseArgs($args,$endstmtchar=',',$tokenchars='_.-')
                                }
                                break;
                        }
-                       
+
                        $tokarr[] = $ch;
                        break;
-               
+
                case '`':
                        if ($intoken) $tokarr[] = $ch;
                case '(':
-               case ')':       
+               case ')':
                case '"':
                case "'":
-                       
+
                        if ($intoken) {
                                if (empty($endquote)) {
                                        $tokens[$stmtno][] = implode('',$tokarr);
@@ -109,9 +109,9 @@ function Lens_ParseArgs($args,$endstmtchar=',',$tokenchars='_.-')
                                        }
                                } else
                                        $tokarr[] = $ch;
-                                       
+
                        }else {
-                       
+
                                if ($ch == '(') $endquote = ')';
                                else $endquote = $ch;
                                $quoted = true;
@@ -120,27 +120,27 @@ function Lens_ParseArgs($args,$endstmtchar=',',$tokenchars='_.-')
                                if ($ch == '`') $tokarr[] = '`';
                        }
                        break;
-                       
+
                default:
-                       
+
                        if (!$intoken) {
                                if ($ch == $endstmtchar) {
                                        $stmtno += 1;
                                        $tokens[$stmtno] = array();
                                        break;
                                }
-                       
+
                                $intoken = true;
                                $quoted = false;
                                $endquote = false;
                                $tokarr = array();
-       
+
                        }
-                       
+
                        if ($quoted) $tokarr[] = $ch;
                        else if (ctype_alnum($ch) || strpos($tokenchars,$ch) !== false) $tokarr[] = $ch;
                        else {
-                               if ($ch == $endstmtchar) {                      
+                               if ($ch == $endstmtchar) {
                                        $tokens[$stmtno][] = implode('',$tokarr);
                                        $stmtno += 1;
                                        $tokens[$stmtno] = array();
@@ -156,7 +156,7 @@ function Lens_ParseArgs($args,$endstmtchar=',',$tokenchars='_.-')
                $pos += 1;
        }
        if ($intoken) $tokens[$stmtno][] = implode('',$tokarr);
-       
+
        return $tokens;
 }
 
@@ -165,7 +165,7 @@ class ADODB_DataDict {
        var $connection;
        var $debug = false;
        var $dropTable = 'DROP TABLE %s';
-       var $renameTable = 'RENAME TABLE %s TO %s'; 
+       var $renameTable = 'RENAME TABLE %s TO %s';
        var $dropIndex = 'DROP INDEX %s';
        var $addCol = ' ADD';
        var $alterCol = ' ALTER COLUMN';
@@ -180,43 +180,43 @@ class ADODB_DataDict {
        var $invalidResizeTypes4 = array('CLOB','BLOB','TEXT','DATE','TIME'); // for changetablesql
        var $blobSize = 100;    /// any varchar/char field this size or greater is treated as a blob
                                                        /// in other words, we use a text area for editting.
-       
+
        function GetCommentSQL($table,$col)
        {
                return false;
        }
-       
+
        function SetCommentSQL($table,$col,$cmt)
        {
                return false;
        }
-       
+
        function MetaTables()
        {
                if (!$this->connection->IsConnected()) return array();
                return $this->connection->MetaTables();
        }
-       
+
        function MetaColumns($tab, $upper=true, $schema=false)
        {
                if (!$this->connection->IsConnected()) return array();
                return $this->connection->MetaColumns($this->TableName($tab), $upper, $schema);
        }
-       
+
        function MetaPrimaryKeys($tab,$owner=false,$intkey=false)
        {
                if (!$this->connection->IsConnected()) return array();
                return $this->connection->MetaPrimaryKeys($this->TableName($tab), $owner, $intkey);
        }
-       
+
        function MetaIndexes($table, $primary = false, $owner = false)
        {
                if (!$this->connection->IsConnected()) return array();
                return $this->connection->MetaIndexes($this->TableName($table), $primary, $owner);
        }
-       
+
        function MetaType($t,$len=-1,$fieldobj=false)
-       {               
+       {
                static $typeMap = array(
                'VARCHAR' => 'C',
                'VARCHAR2' => 'C',
@@ -263,7 +263,7 @@ class ADODB_DataDict {
                'TIMESTAMP WITHOUT TIME ZONE' => 'T', // postgresql
                ##
                'BOOL' => 'L',
-               'BOOLEAN' => 'L', 
+               'BOOLEAN' => 'L',
                'BIT' => 'L',
                'L' => 'L',
                ##
@@ -296,21 +296,21 @@ class ADODB_DataDict {
                'NUM' => 'N',
                'NUMERIC' => 'N',
                'MONEY' => 'N',
-               
+
                ## informix 9.2
-               'SQLINT' => 'I', 
-               'SQLSERIAL' => 'I', 
-               'SQLSMINT' => 'I', 
-               'SQLSMFLOAT' => 'N', 
-               'SQLFLOAT' => 'N', 
-               'SQLMONEY' => 'N', 
-               'SQLDECIMAL' => 'N', 
-               'SQLDATE' => 'D', 
-               'SQLVCHAR' => 'C', 
-               'SQLCHAR' => 'C', 
-               'SQLDTIME' => 'T', 
-               'SQLINTERVAL' => 'N', 
-               'SQLBYTES' => 'B', 
+               'SQLINT' => 'I',
+               'SQLSERIAL' => 'I',
+               'SQLSMINT' => 'I',
+               'SQLSMFLOAT' => 'N',
+               'SQLFLOAT' => 'N',
+               'SQLMONEY' => 'N',
+               'SQLDECIMAL' => 'N',
+               'SQLDATE' => 'D',
+               'SQLVCHAR' => 'C',
+               'SQLCHAR' => 'C',
+               'SQLDTIME' => 'T',
+               'SQLINTERVAL' => 'N',
+               'SQLBYTES' => 'B',
                'SQLTEXT' => 'X',
                 ## informix 10
                "SQLINT8" => 'I8',
@@ -320,7 +320,7 @@ class ADODB_DataDict {
                "SQLLVARCHAR" => 'X',
                "SQLBOOL" => 'L'
                );
-               
+
                if (!$this->connection->IsConnected()) {
                        $t = strtoupper($t);
                        if (isset($typeMap[$t])) return $typeMap[$t];
@@ -328,36 +328,36 @@ class ADODB_DataDict {
                }
                return $this->connection->MetaType($t,$len,$fieldobj);
        }
-       
+
        function NameQuote($name = NULL,$allowBrackets=false)
        {
                if (!is_string($name)) {
                        return FALSE;
                }
-               
+
                $name = trim($name);
-               
+
                if ( !is_object($this->connection) ) {
                        return $name;
                }
-               
+
                $quote = $this->connection->nameQuote;
-               
+
                // if name is of the form `name`, quote it
                if ( preg_match('/^`(.+)`$/', $name, $matches) ) {
                        return $quote . $matches[1] . $quote;
                }
-               
+
                // if name contains special characters, quote it
                $regex = ($allowBrackets) ? $this->nameRegexBrackets : $this->nameRegex;
-               
+
                if ( !preg_match('/^[' . $regex . ']+$/', $name) ) {
                        return $quote . $name . $quote;
                }
-               
+
                return $name;
        }
-       
+
        function TableName($name)
        {
                if ( $this->schema ) {
@@ -365,7 +365,7 @@ class ADODB_DataDict {
                }
                return $this->NameQuote($name);
        }
-       
+
        // Executes the sql array returned by GetTableSQL and GetIndexSQL
        function ExecuteSQLArray($sql, $continueOnError = true)
        {
@@ -373,7 +373,7 @@ class ADODB_DataDict {
                $conn = $this->connection;
                $saved = $conn->debug;
                foreach($sql as $line) {
-                       
+
                        if ($this->debug) $conn->debug = true;
                        $ok = $conn->Execute($line);
                        $conn->debug = $saved;
@@ -385,43 +385,43 @@ class ADODB_DataDict {
                }
                return $rez;
        }
-       
+
        /**
                Returns the actual type given a character code.
-               
+
                C:  varchar
                X:  CLOB (character large object) or largest varchar size if CLOB is not supported
                C2: Multibyte varchar
                X2: Multibyte CLOB
-               
+
                B:  BLOB (binary large object)
-               
+
                D:  Date
-               T:  Date-time 
+               T:  Date-time
                L:  Integer field suitable for storing booleans (0 or 1)
                I:  Integer
                F:  Floating point number
                N:  Numeric or decimal number
        */
-       
+
        function ActualType($meta)
        {
                return $meta;
        }
-       
+
        function CreateDatabase($dbname,$options=false)
        {
                $options = $this->_Options($options);
                $sql = array();
-               
+
                $s = 'CREATE DATABASE ' . $this->NameQuote($dbname);
                if (isset($options[$this->upperName]))
                        $s .= ' '.$options[$this->upperName];
-               
+
                $sql[] = $s;
                return $sql;
        }
-       
+
        /*
         Generates the SQL to create index. Returns an array of sql strings.
        */
@@ -430,25 +430,25 @@ class ADODB_DataDict {
                if (!is_array($flds)) {
                        $flds = explode(',',$flds);
                }
-               
+
                foreach($flds as $key => $fld) {
                        # some indexes can use partial fields, eg. index first 32 chars of "name" with NAME(32)
                        $flds[$key] = $this->NameQuote($fld,$allowBrackets=true);
                }
-               
+
                return $this->_IndexSQL($this->NameQuote($idxname), $this->TableName($tabname), $flds, $this->_Options($idxoptions));
        }
-       
+
        function DropIndexSQL ($idxname, $tabname = NULL)
        {
                return array(sprintf($this->dropIndex, $this->NameQuote($idxname), $this->TableName($tabname)));
        }
-       
+
        function SetSchema($schema)
        {
                $this->schema = $schema;
        }
-       
+
        function AddColumnSQL($tabname, $flds)
        {
                $tabname = $this->TableName ($tabname);
@@ -468,7 +468,7 @@ class ADODB_DataDict {
                }
                return $sql;
        }
-       
+
        /**
         * Change the definition of one column
         *
@@ -500,7 +500,7 @@ class ADODB_DataDict {
                }
                return $sql;
        }
-       
+
        /**
         * Rename one column
         *
@@ -523,7 +523,7 @@ class ADODB_DataDict {
                }
                return array(sprintf($this->renameColumn,$tabname,$this->NameQuote($oldcolumn),$this->NameQuote($newcolumn),$column_def));
        }
-               
+
        /**
         * Drop one column
         *
@@ -546,17 +546,17 @@ class ADODB_DataDict {
                }
                return $sql;
        }
-       
+
        function DropTableSQL($tabname)
        {
                return array (sprintf($this->dropTable, $this->TableName($tabname)));
        }
-       
+
        function RenameTableSQL($tabname,$newname)
        {
                return array (sprintf($this->renameTable, $this->TableName($tabname),$this->TableName($newname)));
-       }       
-       
+       }
+
        /**
         Generate the SQL to create table. Returns an array of sql strings.
        */
@@ -565,11 +565,11 @@ class ADODB_DataDict {
                list($lines,$pkey,$idxs) = $this->_GenFields($flds, true);
                // genfields can return FALSE at times
                if ($lines == null) $lines = array();
-               
+
                $taboptions = $this->_Options($tableoptions);
                $tabname = $this->TableName ($tabname);
                $sql = $this->_TableSQL($tabname,$lines,$pkey,$taboptions);
-               
+
                // ggiunta - 2006/10/12 - KLUDGE:
         // if we are on autoincrement, and table options includes REPLACE, the
         // autoincrement sequence has already been dropped on table creation sql, so
@@ -579,7 +579,7 @@ class ADODB_DataDict {
                unset($taboptions['REPLACE']);
                $tsql = $this->_Triggers($tabname,$taboptions);
                foreach($tsql as $s) $sql[] = $s;
-               
+
                if (is_array($idxs)) {
                        foreach($idxs as $idx => $idxdef) {
                                $sql_idxs = $this->CreateIndexSql($idx, $tabname,  $idxdef['cols'], $idxdef['opts']);
@@ -589,9 +589,9 @@ class ADODB_DataDict {
 
                return $sql;
        }
-               
-       
-       
+
+
+
        function _GenFields($flds,$widespacing=false)
        {
                if (is_string($flds)) {
@@ -608,7 +608,7 @@ class ADODB_DataDict {
                                                $f1['INDEX'] = '';
                                                // fall through intentionally
                                        case 'CONSTRAINT':
-                                       case 'DEFAULT': 
+                                       case 'DEFAULT':
                                                $hasparam = $token;
                                                break;
                                        default:
@@ -633,7 +633,7 @@ class ADODB_DataDict {
                                $hasparam = false;
 
                                $flds[] = $f1;
-                               
+
                        }
                }
                $this->autoIncrement = false;
@@ -642,7 +642,7 @@ class ADODB_DataDict {
                $idxs = array();
                foreach($flds as $fld) {
                        $fld = _array_change_key_case($fld);
-                       
+
                        $fname = false;
                        $fdefault = false;
                        $fautoinc = false;
@@ -658,20 +658,20 @@ class ADODB_DataDict {
                        $funsigned = false;
                        $findex = '';
                        $funiqueindex = false;
-                       
+
                        //-----------------
                        // Parse attributes
                        foreach($fld as $attr => $v) {
                                if ($attr == 2 && is_numeric($v)) $attr = 'SIZE';
                                else if (is_numeric($attr) && $attr > 1 && !is_numeric($v)) $attr = strtoupper($v);
-                               
+
                                switch($attr) {
                                case '0':
                                case 'NAME':    $fname = $v; break;
                                case '1':
                                case 'TYPE':    $ty = $v; $ftype = $this->ActualType(strtoupper($v)); break;
-                               
-                               case 'SIZE':    
+
+                               case 'SIZE':
                                                                $dotat = strpos($v,'.'); if ($dotat === false) $dotat = strpos($v,',');
                                                                if ($dotat === false) $fsize = $v;
                                                                else {
@@ -697,33 +697,33 @@ class ADODB_DataDict {
                                case 'UNIQUE': $funiqueindex = true; break;
                                } //switch
                        } // foreach $fld
-                       
+
                        //--------------------
                        // VALIDATE FIELD INFO
                        if (!strlen($fname)) {
                                if ($this->debug) ADOConnection::outp("Undefined NAME");
                                return false;
                        }
-                       
+
                        $fid = strtoupper(preg_replace('/^`(.+)`$/', '$1', $fname));
                        $fname = $this->NameQuote($fname);
-                       
+
                        if (!strlen($ftype)) {
                                if ($this->debug) ADOConnection::outp("Undefined TYPE for field '$fname'");
                                return false;
                        } else {
                                $ftype = strtoupper($ftype);
                        }
-                       
+
                        $ftype = $this->_GetSize($ftype, $ty, $fsize, $fprec);
-                       
+
                        if ($ty == 'X' || $ty == 'X2' || $ty == 'B') $fnotnull = false; // some blob types do not accept nulls
-                       
+
                        if ($fprimary) $pkey[] = $fname;
-                       
+
                        // some databases do not allow blobs to have defaults
                        if ($ty == 'X') $fdefault = false;
-                       
+
                        // build list of indexes
                        if ($findex != '') {
                                if (array_key_exists($findex, $idxs)) {
@@ -760,7 +760,7 @@ class ADODB_DataDict {
                                        $fdefault = $this->connection->sysDate;
                                }
                        } else if ($fdefault !== false && !$fnoquote) {
-                               if ($ty == 'C' or $ty == 'X' or 
+                               if ($ty == 'C' or $ty == 'X' or
                                        ( substr($fdefault,0,1) != "'" && !is_numeric($fdefault))) {
 
                                        if (($ty == 'D' || $ty == 'T') && strtolower($fdefault) != 'null') {
@@ -775,27 +775,27 @@ class ADODB_DataDict {
                                                }
                                        }
                                        else
-                                       if (strlen($fdefault) != 1 && substr($fdefault,0,1) == ' ' && substr($fdefault,strlen($fdefault)-1) == ' ') 
+                                       if (strlen($fdefault) != 1 && substr($fdefault,0,1) == ' ' && substr($fdefault,strlen($fdefault)-1) == ' ')
                                                $fdefault = trim($fdefault);
                                        else if (strtolower($fdefault) != 'null')
                                                $fdefault = $this->connection->qstr($fdefault);
                                }
                        }
                        $suffix = $this->_CreateSuffix($fname,$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint,$funsigned);
-                       
+
                        // add index creation
                        if ($widespacing) $fname = str_pad($fname,24);
-                       
+
                         // check for field names appearing twice
             if (array_key_exists($fid, $lines)) {
                 ADOConnection::outp("Field '$fname' defined twice");
             }
-                       
+
                        $lines[$fid] = $fname.' '.$ftype.$suffix;
-                       
+
                        if ($fautoinc) $this->autoIncrement = true;
                } // foreach $flds
-               
+
                return array($lines,$pkey,$idxs);
        }
 
@@ -813,56 +813,56 @@ class ADODB_DataDict {
                }
                return $ftype;
        }
-       
-       
+
+
        // return string must begin with space
        function _CreateSuffix($fname,&$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint,$funsigned)
-       {       
+       {
                $suffix = '';
                if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault";
                if ($fnotnull) $suffix .= ' NOT NULL';
                if ($fconstraint) $suffix .= ' '.$fconstraint;
                return $suffix;
        }
-       
+
        function _IndexSQL($idxname, $tabname, $flds, $idxoptions)
        {
                $sql = array();
-               
+
                if ( isset($idxoptions['REPLACE']) || isset($idxoptions['DROP']) ) {
                        $sql[] = sprintf ($this->dropIndex, $idxname);
                        if ( isset($idxoptions['DROP']) )
                                return $sql;
                }
-               
+
                if ( empty ($flds) ) {
                        return $sql;
                }
-               
+
                $unique = isset($idxoptions['UNIQUE']) ? ' UNIQUE' : '';
-       
+
                $s = 'CREATE' . $unique . ' INDEX ' . $idxname . ' ON ' . $tabname . ' ';
-               
+
                if ( isset($idxoptions[$this->upperName]) )
                        $s .= $idxoptions[$this->upperName];
-               
+
                if ( is_array($flds) )
                        $flds = implode(', ',$flds);
                $s .= '(' . $flds . ')';
                $sql[] = $s;
-               
+
                return $sql;
        }
-       
+
        function _DropAutoIncrement($tabname)
        {
                return false;
        }
-       
+
        function _TableSQL($tabname,$lines,$pkey,$tableoptions)
        {
                $sql = array();
-               
+
                if (isset($tableoptions['REPLACE']) || isset ($tableoptions['DROP'])) {
                        $sql[] = sprintf($this->dropTable,$tabname);
                        if ($this->autoIncrement) {
@@ -879,19 +879,19 @@ class ADODB_DataDict {
                        $s .= ",\n                 PRIMARY KEY (";
                        $s .= implode(", ",$pkey).")";
                }
-               if (isset($tableoptions['CONSTRAINTS'])) 
+               if (isset($tableoptions['CONSTRAINTS']))
                        $s .= "\n".$tableoptions['CONSTRAINTS'];
-               
-               if (isset($tableoptions[$this->upperName.'_CONSTRAINTS'])) 
+
+               if (isset($tableoptions[$this->upperName.'_CONSTRAINTS']))
                        $s .= "\n".$tableoptions[$this->upperName.'_CONSTRAINTS'];
-               
+
                $s .= "\n)";
                if (isset($tableoptions[$this->upperName])) $s .= $tableoptions[$this->upperName];
                $sql[] = $s;
-               
+
                return $sql;
        }
-       
+
        /**
                GENERATE TRIGGERS IF NEEDED
                used when table has auto-incrementing field that is emulated using triggers
@@ -900,7 +900,7 @@ class ADODB_DataDict {
        {
                return array();
        }
-       
+
        /**
                Sanitize options, so that array elements with no keys are promoted to keys
        */
@@ -914,8 +914,8 @@ class ADODB_DataDict {
                }
                return $newopts;
        }
-       
-       
+
+
        function _getSizePrec($size)
        {
                $fsize = false;
@@ -929,34 +929,34 @@ class ADODB_DataDict {
                }
                return array($fsize, $fprec);
        }
-       
+
        /**
        "Florian Buzin [ easywe ]" <florian.buzin#easywe.de>
-       
+
        This function changes/adds new fields to your table. You don't
        have to know if the col is new or not. It will check on its own.
        */
        function ChangeTableSQL($tablename, $flds, $tableoptions = false, $dropOldFlds=false)
        {
        global $ADODB_FETCH_MODE;
-       
+
                $save = $ADODB_FETCH_MODE;
                $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
                if ($this->connection->fetchMode !== false) $savem = $this->connection->SetFetchMode(false);
-               
+
                // check table exists
                $save_handler = $this->connection->raiseErrorFn;
                $this->connection->raiseErrorFn = '';
                $cols = $this->MetaColumns($tablename);
                $this->connection->raiseErrorFn = $save_handler;
-               
+
                if (isset($savem)) $this->connection->SetFetchMode($savem);
                $ADODB_FETCH_MODE = $save;
-               
-               if ( empty($cols)) { 
+
+               if ( empty($cols)) {
                        return $this->CreateTableSQL($tablename, $flds, $tableoptions);
                }
-               
+
                if (is_array($flds)) {
                // Cycle through the update fields, comparing
                // existing fields to fields to update.
@@ -969,16 +969,16 @@ class ADODB_DataDict {
                                        $obj = $cols[$k];
                                        if (isset($obj->not_null) && $obj->not_null)
                                                $v = str_replace('NOT NULL','',$v);
-                                       if (isset($obj->auto_increment) && $obj->auto_increment && empty($v['AUTOINCREMENT'])) 
+                                       if (isset($obj->auto_increment) && $obj->auto_increment && empty($v['AUTOINCREMENT']))
                                            $v = str_replace('AUTOINCREMENT','',$v);
-                                       
+
                                        $c = $cols[$k];
                                        $ml = $c->max_length;
                                        $mt = $this->MetaType($c->type,$ml);
-                                       
+
                                        if (isset($c->scale)) $sc = $c->scale;
                                        else $sc = 99; // always force change if scale not known.
-                                       
+
                                        if ($sc == -1) $sc = false;
                                        list($fsize, $fprec) = $this->_getSizePrec($v['SIZE']);
 
@@ -989,11 +989,11 @@ class ADODB_DataDict {
                                        }
                                } else {
                                        $holdflds[$k] = $v;
-                               }               
+                               }
                        }
                        $flds = $holdflds;
                }
-       
+
 
                // already exists, alter table instead
                list($lines,$pkey,$idxs) = $this->_GenFields($flds);
@@ -1004,29 +1004,28 @@ class ADODB_DataDict {
 
                foreach ( $lines as $id => $v ) {
                        if ( isset($cols[$id]) && is_object($cols[$id]) ) {
-                       
+
                                $flds = Lens_ParseArgs($v,',');
-                               
+
                                //  We are trying to change the size of the field, if not allowed, simply ignore the request.
                                // $flds[1] holds the type, $flds[2] holds the size -postnuke addition
                                if ($flds && in_array(strtoupper(substr($flds[0][1],0,4)),$this->invalidResizeTypes4)
                                 && (isset($flds[0][2]) && is_numeric($flds[0][2]))) {
                                        if ($this->debug) ADOConnection::outp(sprintf("<h3>%s cannot be changed to %s currently</h3>", $flds[0][0], $flds[0][1]));
                                        #echo "<h3>$this->alterCol cannot be changed to $flds currently</h3>";
-                                       continue;        
+                                       continue;
                                }
                                $sql[] = $alter . $this->alterCol . ' ' . $v;
                        } else {
                                $sql[] = $alter . $this->addCol . ' ' . $v;
                        }
                }
-               
+
                if ($dropOldFlds) {
                        foreach ( $cols as $id => $v )
-                           if ( !isset($lines[$id]) ) 
+                           if ( !isset($lines[$id]) )
                                        $sql[] = $alter . $this->dropCol . ' ' . $v->name;
                }
                return $sql;
        }
 } // class
-?>
\ No newline at end of file
index 67c16d6..29c6a9c 100644 (file)
@@ -1,12 +1,12 @@
 <?php
-/** 
- * @version V5.18 3 Sep 2012  (c) 2000-2012 John Lim (jlim#natsoft.com). All rights reserved.
- * Released under both BSD license and Lesser GPL library license. 
- * Whenever there is any discrepancy between the two licenses, 
- * the BSD license will take precedence. 
+/**
+ * @version V5.19  23-Apr-2014  (c) 2000-2014 John Lim (jlim#natsoft.com). All rights reserved.
+ * Released under both BSD license and Lesser GPL library license.
+ * Whenever there is any discrepancy between the two licenses,
+ * the BSD license will take precedence.
  *
  * Set tabs to 4 for best viewing.
- * 
+ *
  * The following code is adapted from the PEAR DB error handling code.
  * Portions (c)1997-2002 The PHP Group.
  */
@@ -62,27 +62,27 @@ function adodb_error($provider,$dbType,$errno)
 {
        //var_dump($errno);
        if (is_numeric($errno) && $errno == 0) return 0;
-       switch($provider) { 
+       switch($provider) {
        case 'mysql': $map = adodb_error_mysql(); break;
-       
+
        case 'oracle':
        case 'oci8': $map = adodb_error_oci8(); break;
-       
+
        case 'ibase': $map = adodb_error_ibase(); break;
-       
+
        case 'odbc': $map = adodb_error_odbc(); break;
-       
+
        case 'mssql':
        case 'sybase': $map = adodb_error_mssql(); break;
-       
+
        case 'informix': $map = adodb_error_ifx(); break;
-       
+
        case 'postgres': return adodb_error_pg($errno); break;
-       
+
        case 'sqlite': return $map = adodb_error_sqlite(); break;
        default:
                return DB_ERROR;
-       }       
+       }
        //print_r($map);
        //var_dump($errno);
        if (isset($map[$errno])) return $map[$errno];
@@ -95,29 +95,29 @@ function adodb_error_pg($errormsg)
 {
        if (is_numeric($errormsg)) return (integer) $errormsg;
        // Postgres has no lock-wait timeout.  The best we could do would be to set a statement timeout.
-    static $error_regexps = array(
-            '/(Table does not exist\.|Relation [\"\'].*[\"\'] does not exist|sequence does not exist|class ".+" not found)$/i' => DB_ERROR_NOSUCHTABLE,
-            '/Relation [\"\'].*[\"\'] already exists|Cannot insert a duplicate key into (a )?unique index.*|duplicate key.*violates unique constraint/i'     => DB_ERROR_ALREADY_EXISTS,
-            '/database ".+" does not exist$/i'       => DB_ERROR_NOSUCHDB,
-            '/(divide|division) by zero$/i'          => DB_ERROR_DIVZERO,
-            '/pg_atoi: error in .*: can\'t parse /i' => DB_ERROR_INVALID_NUMBER,
-            '/ttribute [\"\'].*[\"\'] not found|Relation [\"\'].*[\"\'] does not have attribute [\"\'].*[\"\']/i' => DB_ERROR_NOSUCHFIELD,
-            '/(parser: parse|syntax) error at or near \"/i'   => DB_ERROR_SYNTAX,
-            '/referential integrity violation/i'     => DB_ERROR_CONSTRAINT,
-            '/deadlock detected$/i'                  => DB_ERROR_DEADLOCK,
-            '/canceling statement due to statement timeout$/i' => DB_ERROR_STATEMENT_TIMEOUT,
-            '/could not serialize access due to/i'   => DB_ERROR_SERIALIZATION_FAILURE
-        );
+       static $error_regexps = array(
+                       '(Table does not exist\.|Relation [\"\'].*[\"\'] does not exist|sequence does not exist|class ".+" not found)$' => DB_ERROR_NOSUCHTABLE,
+                       'Relation [\"\'].*[\"\'] already exists|Cannot insert a duplicate key into (a )?unique index.*|duplicate key.*violates unique constraint'     => DB_ERROR_ALREADY_EXISTS,
+                       'database ".+" does not exist$'       => DB_ERROR_NOSUCHDB,
+                       '(divide|division) by zero$'          => DB_ERROR_DIVZERO,
+                       'pg_atoi: error in .*: can\'t parse ' => DB_ERROR_INVALID_NUMBER,
+                       'ttribute [\"\'].*[\"\'] not found|Relation [\"\'].*[\"\'] does not have attribute [\"\'].*[\"\']' => DB_ERROR_NOSUCHFIELD,
+                       '(parser: parse|syntax) error at or near \"'   => DB_ERROR_SYNTAX,
+                       'referential integrity violation'     => DB_ERROR_CONSTRAINT,
+                       'deadlock detected$'                  => DB_ERROR_DEADLOCK,
+                       'canceling statement due to statement timeout$' => DB_ERROR_STATEMENT_TIMEOUT,
+                       'could not serialize access due to'   => DB_ERROR_SERIALIZATION_FAILURE
+               );
        reset($error_regexps);
-    while (list($regexp,$code) = each($error_regexps)) {
-        if (preg_match($regexp, $errormsg)) {
-            return $code;
-        }
-    }
-    // Fall back to DB_ERROR if there was no mapping.
-    return DB_ERROR;
+       while (list($regexp,$code) = each($error_regexps)) {
+               if (preg_match("/$regexp/mi", $errormsg)) {
+                       return $code;
+               }
+       }
+       // Fall back to DB_ERROR if there was no mapping.
+       return DB_ERROR;
 }
-       
+
 function adodb_error_odbc()
 {
 static $MAP = array(
@@ -175,7 +175,7 @@ static $MAP = array(
             -923 => DB_ERROR_CONNECT_FAILED,
             -924 => DB_ERROR_CONNECT_FAILED
         );
-               
+
                return $MAP;
 }
 
@@ -193,7 +193,7 @@ static $MAP = array(
             '-1210'   => DB_ERROR_INVALID_DATE,
             '-1212'   => DB_ERROR_INVALID_DATE
        );
-          
+
           return $MAP;
 }
 
@@ -212,7 +212,7 @@ static $MAP = array(
             2291 => DB_ERROR_CONSTRAINT,
             2449 => DB_ERROR_CONSTRAINT
         );
-          
+
        return $MAP;
 }
 
@@ -222,7 +222,7 @@ static $MAP = array(
                  208 => DB_ERROR_NOSUCHTABLE,
           2601 => DB_ERROR_ALREADY_EXISTS
        );
-          
+
        return $MAP;
 }
 
@@ -231,7 +231,7 @@ function adodb_error_sqlite()
 static $MAP = array(
                  1 => DB_ERROR_SYNTAX
        );
-          
+
        return $MAP;
 }
 
@@ -258,7 +258,6 @@ static $MAP = array(
                    2002 => DB_ERROR_CONNECT_FAILED,
                        2005 => DB_ERROR_CONNECT_FAILED
        );
-          
+
        return $MAP;
 }
-?>
\ No newline at end of file
index 7099f03..680e76d 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /**
- * @version V5.18 3 Sep 2012   (c) 2000-2012 John Lim (jlim#natsoft.com). All rights reserved.
+ * @version V5.19  23-Apr-2014  (c) 2000-2014 John Lim (jlim#natsoft.com). All rights reserved.
  * Released under both BSD license and Lesser GPL library license.
  * Whenever there is any discrepancy between the two licenses,
  * the BSD license will take precedence.
@@ -13,7 +13,7 @@
 
 
 // added Claudio Bustos  clbustos#entelchile.net
-if (!defined('ADODB_ERROR_HANDLER_TYPE')) define('ADODB_ERROR_HANDLER_TYPE',E_USER_ERROR); 
+if (!defined('ADODB_ERROR_HANDLER_TYPE')) define('ADODB_ERROR_HANDLER_TYPE',E_USER_ERROR);
 
 if (!defined('ADODB_ERROR_HANDLER')) define('ADODB_ERROR_HANDLER','ADODB_Error_Handler');
 
@@ -74,6 +74,5 @@ function ADODB_Error_Handler($dbms, $fn, $errno, $errmsg, $p1, $p2, &$thisConnec
 
 
        //print "<p>$s</p>";
-       trigger_error($s,ADODB_ERROR_HANDLER_TYPE); 
+       trigger_error($s,ADODB_ERROR_HANDLER_TYPE);
 }
-?>
index 8340a84..10dbb97 100644 (file)
@@ -1,14 +1,14 @@
 <?php
-/** 
- * @version V5.18 3 Sep 2012  (c) 2000-2012 John Lim (jlim#natsoft.com). All rights reserved.
- * Released under both BSD license and Lesser GPL library license. 
-  Whenever there is any discrepancy between the two licenses, 
-  the BSD license will take precedence. 
+/**
+ * @version V5.19  23-Apr-2014  (c) 2000-2014 John Lim (jlim#natsoft.com). All rights reserved.
+ * Released under both BSD license and Lesser GPL library license.
+  Whenever there is any discrepancy between the two licenses,
+  the BSD license will take precedence.
  *
  * Set tabs to 4 for best viewing.
- * 
+ *
  * Latest version is available at http://php.weblogs.com
- * 
+ *
 */
 include_once('PEAR.php');
 
@@ -34,7 +34,7 @@ global $ADODB_Last_PEAR_Error; $ADODB_Last_PEAR_Error = false;
 *
 * @param $dbms         the RDBMS you are connecting to
 * @param $fn           the name of the calling function (in uppercase)
-* @param $errno                the native error number from the database 
+* @param $errno                the native error number from the database
 * @param $errmsg       the native error msg from the database
 * @param $p1           $fn specific parameter - see below
 * @param $P2  &nb