'None', acHIGHLIGHT => 'Highlight', acUNHIGHLIGHT => 'Hide highlight', acSHOWINFO => 'Show info', acSHOWINFODELAY => 'Show info delayed', acHIDEINFO => 'Hide metatdata', acSHOWOBJECT => 'Show Object', acSHOWBLOWUP => 'Show enlargement', acSELECT => 'Select', acLINK => 'Link', // acPOPUP => 'Popup', acREVEAL => 'Reveal', acUNREVEAL => 'Hide reveal', acCUSTOM => 'Custom'); private $trigger_codes = array(atNONE => 'None', atMOUSEOVER => 'Mouse over', atMOUSEOUT => 'Mouse out', atMOUSECLICK => 'Mouse click'); //----------------------------------------------------------------------------------------------- // Constructor: Set defaults, load the list. // We are passed the ID of the Object the list belongs to. public function __construct($owner_id, $owner_type, $owner_link) { $this->owner = $owner_link; $this->owner_id = $owner_id; $this->owner_type = $owner_type; if (($owner_id > 0) && ($owner_type != aotNONE) && !empty($owner_link)) $this->load_actions(); $this->clear_errors(); } //----------------------------------------------------------------------------------------------- // Clear the error status. public function clear_errors() { $this->errors = array(); $this->fatal_error = false; } //----------------------------------------------------------------------------------------------- // Load the list of actions for the Object. public function load_actions() { $this->clear_errors(); $this->actions = array(); // Get the Collection depending on the type of the // owner of our list. $collection = null; if ($this->owner_type == aotOBJECT) $collection = $this->owner->artifact->collection; elseif ($this->owner_type == aotARTIFACT) $collection = $this->owner->collection; if (!empty($collection)) { $db = $collection->dbobj; $prefix = $collection->prefix; // Get the action records. $this->actions = $db->action_get_list($this->owner_id, $this->owner_type, $prefix); if ($db->last_error_status != dbsSUCCESS) { $this->fatal_error = true; $this->errors[] = $db->last_error_msg; } } return !$this->fatal_error; } //----------------------------------------------------------------------------------------------- // Parse the action list XML into our properties. public function load_actionlist_xml($xml) { $this->actions = $this->parse_actionlist_xml($xml); } //----------------------------------------------------------------------------------------------- // Save the action list to the database. public function save_action_list() { $had_error = false; // Get the Collection depending on the type of the // owner of our list. $collection = null; if ($this->owner_type == aotOBJECT) $collection = $this->owner->artifact->collection; elseif ($this->owner_type == aotARTIFACT) $collection = $this->owner->collection; if (!empty($collection)) { $db = $collection->dbobj; $prefix = $collection->prefix; // Delete the old action records, if any. $db->action_delete_list($this->owner_id, $this->owner_type, $prefix); // Add the new records. foreach ($this->actions as $action) { if (!$db->action_insert($this->owner_id, $this->owner_type, $action, $prefix)) { $had_error = true; $this->errors[] = $db->last_error_msg; } } // Reload to get the new action list IDs. $this->load_actions(); } return !$had_error; } //----------------------------------------------------------------------------------------------- // Build the HTML for a '; foreach ($this->action_codes as $code => $title) $select .= ''; $select .= ''; return $select; } //----------------------------------------------------------------------------------------------- // Build the HTML for a '; foreach ($this->trigger_codes as $code => $title) $select .= ''; $select .= ''; return $select; } //----------------------------------------------------------------------------------------------- // Create an XML packet from our action list. // This is used by the cls-actionlist.js module. public function make_xml_packet() { if (empty($this->actions)) $list_xml = $this->make_default_xml_packet(); else { $list_xml = ''; foreach ($this->actions as $action) $list_xml .= '' . '' . $action['id'] . '' . '' . $action['action_seq'] . '' . '' . $action['trigger_code'] . '' . '' . $action['action_code'] . '' . '' . $action['hilite_color'] . '' . '' . $action['hilite_width'] . '' . '' . $action['select_color'] . '' . '' . $action['select_width'] . '' . '' . $action['custom_function'] . '' . ''; $list_xml .= ''; } return $list_xml; } //----------------------------------------------------------------------------------------------- // Create the XML packet for the default set of actions. public function make_default_xml_packet() { $list_xml = '' . '' . '800001' . '1' . '' . atMOUSEOVER . '' . '' . acHIGHLIGHT . '' . '#00ff00' . '1' . '#ff0000' . '2' . '' . '' . '' . '800002' . '2' . '' . atMOUSEOUT . '' . '' . acUNHIGHLIGHT . '' . '#00ff00' . '1' . '#ff0000' . '2' . '' . '' . '' . '800003' . '3' . '' . atMOUSECLICK . '' . '' . acSHOWINFO . '' . '#00ff00' . '1' . '#ff0000' . '2' . '' . '' . ''; return $list_xml; } //----------------------------------------------------------------------------------------------- // Format our action for display. public function make_actionlist_display($table_css) { $display = 'None'; if (!empty($this->actions)) { $display = '' . '' . '' . '' . '' . '' . '' . ''; foreach ($this->actions as $action) { $display .= '' . '' . '' . '' . '' . '' . ''; } $display .= '
TriggerActionHilite Color/WidthSelect Color/WidthCustom Function/Link
' . $this->trigger_codes[$action['trigger_code']] . '' . $this->action_codes[$action['action_code']] . '' . $action['hilite_color'] . ' / ' . $action['hilite_width'] . ' pixel' . $action['select_color'] . ' / ' . $action['select_width'] . ' pixel' . $action['custom_function'] . '
'; } return $display; } //----------------------------------------------------------------------------------------------- // Parse an action list XML packet, // put the data in our properties. public function parse_actionlist_xml($xml) { $actions = array(); $xmldoc = new DOMDocument(); $xmldoc->preserveWhiteSpace = false; $xml_errors = load_xml_string($xmldoc, $xml); if (!empty($xml_errors)) { $this->fatal_error = true; $this->errors[] = 'The action list XML is not well formed: '; foreach ($xml_errors as $error) $this->errors[] = "  $error"; return false; } $xmldoc->normalize(); $xpath = new DOMXPath($xmldoc); $action_count = $xmldoc->getElementsByTagName('action')->length; for ($i = 1; $i <= $action_count; $i++) { $root = "//actionlist/action[$i]"; $actions[] = array('action_seq' => get_xml_value($xpath, "$root/sequence"), 'trigger_code' => get_xml_value($xpath, "$root/trigger-code"), 'action_code' => get_xml_value($xpath, "$root/action-code"), 'hilite_color' => get_xml_value($xpath, "$root/hilite-color"), 'hilite_width' => get_xml_value($xpath, "$root/hilite-width"), 'select_color' => get_xml_value($xpath, "$root/select-color"), 'select_width' => get_xml_value($xpath, "$root/select-width"), 'custom_function' => get_xml_value($xpath, "$root/custom-function"), 'owner_id' => $this->owner_id, 'owner_type' => $this->owner_type); } return $actions; } } ?>db = null; $this->db_connect_str = ''; $this->last_id = -1; $this->clear_error(); $this->tsearch_parser = new TSearchParser('metadata'); $this->tsearch_parser->b_default_and = true; } //----------------------------------------------------------------------------------------------- // Clear error status. function clear_error() { $this->last_error_status = dbsSUCCESS; $this->last_error_code = ''; $this->last_error_msg = ''; } //----------------------------------------------------------------------------------------------- // Set an error status. $status and $code will be one of the // dbsXXXX and dbeXXXX codes defined above. function set_error($status, $code, $msg) { $this->last_error_status = $status; $this->last_error_code = $code; $this->last_error_msg = $msg; } //----------------------------------------------------------------------------------------------- // Connect to a PostgreSQL database. // If we have an existing and valid database connection, use it, // otherwise connect now. public function db_connect($connect_str) { $this->clear_error(); $had_error = false; if (empty($connect_str)) { $had_error = true; $this->set_error(dbsERROR, dbeCONNECT_FAILED, 'Invalid connection parameters.'); } else { if (($connect_str != $this->db_connect_str) || (!isset($this->db)) || (pg_connection_status($this->db) != PGSQL_CONNECTION_OK)) { if (isset($this->db) && (pg_connection_status($this->db) == PGSQL_CONNECTION_OK)) @pg_close($this->db); if (!$this->db = @pg_connect($connect_str)) { $had_error = true; $this->set_error(dbsERROR, dbeCONNECT_FAILED, 'Could not connect to the database server.'); } } } return !$had_error; } //----------------------------------------------------------------------------------------------- // Close the database connection. public function db_close() { $this->clear_error(); if (($this->db != null) && (pg_connection_status($this->db) == PGSQL_CONNECTION_OK)) pg_close($this->db); $this->db = null; } //----------------------------------------------------------------------------------------------- // Execute an arbitrary DDL SQL statement, handle errors. // No result set is returned since this is not a SELECT query. // We assume the error status properties have already been // cleared by our caller if required. public function exec_ddl($sql) { if (!empty($sql)) { $result = @pg_query($this->db, $sql); if (!$result) $this->set_error(dbsERROR, dbeGENERAL_FAILURE, pg_last_error($this->db)); if ($result) pg_free_result($result); } return ($this->last_error_status == dbsSUCCESS); } //----------------------------------------------------------------------------------------------- // Execute an arbitrary non-SELECT SQL statement, handle errors. // Normally no result set is returned since this is not a SELECT query, // but if $return_id is true, the query is expected to return the id of the // newly inserted record as $row['new_id']. This is done via a RULE in PostgreSQL. // We will just save the ID in our $last_id property. // We assume the error status properties have already been // cleared by our caller if required. A warning status is // set if no rows are affected by the query. public function exec_sql($sql, $return_id) { // print "

sql=[$sql]

"; if (!empty($sql)) { $this->last_sql = $sql; $this->last_id = -1; $result = @pg_query($this->db, $sql); if (!$result) $this->set_error(dbsERROR, dbeGENERAL_FAILURE, pg_last_error($this->db)); else { if ($return_id) { $row = pg_fetch_assoc($result); if (isset($row['new_id'])) $this->last_id = $row['new_id']; } $this->last_affected_rows = pg_affected_rows($result); if ($this->last_affected_rows < 1) $this->set_error(dbsWARNING, dbeNO_ROWS_AFFECTED, 'Warning: No rows affected by database transaction.'); } if ($result) pg_free_result($result); } return ($this->last_error_status == dbsSUCCESS); } //----------------------------------------------------------------------------------------------- // Execute an arbitrary SELECT SQL statement, handle errors. // The result set is returned; the caller is responsible for // freeing it. We assume the error status properties have already // been cleared by our caller if required. An error will cause us // to return a false result. public function exec_query($sql) { $result = false; if (!empty($sql)) { $this->last_sql = $sql; $result = @pg_query($this->db, $sql); if (!$result) $this->set_error(dbsERROR, dbeGENERAL_FAILURE, pg_last_error($this->db)); } return $result; } //----------------------------------------------------------------------------------------------- // See if the Collection tables exist. function collection_tables_exist($prefix) { $exists = false; $sql = "SELECT tablename FROM \"pg_tables\" " . "WHERE (schemaname='public') and " . "((tablename = '" . $prefix . "_action') or " . "(tablename = '" . $prefix . "_artifact') or " . "(tablename = '" . $prefix . "_category') or " . "(tablename = '" . $prefix . "_object') or " . "(tablename = '" . $prefix . "_schema'))"; if ($result = $this->exec_query($sql)) { $exists = (pg_num_rows($result) == 5); pg_free_result($result); } else { $this->set_error(dbsERROR, dbeGENERAL_FAILURE, pg_last_error($this->db)); $exists = false; } return $exists; } //----------------------------------------------------------------------------------------------- // Create the tables required for a Collection. The tables have standard names, // prefixed with the supplied three character string. We will attempt to create // them all in one transaction so they all succeed or fail together. public function make_collection_tables($prefix) { // Artifact table $sql = 'CREATE TABLE ' . $prefix . '_artifact (' . 'id serial NOT NULL,' . 'collection_name character varying(60),' . 'artifact_prefix character varying(5),' . 'artifact_name character varying(50),' . 'artifact_title character varying(150),' . 'artifact_description text,' . 'schema_id integer,' . 'xslt_id integer,' . 'metadata text,' . 'image_type character varying(3),' . 'image_sizes character varying(60),' . 'artifact_owner character varying(30),' . 'artifact_permissions text,' . 'sequence_source character varying(150),' . 'thumb_size character varying(10),' . 'viewer_title character varying(100),' . 'viewer_logo_image character varying(40),' . 'CONSTRAINT ' . $prefix . '_artifact_pkey PRIMARY KEY (id) ) ' . 'WITH OIDS;' . "\n"; // Artifact table rule to retrieve the ID value after an insert. $sql .= 'CREATE RULE get_pkey_on_insert ' . 'AS ON INSERT TO ' . $prefix . '_artifact ' . "DO SELECT currval('" . $prefix . "_artifact_id_seq') AS new_id;\n"; // Object table $sql .= 'CREATE TABLE ' . $prefix . '_object (' . 'id serial NOT NULL,' . 'parent_id integer,' . 'artifact_id integer,' . 'object_type smallint,' . 'object_level smallint,' . 'object_seq integer DEFAULT 0,' . 'category_id integer,' . 'imt_id character varying(50),' . 'object_title character varying(255),' . 'metadata text,' . 'image_name character varying(150),' . 'image_width integer,' . 'image_height integer,' . 'reveal_image_name character varying(150),' . 'rect_top smallint,' . 'rect_left smallint,' . 'rect_width smallint,' . 'rect_height smallint,' . 'zindex smallint,' . 'meta_vector tsvector,' . 'CONSTRAINT ' . $prefix . '_object_pkey PRIMARY KEY (id) ) ' . 'WITH OIDS;' . "\n"; // Index on Object table TSearch vector field. $sql .= 'CREATE INDEX ' . $prefix . '_object_meta_vector_idx ON ' . $prefix . '_object USING gist(meta_vector);'; // Trigger to update Object table TSearch vector field on update or insert. $sql .= 'CREATE TRIGGER ' . $prefix . '_tsvectorupdate BEFORE UPDATE OR INSERT ON ' . $prefix . '_object ' . 'FOR EACH ROW EXECUTE PROCEDURE tsearch2(meta_vector, metadata);'; // Object table rule to retrieve the ID value after an insert. $sql .= 'CREATE RULE get_pkey_on_insert ' . 'AS ON INSERT TO ' . $prefix . '_object ' . "DO SELECT currval('" . $prefix . "_object_id_seq') AS new_id;\n"; // Action table. $sql .= 'CREATE TABLE ' . $prefix . '_action (' . 'id serial NOT NULL,' . 'owner_id integer,' . 'owner_type smallint,' . 'action_code smallint,' . 'trigger_code smallint,' . 'action_seq smallint,' . 'custom_function character varying(50),' . 'hilite_color character varying(12),' . 'hilite_width smallint,' . 'select_color character varying(12),' . 'select_width smallint,' . 'CONSTRAINT ' . $prefix . '_action_pkey PRIMARY KEY (id) ) ' . 'WITH OIDS;' . "\n"; // Category table. $sql .= 'CREATE TABLE ' . $prefix . '_category (' . 'id serial NOT NULL,' . 'artifact_id integer,' . 'category_code character varying(50),' . 'category_title character varying(200),' . 'category_color character varying(8),' . 'CONSTRAINT ' . $prefix . '_category_pkey PRIMARY KEY (id) ) ' . 'WITH OIDS;' . "\n"; // XML Schema table. $sql .= 'CREATE TABLE ' . $prefix . '_schema (' . 'id serial NOT NULL,' . 'schema_name character varying(50),' . 'schema_description text,' . 'xml_text text,' . 'xml_type character varying(4),' . 'xslt_type character varying(1),' . 'CONSTRAINT ' . $prefix . '_schema_pkey PRIMARY KEY (id) ) ' . 'WITH OIDS;' . "\n"; // Schema table rule to retrieve the ID value after an insert. $sql .= 'CREATE RULE get_pkey_on_insert ' . 'AS ON INSERT TO ' . $prefix . '_schema ' . "DO SELECT currval('" . $prefix . "_schema_id_seq') AS new_id;\n"; // Execute the DDL. $status = $this->exec_ddl($sql); return $status; } //----------------------------------------------------------------------------------------------- // Delete the tables created for a Collection. The tables have standard names, // prefixed with the supplied three character string. We will attempt to delete // them all in one transaction so they all succeed or fail together. public function delete_collection_tables($prefix) { $sql = 'DROP TABLE ' . $prefix . '_artifact;' . "\n"; $sql .= 'DROP TABLE ' . $prefix . '_object;' . "\n"; $sql .= 'DROP TABLE ' . $prefix . '_action;' . "\n"; $sql .= 'DROP TABLE ' . $prefix . '_category;' . "\n"; $sql .= 'DROP TABLE ' . $prefix . '_schema;' . "\n"; $status = $this->exec_ddl($sql); return $status; } //=========================== Artifact table functions ========================================= //----------------------------------------------------------------------------------------------- // Insert a record into the Artifact table. public function artifact_insert($rec, $prefix) { $this->clear_error(); $sql = 'INSERT INTO ' . $prefix . '_artifact ' . '(id, collection_name, artifact_prefix, artifact_name, artifact_title, ' . 'artifact_description, schema_id, metadata, artifact_owner, ' . 'artifact_permissions, sequence_source, image_type, image_sizes, ' . 'thumb_size, viewer_title, viewer_logo_image) ' . 'VALUES (DEFAULT, ' . quotestr($rec['collection_name']) . ', ' . quotestr($rec['artifact_prefix']) . ', ' . quotestr($rec['artifact_name']) . ', ' . quotestr($rec['artifact_title']) . ', ' . quotestr($rec['artifact_description']) . ', ' . quotestr($rec['schema_id']) . ', ' . quotestr($rec['metadata']) . ', ' . quotestr($rec['artifact_owner']) . ', ' . quotestr($rec['artifact_permissions']) . ', ' . quotestr($rec['sequence_source']) . ', ' . quotestr($rec['image_type']) . ', ' . quotestr($rec['image_sizes']) . ', ' . quotestr($rec['thumb_size']) . ', ' . quotestr($rec['viewer_title']) . ', ' . quotestr($rec['viewer_logo_image']) . ');'; $this->exec_sql($sql, true); return ($this->last_error_status == dbsSUCCESS); } //----------------------------------------------------------------------------------------------- // Update an Artifact record based on its ID. // It is an error if the record does not exist. public function artifact_update($id, $rec, $prefix) { $this->clear_error(); $sql = 'UPDATE ' . $prefix . '_artifact SET ' . 'collection_name=' . quotestr($rec['collection_name']) . ', artifact_prefix=' . quotestr($rec['artifact_prefix']) . ', artifact_name=' . quotestr($rec['artifact_name']) . ', artifact_title=' . quotestr($rec['artifact_title']) . ', artifact_description=' . quotestr($rec['artifact_description']) . ', schema_id=' . quotestr($rec['schema_id']) . ', metadata=' . quotestr($rec['metadata']) . ', artifact_owner=' . quotestr($rec['artifact_owner']) . ', artifact_permissions=' . quotestr($rec['artifact_permissions']) . ', sequence_source=' . quotestr($rec['sequence_source']) . ', image_type=' . quotestr($rec['image_type']) . ', image_sizes=' . quotestr($rec['image_sizes']) . ', thumb_size=' . quotestr($rec['thumb_size']) . ', viewer_title=' . quotestr($rec['viewer_title']) . ', viewer_logo_image=' . quotestr($rec['viewer_logo_image']) . ' WHERE id=' . $id; $this->exec_sql($sql, false); return ($this->last_error_status == dbsSUCCESS); } //----------------------------------------------------------------------------------------------- // Delete an Artifact record. // Also delete all category records for the Artifact. public function artifact_delete($id, $collection_prefix) { $table = $collection_prefix . '_artifact'; $sql = "DELETE FROM $table WHERE id=$id"; $ok = $this->exec_sql($sql, false); if ($ok) { $table = $collection_prefix . '_category'; $sql = "DELETE FROM $table WHERE artifact_id=$id"; $ok = $this->exec_sql($sql, false); } return $ok; } //----------------------------------------------------------------------------------------------- // Get a single Artifact record based on Artifact name. public function artifact_get_row_by_name($artifact_name, $collection_prefix) { $row = array(); $artifact_table = $collection_prefix . '_artifact'; $schema_table = $collection_prefix . '_schema'; $sql = "SELECT $artifact_table.*, " . "s1.schema_name, s2.schema_name as xslt_name, s1.xml_text as dtd, s2.xml_text as xslt " . "FROM $artifact_table " . "LEFT JOIN $schema_table s1 ON (s1.id = $artifact_table.schema_id) " . "LEFT JOIN $schema_table s2 ON (s2.id = $artifact_table.xslt_id) " . 'WHERE artifact_name=' . quotestr($artifact_name); if ($result = $this->exec_query($sql)) { if (pg_num_rows($result) > 0) $row = pg_fetch_assoc($result); pg_free_result($result); } return $row; } //----------------------------------------------------------------------------------------------- // Get a single Artifact record based on Artifact prefix and Collection name. public function artifact_get_row_by_prefix($artifact_prefix, $collection_prefix) { $row = array(); $artifact_table = $collection_prefix . '_artifact'; $schema_table = $collection_prefix . '_schema'; $sql = "SELECT $artifact_table.*, " . "s1.schema_name, s2.schema_name as xslt_name, s1.xml_text as dtd, s2.xml_text as xslt " . "FROM $artifact_table " . "LEFT JOIN $schema_table s1 ON (s1.id = $artifact_table.schema_id) " . "LEFT JOIN $schema_table s2 ON (s2.id = $artifact_table.xslt_id) " . 'WHERE artifact_prefix=' . quotestr($artifact_prefix); if ($result = $this->exec_query($sql)) { if (pg_num_rows($result) > 0) $row = pg_fetch_assoc($result); pg_free_result($result); } return $row; } //----------------------------------------------------------------------------------------------- // Get a single Artifact record based on ID. public function artifact_get_row_by_id($id, $collection_prefix) { $row = array(); $artifact_table = $collection_prefix . '_artifact'; $schema_table = $collection_prefix . '_schema'; $sql = "SELECT $artifact_table.*, " . "s1.schema_name, s2.schema_name as xslt_name, s1.xml_text as dtd, s2.xml_text as xslt " . "FROM $artifact_table " . "LEFT JOIN $schema_table s1 ON (s1.id = $artifact_table.schema_id) " . "LEFT JOIN $schema_table s2 ON (s2.id = $artifact_table.xslt_id) " . "WHERE $artifact_table.id=$id"; if ($result = $this->exec_query($sql)) { if (pg_num_rows($result) > 0) $row = pg_fetch_assoc($result); pg_free_result($result); } return $row; } //----------------------------------------------------------------------------------------------- // Get a list of all Artifact records for a Collection. public function artifact_get_list($collection_prefix) { $rows = array(); $sql = 'SELECT * FROM ' . $collection_prefix . '_artifact ' . 'ORDER BY lower(artifact_title)'; if ($result = $this->exec_query($sql)) { if (pg_num_rows($result) > 0) while($row = pg_fetch_assoc($result)) $rows[] = $row; pg_free_result($result); } return $rows; } //----------------------------------------------------------------------------------------------- // Get a list of all Artifact records for a Collection. // All records are returned. We also get a count of the // Objects in the Artifacts. public function artifact_get_report_list($collection_prefix) { $rows = array(); $sql = 'SELECT *, ' . '(SELECT count(id) FROM ' . $collection_prefix . '_object ' . 'where artifact_id = ' . $collection_prefix . '_artifact.id) AS ocount ' . 'FROM ' . $collection_prefix . '_artifact ' . 'ORDER BY artifact_name'; if ($result = $this->exec_query($sql)) { if (pg_num_rows($result) > 0) while($row = pg_fetch_assoc($result)) $rows[] = $row; pg_free_result($result); } return $rows; } //----------------------------------------------------------------------------------------------- // Get a count of the Objects in an Artifact. public function artifact_get_object_count($artifact_id, $collection_prefix) { $count = 0; $sql = 'SELECT count(id) AS ocount ' . 'FROM ' . $collection_prefix . '_object ' . 'WHERE artifact_id = ' . $artifact_id; if ($result = $this->exec_query($sql)) { if (pg_num_rows($result) > 0) { $row = pg_fetch_assoc($result); $count = $row['ocount']; } pg_free_result($result); } return $count; } //----------------------------------------------------------------------------------------------- // Get a count of the Artifacts for a Collection. public function artifact_get_collect_count($collect_name, $collection_prefix) { $count = 0; $sql = 'SELECT count(id) AS acount ' . 'FROM ' . $collection_prefix . '_artifact ' . "WHERE collection_name = '$collect_name'"; if ($result = $this->exec_query($sql)) { if (pg_num_rows($result) > 0) { $row = pg_fetch_assoc($result); $count = $row['acount']; } pg_free_result($result); } return $count; } //----------------------------------------------------------------------------------------------- // Get the Artifacts owned by a user. public function artifacts_owned_by($username, $collection_prefix) { $rows = array(); $sql = 'SELECT artifact_name, artifact_title ' . 'FROM ' . $collection_prefix . '_artifact ' . "WHERE artifact_owner = '$username'"; if ($result = $this->exec_query($sql)) { if (pg_num_rows($result) > 0) while($row = pg_fetch_assoc($result)) $rows[] = $row; pg_free_result($result); } return $rows; } //=========================== Object table functions ========================================= //----------------------------------------------------------------------------------------------- // Insert a record into the Object table. // Because of a PostgreSQL RULE, the ID of the inserted // record will be stuffed into the $last_id property. // The rule on the object table looks like: // CREATE RULE get_pkey_on_insert // AS ON INSERT TO [prefix]_object // DO SELECT currval('[prefix]_object_id_seq') AS id; public function object_insert($rec, $prefix) { $this->clear_error(); $sql = 'INSERT INTO ' . $prefix . '_object ' . '(id, parent_id, artifact_id, object_level, object_type, metadata, image_name, image_width, image_height, rect_top, rect_left, rect_width, rect_height, zindex, imt_id, object_seq, category_id, object_title) ' . 'VALUES (DEFAULT, ' . $rec['parent_id'] . ', ' . $rec['artifact_id'] . ', ' . $rec['object_level'] . ', ' . $rec['object_type'] . ', ' . quotestr(pg_escape_string($rec['metadata'])) . ', ' . quotestr(pg_escape_string($rec['image_name'])) . ', ' . $rec['image_width'] . ', ' . $rec['image_height'] . ', ' . $rec['rect_top'] . ', ' . $rec['rect_left'] . ', ' . $rec['rect_width'] . ', ' . $rec['rect_height'] . ', ' . $rec['zindex'] . ', ' . quotestr(pg_escape_string($rec['imt_id'])) . ', ' . $rec['object_seq'] . ', ' . $rec['category_id'] . ', ' . quotestr(pg_escape_string($rec['object_title'])) . ');'; $this->exec_sql($sql, true); return ($this->last_error_status == dbsSUCCESS); } //----------------------------------------------------------------------------------------------- // Update an Object record based on its ID. // It is an error if the record does not exist. public function object_update($id, $rec, $prefix) { $this->clear_error(); $sql = 'UPDATE ' . $prefix . '_object SET ' . 'parent_id=' . $rec['parent_id'] . ', ' . 'artifact_id=' . $rec['artifact_id'] . ', ' . 'object_level=' . $rec['object_level'] . ', ' . 'object_type=' . $rec['object_type'] . ', ' . 'metadata=' . quotestr(pg_escape_string($rec['metadata'])) . ', ' . 'image_name=' . quotestr(pg_escape_string(no_ext($rec['image_name']))) . ', ' . 'image_width=' . $rec['image_width'] . ', ' . 'image_height=' . $rec['image_height'] . ', ' . 'reveal_image_name=' . quotestr(pg_escape_string(no_ext($rec['reveal_image_name']))) . ', ' . 'rect_top=' . $rec['rect_top'] . ', ' . 'rect_left=' . $rec['rect_left'] . ', ' . 'rect_width=' . $rec['rect_width'] . ', ' . 'rect_height=' . $rec['rect_height'] . ', ' . 'zindex=' . $rec['zindex'] . ', ' . 'imt_id=' . quotestr(pg_escape_string($rec['imt_id'])) . ', ' . 'object_seq=' . $rec['object_seq'] . ', ' . 'category_id=' . $rec['category_id'] . ', ' . 'object_title=' . quotestr(pg_escape_string($rec['object_title'])) . ' WHERE id=' . $id . ';'; $this->exec_sql($sql, false); return ($this->last_error_status == dbsSUCCESS); } //----------------------------------------------------------------------------------------------- // Delete an entire Object branch (Object plus all descendants). // This function is recursive. public function object_delete_branch($artifact_id, $object_id, $prefix, &$delete_count) { $rows = $this->object_get_list_for_parent($artifact_id, $object_id, $prefix); foreach ($rows as $row) $this->object_delete_branch($artifact_id, $row['id'], $prefix, $delete_count); $sql = 'DELETE FROM ' . $prefix . '_object ' . 'WHERE artifact_id=' . $artifact_id . 'AND id=' . $object_id; $ok = $this->exec_sql($sql, false); $delete_count += $this->last_affected_rows; return $ok; } //----------------------------------------------------------------------------------------------- // Get a single Object record based on sequence and level. public function object_get_row_by_sequence($sequence, $level, $collection_prefix) { $row = array(); $sql = 'SELECT * FROM ' . $collection_prefix . '_object ' . 'WHERE object_level=' . $level . ' AND object_seq=' . $sequence; if ($result = $this->exec_query($sql)) { if (pg_num_rows($result) > 0) $row = pg_fetch_assoc($result); pg_free_result($result); } return $row; } //----------------------------------------------------------------------------------------------- // Get a single Object record based on ID. public function object_get_row_by_id($id, $collection_prefix) { $row = array(); $object_table = $collection_prefix . '_object'; $category_table = $collection_prefix . '_category'; $sql = "SELECT $object_table.*, $category_table.category_title " . "FROM $object_table " . "LEFT JOIN $category_table ON ($category_table.id=$object_table.category_id) " . "WHERE $object_table.id=$id"; if ($result = $this->exec_query($sql)) { if (pg_num_rows($result) > 0) $row = pg_fetch_assoc($result); pg_free_result($result); } return $row; } //----------------------------------------------------------------------------------------------- // Get a list of all Object records for an Artifact, ordered // by parent to produce a tree structure. public function object_get_tree($collection_prefix, $artifact_id) { $rows = array(); $sql = 'SELECT * FROM ' . $collection_prefix . '_object ' . 'WHERE artifact_id=' . $artifact_id . ' ' . 'ORDER BY parent_id, object_seq'; if ($result = $this->exec_query($sql)) { if (pg_num_rows($result) > 0) while($row = pg_fetch_assoc($result)) $rows[] = $row; pg_free_result($result); } return $rows; } //----------------------------------------------------------------------------------------------- // Get a list of all Object record IDs for an Artifact at a specified level. // Return as an ordered array. public function object_get_level_ids($level, $collection_prefix, $artifact_id) { $ids = array(); $sql = 'SELECT id FROM ' . $collection_prefix . '_object ' . 'where artifact_id=' . $artifact_id . ' AND object_level=' . $level . ' order by object_seq'; if ($result = $this->exec_query($sql)) { if (pg_num_rows($result) > 0) while($row = pg_fetch_assoc($result)) $ids[] = $row['id']; pg_free_result($result); } return $ids; } //----------------------------------------------------------------------------------------------- // Get a list of all Object record IDs that are siblings of the // specified Object. Siblings have the same parent as our Object. // Return as an ordered array. public function object_get_siblings($artifact_id, $parent_id, $collection_prefix) { $ids = array(); $sql = 'SELECT id FROM ' . $collection_prefix . '_object ' . 'WHERE artifact_id=' . $artifact_id . ' AND parent_id=' . $parent_id . ' ' . ' order by object_seq'; if ($result = $this->exec_query($sql)) { if (pg_num_rows($result) > 0) while($row = pg_fetch_assoc($result)) $ids[] = $row['id']; pg_free_result($result); } return $ids; } //----------------------------------------------------------------------------------------------- // Get a list of all child Object records for a parent ID. public function object_get_list_for_parent($artifact_id, $parent_id, $collection_prefix) { $rows = array(); $sql = 'SELECT * FROM ' . $collection_prefix . '_object ' . 'WHERE artifact_id=' . $artifact_id . ' AND parent_id=' . $parent_id . ' ' . 'ORDER BY object_seq'; if ($result = $this->exec_query($sql)) { if (pg_num_rows($result) > 0) while($row = pg_fetch_assoc($result)) $rows[] = $row; pg_free_result($result); } return $rows; } //----------------------------------------------------------------------------------------------- // Determine if an Object has child Object records. public function object_has_children($parent_id, $collection_prefix) { $has_kids = false; $sql = 'SELECT count(id) as kids FROM ' . $collection_prefix . '_object ' . 'WHERE parent_id=' . $parent_id ; if ($result = $this->exec_query($sql)) { $row = pg_fetch_assoc($result); $has_kids = ($row['kids'] > 0); pg_free_result($result); } return $has_kids; } //----------------------------------------------------------------------------------------------- // Find the ID of the first Object in the Artifact. // "First" means the Object with level 1 and sequence 1. public function get_first_object($artifact_id, $prefix) { $id = -1; $sql = 'SELECT id FROM ' . $prefix . '_object ' . 'WHERE (artifact_id=' . $artifact_id . ') AND (object_level=1) AND (object_seq=1)'; if ($result = $this->exec_query($sql)) { if (pg_num_rows($result) > 0) { $row = pg_fetch_assoc($result); $id = $row['id']; } pg_free_result($result); } return $id; } //----------------------------------------------------------------------------------------------- // Find the ID of the first Object in the Artifact // that has metadata. public function get_first_object_metadata($artifact_id, $prefix) { $id = -1; $sql = 'SELECT id FROM ' . $prefix . '_object ' . 'WHERE (artifact_id=' . $artifact_id . ') ' . 'AND (metadata IS NOT NULL) ' . "AND (metadata != '')"; if ($result = $this->exec_query($sql)) { if (pg_num_rows($result) > 0) { $row = pg_fetch_assoc($result); $id = $row['id']; } pg_free_result($result); } return $id; } //----------------------------------------------------------------------------------------------- // Get an Object with a given markup ID for an Artifact. public function object_by_markupid($markup_id, $artifact_id, $collection_prefix) { $row = array(); $sql = 'SELECT * FROM ' . $collection_prefix . '_object ' . 'WHERE imt_id=' . quotestr($markup_id) . ' AND artifact_id=' . $artifact_id; if ($result = $this->exec_query($sql)) { if (pg_num_rows($result) > 0) $row = pg_fetch_assoc($result); pg_free_result($result); } return $row; } //----------------------------------------------------------------------------------------------- // Basic search for Object metadata. public function object_search($term, $collection_prefix, $artifact_id) { $rows = array(); $sql = 'SELECT * FROM ' . $collection_prefix . '_object ' . 'WHERE artifact_id=' . $artifact_id . ' ' . 'AND lower(metadata) LIKE ' . quotestr('%' . $term . '%') . ' ' . 'ORDER BY parent_id, object_seq'; if ($result = $this->exec_query($sql)) { if (pg_num_rows($result) > 0) while($row = pg_fetch_assoc($result)) $rows[] = $row; pg_free_result($result); } return $rows; } //----------------------------------------------------------------------------------------------- // Search for Objects using the TSearch full-text search // extension for PostgreSQL. public function object_tsearch($search_term, $fields, $categories, $collection_prefix, $artifact_id) { $rows = array(); $search_str = $search_term; // If we have fields, scrape out the terms for each field, // combine them with OR, add the field terms to the search term // with AND. This gets records with the field terms, but not // necessarily those where the field values match the terms. if (!empty($fields)) { $field_terms = ''; foreach ($fields as $field) { if (!empty($field_terms)) $field_terms .= ' OR '; $term = $field[3]; if (strpos($term, ' ') && (substr($term, 0, 1) != '"')) $term = '"' . $term . '"'; $field_terms .= $term; } if (!empty($search_str)) $search_str .= ' AND (' . $field_terms . ')'; else $search_str = $field_terms; } // Parse the search term + field terms into a form // that TSearch can work with. $this->tsearch_parser->parse($search_str); $search_str = $this->tsearch_parser->s_tsearch; $ilike_term = $this->tsearch_parser->s_ilike; // Build the select. If we have a search term, use it // for both the rank() function and the to_tsquery() // function. Categories are dealt with through a // simple IN (nn,nn,nn). The TSearch parser also // returns an ILIKE query fragment that handles // phrases in the search term (see the TSearchParser // class in class-pgts2parse.inc). The meta_vector // field is the TSearch-parsed version of the // metadata field. $sql = 'SELECT *'; if (!empty($search_str)) $sql .= ', rank(meta_vector,' . quotestr($search_str) . ')'; $sql .= ' FROM ' . $collection_prefix . '_object ' . 'WHERE (artifact_id=' . $artifact_id . ')'; if (!empty($search_str)) $sql .= ' AND (meta_vector @@ to_tsquery(' . quotestr('default') . ', ' . quotestr($search_str) . '))'; if (!empty($categories)) $sql .= ' AND (category_id IN (' . implode(',', $categories) . '))'; if (!empty($ilike_term)) $sql .= ' ' . $ilike_term; $sql .= ' ORDER BY parent_id, object_seq'; // Execute the query, get the result rows. if ($result = $this->exec_query($sql)) { if (pg_num_rows($result) > 0) while($row = pg_fetch_assoc($result)) $rows[] = $row; pg_free_result($result); } // Filter the results for any field criteria. if (!empty($fields)) $rows = $this->object_filter_by_fields($fields, $rows); return $rows; } //----------------------------------------------------------------------------------------------- // Filter Object records by a set of field criteria. // $field is: 0 => opening parentheses // 1 => field name // 2 => operator // 3 => term // 4 => closing parentheses // 5 => boolean link public function object_filter_by_fields($fields, $rows) { $newrows = array(); foreach ($rows as $row) { if (!empty($row['metadata'])) { $xpath = ''; foreach ($fields as $field) { $openpara = trim($field[0]); $fieldname = mb_convert_case($field[1], MB_CASE_LOWER); $operator = $field[2]; if ($operator == '!') { $not = 'not('; $not_end = ')'; } else { $not = ''; $not_end = ''; } $term = mb_convert_case($field[3], MB_CASE_LOWER); $closepara = trim($field[4]); if ($field[5] == '&') $link = ' and '; elseif ($field[5] == '|') $link = ' or '; else $link = ''; // XPath string for each field is // ( (//fieldname[not(contains(text(), term))]) ) and/or $xpath .= $openpara . '(//' . $fieldname . '[' . $not . 'contains(normalize-space(text()),' . "'$term'" . ')' . $not_end . '])' . $closepara . $link; } $metadata = mb_convert_case($row['metadata'], MB_CASE_LOWER); if (xquery($xpath, '' . $metadata . '')) $newrows[] = $row; } } return $newrows; } //----------------------------------------------------------------------------------------------- // Select Objects for export public function object_get_export_data($artifact_id, $selected_nodes, $fields, $categories, $collection_prefix) { $rows = array(); // Build the select. Categories are dealt with through a // simple IN (nn,nn,nn). $sql = 'SELECT * ' . 'FROM ' . $collection_prefix . '_object ' . 'WHERE (artifact_id=' . $artifact_id . ')'; if (!empty($selected_nodes)) $sql .= ' AND (id IN (' . implode(',', $selected_nodes) . '))'; if (!empty($categories)) $sql .= ' AND (category_id IN (' . implode(',', $categories) . '))'; $sql .= ' ORDER BY parent_id, object_seq'; // Execute the query, get the result rows. if ($result = $this->exec_query($sql)) { if (pg_num_rows($result) > 0) while($row = pg_fetch_assoc($result)) $rows[] = $row; pg_free_result($result); } // Filter the results for any field criteria. if (!empty($fields)) $rows = $this->object_filter_by_fields($fields, $rows); return $rows; } //=========================== Action table functions ========================================= //----------------------------------------------------------------------------------------------- // Insert a record into the action table. public function action_insert($owner_id, $owner_type, $rec, $prefix) { $this->clear_error(); $sql = 'INSERT INTO ' . $prefix . '_action ' . '(id, owner_id, owner_type, action_code, trigger_code, custom_function, ' . 'action_seq, hilite_color, hilite_width, select_color, select_width) ' . 'VALUES (DEFAULT, ' . $owner_id . ', ' . $owner_type . ', ' . $rec['action_code'] . ', ' . $rec['trigger_code'] . ', ' . quotestr($rec['custom_function']) . ', ' . $rec['action_seq'] . ', ' . quotestr($rec['hilite_color']) . ', ' . $rec['hilite_width'] . ', ' . quotestr($rec['select_color']) . ', ' . $rec['select_width'] . ')'; $this->exec_sql($sql, false); return ($this->last_error_status == dbsSUCCESS); } //----------------------------------------------------------------------------------------------- // Update an action record based on its ID. // It is an error if the record does not exist. public function action_update($id, $rec, $prefix) { $sql = 'UPDATE ' . $prefix . '_action SET ' . 'owner_id=' . $rec['owner_id'] . 'owner_type=' . $rec['owner_type'] . ', action_code=' . $rec['action_code'] . ', trigger_code=' . $rec['trigger_code'] . ', custom_function=' . quotestr($rec['custom_function']) . ' WHERE id=' . $id; $this->exec_sql($sql, false); return ($this->last_error_status == dbsSUCCESS); } //----------------------------------------------------------------------------------------------- // Get a single action record based on ID. public function action_get_row_by_id($id, $prefix) { $row = array(); $sql = 'SELECT * FROM ' . $prefix . '_action WHERE id=' . $id; if ($result = $this->exec_query($sql)) { if (pg_num_rows($result) > 0) $row = pg_fetch_assoc($result); pg_free_result($result); } return $row; } //----------------------------------------------------------------------------------------------- // Get a list of all action records for an Object or Artifact. public function action_get_list($owner_id, $owner_type, $prefix) { $rows = array(); $sql = 'SELECT * FROM ' . $prefix . '_action ' . 'WHERE owner_id=' . $owner_id . ' AND owner_type=' . $owner_type . ' ORDER BY action_seq'; if ($result = $this->exec_query($sql)) { if (pg_num_rows($result) > 0) while($row = pg_fetch_assoc($result)) $rows[] = $row; pg_free_result($result); } return $rows; } //----------------------------------------------------------------------------------------------- // Delete all action records for an Object or Artifact. public function action_delete_list($owner_id, $owner_type, $prefix) { $rows = array(); $sql = 'DELETE FROM ' . $prefix . '_action ' . 'WHERE owner_id=' . $owner_id . ' AND owner_type=' . $owner_type; if ($result = $this->exec_query($sql)) pg_free_result($result); return $rows; } //=========================== Category table functions ========================================= //----------------------------------------------------------------------------------------------- // Insert a record into the category table. // If $update_if_exists == true, update the non-ID fields if the code exists. // if $check_integrity == true and the code exists, check that the label // matches the received label; it is an error if it does not. public function category_insert($rec, $prefix, $check_integrity) { $this->clear_error(); $sql = ''; if ($check_integrity) { $row = $this->category_get_row_by_code($rec['category_code'], $rec['artifact_id'], $prefix); if (!empty($row)) { if ($rec['category_title'] != $row['category_title']) { $this->last_error_status = dbsWARNING; $this->last_error_code = dbeDATA_MISMATCH; $this->last_error_msg = 'Category code "' . $rec['category_code'] . '" already exists, but the titles do not match ("' . $rec['category_title'] . '" <> "' . $row['category_title'] . '").'; } } } else { $sql = 'INSERT INTO ' . $prefix . '_category ' . '(id, artifact_id, category_code, category_title, category_color) ' . 'VALUES (DEFAULT, ' . $rec['artifact_id'] . ', ' . quotestr(pg_escape_string($rec['category_code'])) . ', ' . quotestr(pg_escape_string($rec['category_title'])) . ', ' . quotestr($rec['category_color']) . ')'; } if (!empty($sql)) { $this->exec_sql($sql, false); } return ($this->last_error_status == dbsSUCCESS); } //----------------------------------------------------------------------------------------------- // Update a category record based on its ID. // It is an error if the record does not exist. public function category_update($id, $rec, $prefix) { $sql = 'UPDATE ' . $prefix . '_category SET ' . 'artifact_id=' . $rec['artifact_id'] . ', category_code=' . quotestr(pg_escape_string($rec['category_code'])) . ', category_title=' . quotestr(pg_escape_string($rec['category_title'])) . ', category_color=' . quotestr($rec['category_color']) . ' WHERE id=' . $id; $this->exec_sql($sql, false); return ($this->last_error_status == dbsSUCCESS); } //----------------------------------------------------------------------------------------------- // Delete a category record. public function category_delete($id, $prefix) { $table = $prefix . '_category'; $sql = "DELETE FROM $table WHERE id=$id"; $ok = $this->exec_sql($sql, false); return $ok; } //----------------------------------------------------------------------------------------------- // Given an array of category data, we will // create, update or delete category records. // The array structure is: // array(array(id, title, update-type), array(... public function update_categories($categories, $artifact_id, $prefix) { $errors = array(); foreach ($categories as $category) { $update_type = $category[2]; $rec = array('artifact_id' => $artifact_id, 'category_code' => '', 'category_title' => $category[1], 'category_color' => ''); switch ($update_type) { case 'd': // Delete if (!$this->category_delete(intval($category[0], $prefix))) $errors[] = 'Unable to delete category ' . $category[1] . '[id: ' . $category[0] . ']. The server says: ' . $this->last_error_msg; break; case 'n': // Create if (!$this->category_insert($rec, $prefix, false)) $errors[] = 'Unable to create category ' . $category[1] . '[id: ' . $category[0] . ']. The server says: ' . $this->last_error_msg; break; case 'u': // Update if (!$this->category_update($category[0], $rec, $prefix)) $errors[] = 'Unable to update category ' . $category[1] . '[id: ' . $category[0] . ']. The server says: ' . $this->last_error_msg; break; } } return $errors; } //----------------------------------------------------------------------------------------------- // Get a single category record based on category code and Artifact id. public function category_get_row_by_code($category_code, $artifact_id, $prefix) { $row = array(); $sql = 'SELECT * FROM ' . $prefix . '_category WHERE category_code=' . quotestr($category_code) . ' AND artifact_id=' . $artifact_id; if ($result = $this->exec_query($sql)) { if (pg_num_rows($result) > 0) $row = pg_fetch_assoc($result); pg_free_result($result); } return $row; } //----------------------------------------------------------------------------------------------- // Get a single category record based on ID. public function category_get_row_by_id($id, $prefix) { $row = array(); $sql = 'SELECT * FROM ' . $prefix . '_category WHERE id=' . $id; if ($result = $this->exec_query($sql)) { if (pg_num_rows($result) > 0) $row = pg_fetch_assoc($result); pg_free_result($result); } return $row; } //----------------------------------------------------------------------------------------------- // Get a list of all category records for an Artifact. public function category_get_list($artifact_id, $prefix) { $rows = array(); $sql = 'SELECT * FROM ' . $prefix . '_category ' . 'WHERE artifact_id=' . $artifact_id . ' ' . 'ORDER BY category_title'; if ($result = $this->exec_query($sql)) { if (pg_num_rows($result) > 0) while($row = pg_fetch_assoc($result)) $rows[] = $row; pg_free_result($result); } return $rows; } //--------------------------------------------------------------------------------------- // Check if a category is in use by any of an Artifact's Objects. public function category_in_use($category_id, $artifact_id, $prefix) { $in_use = false; $sql = 'SELECT count(id) as in_use FROM ' . $prefix . '_object ' . 'WHERE artifact_id=' . $artifact_id . ' AND category_id=' . $category_id; if ($result = $this->exec_query($sql)) { $row = pg_fetch_assoc($result); $in_use = ($row['in_use'] > 0); pg_free_result($result); } return $in_use; } //=========================== Schema table functions ========================================= //----------------------------------------------------------------------------------------------- // Insert a record into the Schema table. The name must be unique. public function schema_insert($rec, $prefix) { $this->clear_error(); $sql = 'INSERT INTO ' . $prefix . '_schema ' . '(id, schema_name, schema_description, xml_text, xml_type, xslt_type) ' . 'VALUES (DEFAULT, ' . quotestr($rec['schema_name']) . ', ' . quotestr($rec['schema_description']) . ', ' . quotestr($rec['xml_text']) . ', ' . quotestr($rec['xml_type']) . ', ' . quotestr($rec['xslt_type']) . ')'; $this->exec_sql($sql, true); return ($this->last_error_status == dbsSUCCESS); } //----------------------------------------------------------------------------------------------- // Update an Schema record based on its ID. // It is an error if the record does not exist. public function schema_update($id, $rec, $prefix) { $sql = 'UPDATE ' . $prefix . '_schema SET ' . ' schema_name=' . quotestr($rec['schema_name']) . ', schema_description=' . quotestr(pg_escape_string($rec['schema_description'])) . ', xml_text=' . quotestr(pg_escape_string($rec['xml_text'])) . ', xml_type=' . quotestr($rec['xml_type']) . ', xslt_type=' . quotestr($rec['xslt_type']) . ' WHERE id=' . $id; $this->exec_sql($sql, false); return ($this->last_error_status == dbsSUCCESS); } //----------------------------------------------------------------------------------------------- // Delete a Schema record. public function schema_delete($id, $collection_prefix) { $schema_table = $collection_prefix . '_schema'; $sql = "DELETE FROM $schema_table " . "WHERE id=$id"; $ok = $this->exec_sql($sql, false); return $ok; } //----------------------------------------------------------------------------------------------- // Get a single Schema record based on Schema name. public function schema_get_row_by_name($schema_name, $prefix) { $row = array(); $sql = 'SELECT * FROM ' . $prefix . '_schema WHERE schema_name=' . quotestr($schema_name); if ($result = $this->exec_query($sql)) { if (pg_num_rows($result) > 0) $row = pg_fetch_assoc($result); pg_free_result($result); } return $row; } //----------------------------------------------------------------------------------------------- // Get a single Schema record based on ID. public function schema_get_row_by_id($id, $prefix) { $row = array(); $sql = 'SELECT * FROM ' . $prefix . '_schema WHERE id=' . $id; if ($result = $this->exec_query($sql)) { if (pg_num_rows($result) > 0) $row = pg_fetch_assoc($result); pg_free_result($result); } return $row; } //----------------------------------------------------------------------------------------------- // Get a list of all Schema records. // If $xml_type is not empty, get only records of the // specified type. If $xslt_type is not empty, get // only XSLT records of the specified kind. public function schema_get_list($prefix, $xml_type, $xslt_type) { $rows = array(); $sql = 'SELECT * FROM ' . $prefix . '_schema '; if (!empty($xml_type)) $sql .= 'WHERE xml_type=' . quotestr($xml_type); if (!empty($xslt_type)) $sql .= ' AND xslt_type=' . quotestr($xslt_type); $sql .= ' ORDER BY schema_name'; if ($result = $this->exec_query($sql)) { if (pg_num_rows($result) > 0) while($row = pg_fetch_assoc($result)) $rows[] = $row; pg_free_result($result); } return $rows; } //----------------------------------------------------------------------------------------------- // See if a schema record is in use by any Artifact. public function schema_in_use($id, $prefix) { $in_use = false; $sql = 'SELECT count(id) as in_use FROM ' . $prefix . '_artifact ' . 'WHERE schema_id=' . $id . ' OR xslt_id=' . $id; if ($result = $this->exec_query($sql)) { $row = pg_fetch_assoc($result); $in_use = ($row['in_use'] > 0); pg_free_result($result); } return $in_use; } //----------------------------------------------------------------------------------------------- // Get a list of Artifacts using a schema record. public function schema_used_by($id, $prefix) { $rows = array(); $table = $prefix . '_artifact '; $sql = 'SELECT artifact_title, artifact_name FROM ' . $table . 'WHERE schema_id=' . $id . ' OR xslt_id=' . $id; if ($result = $this->exec_query($sql)) { if (pg_num_rows($result) > 0) while($row = pg_fetch_assoc($result)) $rows[] = $row; pg_free_result($result); } return $rows; } } ?> acHIGHLIGHT, 'trigger_code' => atMOUSEOVER, 'hilite_color' => '#f5f500', 'hilite_width' => 1, 'select_color' => '#ff0000', 'select_width' => 2), array('action_code' => acSHOWINFODELAY, 'trigger_code' => atMOUSEOVER, 'hilite_color' => '#f5f500', 'hilite_width' => 1, 'select_color' => '#ff0000', 'select_width' => 2), array('action_code' => acUNHIGHLIGHT, 'trigger_code' => atMOUSEOUT, 'hilite_color' => '#f5f500', 'hilite_width' => 1, 'select_color' => '#ff0000', 'select_width' => 2)); //----------------------------------------------------------------------------------------------- // Constructor: just set defaults. // We are passed a reference to the Artifact object // this Object belongs to. public function __construct($authorization_link, $artifact_link, $image_url) { $this->authorization = $authorization_link; $this->need_authorization = (isset($this->authorization) && !empty($this->authorization)); $this->id = -1; $this->parent_id = -1; $this->prior_sibling_id = -1; $this->next_sibling_id = -1; $this->first_sibling_id = -1; $this->last_sibling_id = -1; $this->sibling_ids = array(); $this->title = ''; $this->artifact = $artifact_link; $this->rect = array('top' => 0, 'left' => 0, 'width' => 0, 'height' => 0, 'zindex' => 0); $this->object_row = array(); $this->child_rows = array(); $this->action_list = null; $this->image_base_path = $image_url . $artifact_link->collection->prefix . '_' . $artifact_link->prefix . '/'; $this->clear_errors(); } //----------------------------------------------------------------------------------------------- // Clear the error status. public function clear_errors() { $this->errors = array(); $this->fatal_error = false; } //----------------------------------------------------------------------------------------------- // Load the data for the object. public function load_object($object_id) { $this->clear_errors(); $db = $this->artifact->collection->dbobj; $prefix = $this->artifact->collection->prefix; // Get the Object record. $this->object_row = $db->object_get_row_by_id($object_id, $prefix); if (empty($this->object_row)) { $this->errors[] = 'Object ' . $object_id . ' not found.'; $this->fatal_error = true; } else { // Copy the record data to our properties. $this->id = $object_id; $this->parent_id = $this->object_row['parent_id']; $this->sequence = $this->object_row['object_seq']; $this->level = $this->object_row['object_level']; $this->object_type = $this->object_row['object_type']; $this->title = $this->object_row['object_title']; $this->metadata = $this->object_row['metadata']; $this->category = $this->object_row['category_title']; $this->category_id = $this->object_row['category_id']; $this->imt_id = $this->object_row['imt_id']; // Get our parent row and type. if ($this->parent_id <> 0) { $parent_row = $db->object_get_row_by_id($this->parent_id, $prefix); $this->parent_object_type = $parent_row['object_type']; } else $this->parent_object_type = otSIMPLE; // Rectangle. $this->rect['left'] = intval(intval($this->object_row['rect_left'])); $this->rect['top'] = intval(intval($this->object_row['rect_top'])); $this->rect['width'] = intval(intval($this->object_row['rect_width'])); $this->rect['height'] = intval(intval($this->object_row['rect_height'])); $this->rect['zindex'] = intval(intval($this->object_row['zindex'])); // Get a list of sibling Object IDs. $this->sibling_ids = $db->object_get_siblings($this->artifact->artifact_id, $this->parent_id, $prefix); // Get the first, last, prior and next siblings. $this->prior_sibling_id = $this->get_sibling(-1); $this->next_sibling_id = $this->get_sibling(1); $this->first_sibling_id = $this->get_sibling(0); $this->last_sibling_id = $this->get_sibling(999999); // Get the child Object records. $this->child_rows = $db->object_get_list_for_parent($this->artifact->artifact_id, $object_id, $prefix); // Object image file name and size. if (empty($this->object_row['image_name'])) $this->image_filename = ''; else $this->image_filename = strtolower($this->object_row['image_name']) . '.' . $this->artifact->image_type; $this->image_size = array('width' => $this->object_row['image_width'], 'height' => $this->object_row['image_height']); if (empty($this->object_row['reveal_image_name'])) $this->reveal_image_name = ''; else $this->reveal_image_name = strtolower($this->object_row['reveal_image_name']) . '.' . $this->artifact->image_type; // Action list. $this->action_list = new c_ActionList($this->id, aotOBJECT, $this); } return !$this->fatal_error; } //--------------------------------------------------------------------------------------- // Copy the passed data into our properties. // The data is assumed to be valid. public function set_object_data($data, $is_new) { $this->clear_errors(); $this->parent_id = $data['parent_id']; $this->artifact->artifact_id = $data['artifact_id']; $this->object_type = $data['object_type']; $this->level = $data['object_level']; $this->image_filename = $data['image_name']; $this->reveal_image_name = $data['reveal_image_name']; if (!empty($this->image_filename)) { $this->image_size['width'] = $data['image_width']; $this->image_size['height'] = $data['image_height']; } else { $this->image_size['width'] = 0; $this->image_size['height'] = 0; } $this->metadata = $data['metadata']; $this->imt_id = $data['imt_id']; $this->sequence = $data['object_seq']; $this->category_id = $data['category_id']; $this->title = $data['object_title']; // Actions come in as an XML chunk. If it is really an // action list XML packet, just parse the packet into our actions. // If the chunk just contains 'default', no actions were returned. // If this is a new Object, create a default XML chunk. // If it is an existing Object, leave the actions alone. $xml = $data['actions']; if ($is_new) $this->action_list = new c_ActionList(0, aotOBJECT, $this); if (strtolower($xml) == 'default') { if ($is_new) { $xml = $this->action_list->make_default_xml_packet(); $this->action_list->load_actionlist_xml($xml); } } else $this->action_list->load_actionlist_xml($xml); } //--------------------------------------------------------------------------------------- // Save our Object to the database. public function save_object($do_insert) { $this->clear_errors(); $had_error = false; $collection = $this->artifact->collection; $db = $collection->dbobj; $prefix = $collection->prefix; $data = array('parent_id' => $this->parent_id, 'artifact_id' => $this->artifact->artifact_id, 'object_type' => $this->object_type, 'object_level' => $this->level, 'image_name' => $this->image_filename, 'image_width' => $this->image_size['width'], 'image_height' => $this->image_size['height'], 'reveal_image_name' => $this->reveal_image_name, 'rect_top' => $this->rect['top'], 'rect_left' => $this->rect['left'], 'rect_width' => $this->rect['width'], 'rect_height' => $this->rect['height'], 'zindex' => $this->rect['zindex'], 'metadata' => $this->metadata, 'imt_id' => $this->imt_id, 'object_seq' => $this->sequence, 'category_id' => $this->category_id, 'object_title' => $this->title); // Insert or update record. if ($do_insert) $had_error = (!$db->object_insert($data, $prefix)); else $had_error = (!$db->object_update($this->id, $data, $prefix)); if ($had_error) $this->errors[] = $db->last_error_msg; else { // Save the Object's action list. if ($do_insert) $this->id = $db->last_id; $this->action_list->owner_id = $this->id; if (!$this->action_list->save_action_list()) { $had_error = true; foreach ($this->action_list->errors as $error) $this->errors[] = $error; } } // Reload our properties from the just saved record. $this->load_object($this->id); return !$had_error; } //--------------------------------------------------------------------------------------- // Get the first ($incr=0), last ($incr=999999), // prior ($incr=-1) or next ($incr=1) sibling of this Object. // If none, set to -1. Root Objects (parent ID = 0) always // can have siblings. Other Objects can have siblings only // if they are type otMULTIPART. public function get_sibling($incr) { $id = -1; if (($this->parent_id == 0) || ($this->parent_object_type == otMULTIPART)) { switch ($incr) { case -1: // Prior $me = array_search ($this->id, $this->sibling_ids); if ($me > 0) $id = $this->sibling_ids[$me - 1]; break; case 0: // First if (!empty($this->sibling_ids[0]) && ($this->sibling_ids[0] != $this->id)) $id = $this->sibling_ids[0]; break; case 1; // Next $me = array_search ($this->id, $this->sibling_ids); if ($me < count($this->sibling_ids) - 1) $id = $this->sibling_ids[$me + 1]; break; case 999999: // Last if (!empty($this->sibling_ids[count($this->sibling_ids) - 1]) && ($this->sibling_ids[count($this->sibling_ids) - 1] != $this->id)) $id = $this->sibling_ids[count($this->sibling_ids) - 1]; break; } } return $id; } //--------------------------------------------------------------------------------------- // Build a
with mouseover, mouseout, and onclick event handlers, // of a position and size that matches the rectangle of an Object. public function build_rect($row, $info_delay, $scale_factor, $size_folder, $actions, $show_object_path) { global $_highlight_color, $_image_blowup_path, $_img_ext; // Set up some data for convenience. $id = $row['id']; $quote_id = quotestr('O' . $id); $item_number = $row['object_seq']; $rect_title = htmlentities($row['object_title']); // Set the onclick and mouseover handlers for the div. $on_trigger = array(atMOUSECLICK => '', atMOUSEOVER => '', atMOUSEOUT => ''); // Actions and trigger codes determine the Javascript function called. foreach ($actions as $action) { switch ($action['action_code']) { case acNONE: case acSHOWINFO; $on_trigger[$action['trigger_code']] .= 'ObjectView.showInfo(' . $quote_id . ');'; break; case acSHOWINFODELAY; $on_trigger[$action['trigger_code']] .= 'ObjectView.showInfoDelayed(' . $quote_id . ',' . $info_delay . ');'; break; case acHIDEINFO; $on_trigger[$action['trigger_code']] .= 'ObjectView.hideInfo(' . $quote_id . ');'; break; case acSHOWOBJECT: $on_trigger[$action['trigger_code']] .= 'ObjectView.showObject(' . quotestr($show_object_path) . ');'; break; case acSHOWBLOWUP: $on_trigger[$action['trigger_code']] .= 'ObjectView.showEnlarge(' . $quote_id . ',' . quotestr($rect_title) . ');'; break; case acLINK: if (!empty($action['custom_function'])) $on_trigger[$action['trigger_code']] .= 'ObjectView.linkTo(event,' . quotestr($action['custom_function']) . ');'; break; case acPOPUP: $on_trigger[$action['trigger_code']] .= ''; break; case acREVEAL: $on_trigger[$action['trigger_code']] .= 'ObjectView.showReveal(' . $quote_id . ',' . quotestr(make_abs_url($this->image_base_path . $size_folder . '/reveal/' . $row['reveal_image_name'] . '.' . $this->artifact->image_type)) . ');'; break; case acUNREVEAL: $on_trigger[$action['trigger_code']] .= 'ObjectView.hideReveal(' . $quote_id . ');'; break; case acSELECT: $on_trigger[$action['trigger_code']] = 'ObjectView.selectItem(' . $quote_id . ',' . $action['select_width'] . ',' . quotestr($action['select_color']) . ',' . 'true);'; break; case acHIGHLIGHT: $on_trigger[$action['trigger_code']] .= 'ObjectView.showHighlight(' . $quote_id . ',' . $action['hilite_width'] . ',' . quotestr($action['hilite_color']) . ');'; break; case acUNHIGHLIGHT: $on_trigger[$action['trigger_code']] .= 'ObjectView.hideHighlight(' . $quote_id . ')'; break; case acCUSTOM: if (!empty($action['custom_function'])) { $func = $action['custom_function'] . '(' . $quote_id . ',' . $action['hilite_width'] . ',' . quotestr($action['hilite_color']) . ',' . $action['select_width'] . ',' . quotestr($action['select_color']) . ');'; $on_trigger[$action['trigger_code']] .= func; } break; } } // Build the div with mouseover, mouseout and mouseclick event handlers. // The div is absolutely positioned using the item coordinates. The title // will be displayed as a mouseover tooltip. // The span holds the item number, which can be displayed // over the image. The 'pix.gif' image is a hack for the // utterly abominable Internet Explorer, which won't trigger // a mouseover for an empty div. The image is transparent, // and is scaled to fully fill the rect div, giving IE // something to work with. $left = intval(intval($row['rect_left']) * $scale_factor); $top = intval(intval($row['rect_top']) * $scale_factor); $width = intval(intval($row['rect_width']) * $scale_factor); $height = intval(intval($row['rect_height']) * $scale_factor); $zindex = $row['zindex']; $rect_divs = '
' . '' . '' . $item_number . '' . '
' . "\n"; return $rect_divs; } //--------------------------------------------------------------------------------------- // Get a list of the titles in the Object's children. function child_object_titles($color) { $item_titles = array(); foreach ($this->child_rows as $row) $item_titles[] = array('title' => htmlentities($row['object_title']), 'color' => $color, 'id' => $row['id']); return $item_titles; } //--------------------------------------------------------------------------------------- // Build all of the
tags to represent the Objects that are // children of our Object. function build_object_block($info_delay, $size_index, $def_actions) { // Calculate actual size, get image scale factor and path. $scale_factor = $this->artifact->image_sizes[$size_index]['factor']; $size_folder = $this->artifact->image_sizes[$size_index]['folder']; $image_path = make_abs_url($this->image_base_path . $size_folder . '/' . $this->image_filename); $rect_divs = ''; // For each child, create a temporary Object object, // use it to generate the
tags. foreach ($this->child_rows as $row) { $object_id = $row['id']; $object = object_connect($this->authorization, $object_id, $this->artifact); // Get the actions for the Object. if (!empty($def_actions)) $actions = $def_actions; elseif (!empty($object->action_list->actions)) $actions = $object->action_list->actions; else $actions = $this->base_actions; // Build a path to the Object depending on its type. if (($object->object_type == otMULTIPART) && isset($object->child_rows[0]['id'])) $show_object_path = $this->make_object_path($object->child_rows[0]['id']); else $show_object_path = $this->make_object_path($row['id']); unset($object); // Build a
, add it to our HTML block. $rect_divs .= $this->build_rect($row, $info_delay, $scale_factor, $size_folder, $actions, $show_object_path); } // Add the tag to the HTML block. $block = '' . "\n" . $rect_divs; return $block; } //--------------------------------------------------------------------------------------- // Convert an Object type code to a string. function object_type_str($type) { $type_str = 'Unknown'; switch ($type) { case otSIMPLE: $type_str = 'Simple'; break; case otMULTIPART: $type_str = 'Multipart'; break; } return $type_str; } //--------------------------------------------------------------------------------------- // Format the metadata for our Object using the supplied XSLT. // If no XSLT, just indent the XML and return it. public function format_metadata($xslt) { if (empty($this->metadata)) $fxml = ''; else { $xml = '' . $this->metadata . ''; $xmldoc = new DOMDocument; $xml_errors = load_xml_string($xmldoc, $xml); if (!empty($xml_errors)) { $fxml = '

The metadata for this Object is not valid ' . 'and cannot be properly displayed. The unformatted ' . 'metadata is shown below.

'; $fxml .= '

' . readable_xml($this->metadata, true) . '

'; return $fxml; } // Load the XSLT, transform the metadata. $xsldoc = new DOMDocument; $xsldoc->loadXML($xslt); $proc = new XSLTProcessor; $proc->importStyleSheet($xsldoc); $fxml = $proc->transformToXML($xmldoc); } return $fxml; } //--------------------------------------------------------------------------------------- // Generate the node ID for an Object (Collection + Artifact + Object). public function object_node_id($id) { if (empty($id)) $id = $this->id; return 'C' . $this->artifact->collection->name . '-A' . $this->artifact->artifact_id . '-O' . $id; } //--------------------------------------------------------------------------------------- // Get the number of kids this Object has. public function child_count() { return count($this->child_rows); } //--------------------------------------------------------------------------------------- // Check if this Object has an image. public function has_image() { return (!empty($this->image_filename)); } //--------------------------------------------------------------------------------------- // Build a node path to this Object. // The path is a series of Object node IDs separated by /. public function make_object_path($id) { $collection = $this->artifact->collection; $db = $collection->dbobj; $prefix = $collection->prefix; if (empty($id)) $id = $this->id; $path = ''; while ($id != 0) { $prow = $db->object_get_row_by_id($id, $prefix); if (empty($prow)) $id = 0; else { $id = $prow['parent_id']; $path = '/' . $this->object_node_id($prow['id']) . $path; } } return $path; } //--------------------------------------------------------------------------------------- // Get a list of the unique in an Object's metadata. public function get_metadata_tags() { $list = array(); if (!empty($this->metadata)) { $xmldoc = new DOMDocument(); $xmldoc->preserveWhiteSpace = false; load_xml_string($xmldoc, '' . $this->metadata . ''); $list = get_tags($xmldoc); sort($list); $outlist = array(); foreach($list as $item) if (($item != 'metaroottag') && !in_array($item, $outlist)) $outlist[] = $item; } return $outlist; } } ?> Viewer The requested page cannot be found.

'; exit; } $node_path = $active_object->make_object_path(''); $collect_name = $active_collection->name; $artifact_name = $active_artifact->name; } else { // General load of an Artifact, no specific Object. // The Collection name and Artifact name are used. $collect_name = load_data('collection'); $artifact_name = load_data('artifact'); $node_path = ''; $active_collection = collection_connect(null, $collect_name); $active_artifact = artifact_connect_by_name(null, $artifact_name, $active_collection); } // Artifact ID and title for the viewer. $artifact_id = $active_artifact->artifact_id; $artifact_title = $active_artifact->viewer_title; if (empty($artifact_title)) $artifact_title = $active_artifact->title; // The rest of this is just templates. // The Ext layout builder will mungle it up into the viewer page. ?>