diff --git a/includes/datastream.version.inc b/includes/datastream.version.inc index f245830c..515094bd 100644 --- a/includes/datastream.version.inc +++ b/includes/datastream.version.inc @@ -280,17 +280,16 @@ function islandora_datastream_version_replace_form($form, &$form_state, Abstract $form_state['object_id'] = $object->id; $form_state['dsid'] = $datastream->id; $form_state['object'] = $object; - $extensions = islandora_get_object_extensions($object); + $datastream_mime_map = islandora_get_object_extensions($object); $mime_detect = new MimeDetect(); $ext = array(); - if (isset($extensions[$datastream->id])) { - foreach ($extensions[$datastream->id]['mime'] as $key => $value) { - $str = $mime_detect->getExtension($value); - array_push($ext, $str); + if (isset($datastream_mime_map[$datastream->id])) { + foreach ($datastream_mime_map[$datastream->id]['mime'] as $key => $value) { + $extensions = $mime_detect->getValidExtensions($value); + $ext = array_merge($ext, $extensions); } } - $comma = count($ext) > 1 ? "," : ""; - $ext = array(implode($comma, $ext)); + $upload_size = min((int) ini_get('post_max_size'), (int) ini_get('upload_max_filesize')); return array( 'dsid_fieldset' => array( diff --git a/includes/ingest.form.inc b/includes/ingest.form.inc index f7979063..b5a4740d 100644 --- a/includes/ingest.form.inc +++ b/includes/ingest.form.inc @@ -706,7 +706,11 @@ function islandora_ingest_form_ingest_button(array &$form_state) { $validate_callback = $form_id . '_validate'; $validate = function_exists($validate_callback) ? array($validate_callback) : NULL; $submit_callback = $form_id . '_submit'; - $submit = function_exists($submit_callback) ? array($submit_callback, 'islandora_ingest_form_submit') : array('islandora_ingest_form_submit'); + $submit = function_exists($submit_callback) ? array( + $submit_callback, + 'islandora_ingest_form_pre_submit', + 'islandora_ingest_form_submit', + ) : array('islandora_ingest_form_pre_submit', 'islandora_ingest_form_submit'); return array( '#type' => 'submit', '#name' => 'ingest', diff --git a/includes/mime_detect.inc b/includes/mime_detect.inc index 03ece01f..74b87fd6 100644 --- a/includes/mime_detect.inc +++ b/includes/mime_detect.inc @@ -132,7 +132,8 @@ class MimeDetect { 'wbxml' => 'application/vnd.wap.wbxml', 'xht' => 'application/xhtml+xml', 'xhtml' => 'application/xhtml+xml', - 'xsl' => 'text/xml', + 'xsl' => 'text/xsl', + 'xslt' => 'text/xsl', 'xml' => 'text/xml', 'csv' => 'text/csv', 'tsv' => 'text/tab-separated-values', @@ -224,6 +225,8 @@ class MimeDetect { "zip" => "application/x-zip", // others: 'bin' => 'application/octet-stream', + // Web Archives: + "warc" => "application/warc", ); protected $protectedFileExtensions; protected $extensionExceptions = array( diff --git a/includes/tuque_wrapper.inc b/includes/tuque_wrapper.inc index 573d7c62..348ac60a 100644 --- a/includes/tuque_wrapper.inc +++ b/includes/tuque_wrapper.inc @@ -144,6 +144,41 @@ class IslandoraFedoraObject extends FedoraObject { protected $fedoraDatastreamClass = 'IslandoraFedoraDatastream'; protected $fedoraRelsExtClass = 'IslandoraFedoraRelsExt'; + /** + * Magical magic, to allow recursive modifications. + * + * So... Magic functions in PHP are not re-entrant... Meaning that if you + * have something which tries to call __set on an object anywhere later in + * the callstack after it has already been called, it will not call the + * magic method again; instead, it will set the property on the object + * proper. Here, we detect the property being set on the object proper, and + * restore the magic functionality as long as it keeps getting set... + * + * Not necessary to try to account for this in Tuque proper, as Tuque itself + * does not have a mechanism to trigger modifications resulting from other + * modifications. + * + * @param string $name + * The name of the property being set. + * @param mixed $value + * The value to which the property should be set. + */ + public function __set($name, $value) { + parent::__set($name, $value); + + // XXX: Due to the structure of the code, we cannot use property_exists() + // (because many of the properties are declared in the class, and the magic + // triggers due them being NULLed), nor can we use isset() (because it is + // implemented as another magic function...). + $vars = get_object_vars($this); + while (isset($vars[$name])) { + $new_value = $this->$name; + unset($this->$name); + parent::__set($name, $new_value); + $vars = get_object_vars($this); + } + } + /** * Ingest the given datastream. * @@ -173,6 +208,30 @@ class IslandoraFedoraObject extends FedoraObject { throw $e; } } + + /** + * Inherits. + * + * Calls parent and invokes object modified and deleted(/purged) hooks. + * + * @see FedoraObject::modifyObject() + */ + protected function modifyObject($params) { + try { + parent::modifyObject($params); + islandora_invoke_object_hooks(ISLANDORA_OBJECT_MODIFIED_HOOK, $this->models, $this); + if ($this->state == 'D') { + islandora_invoke_object_hooks(ISLANDORA_OBJECT_PURGED_HOOK, $this->models, $this->id); + } + } + catch (Exception $e) { + watchdog('islandora', 'Failed to modify object: @pid
code: @code
message: @msg', array( + '@pid' => $this->id, + '@code' => $e->getCode(), + '@msg' => $e->getMessage()), WATCHDOG_ERROR); + throw $e; + } + } } class IslandoraRepositoryConnection extends RepositoryConnection {} @@ -219,25 +278,10 @@ class IslandoraFedoraApiM extends FedoraApiM { if (isset($params['lastModifiedDate'])) { $params['lastModifiedDate'] = (string) $object[$dsid]->createdDate; } - try { - if ($context['block']) { - throw new Exception('Modify Datastream was blocked.'); - } - $ret = parent::modifyDatastream($pid, $dsid, $params); - islandora_invoke_datastream_hooks(ISLANDORA_DATASTREAM_MODIFIED_HOOK, $object->models, $dsid, $object, $datastream); - if (isset($params['dsState']) && $params['dsState'] == 'D') { - islandora_invoke_datastream_hooks(ISLANDORA_DATASTREAM_PURGED_HOOK, $object->models, $dsid, $object, $dsid); - } - return $ret; - } - catch (Exception $e) { - watchdog('islandora', 'Failed to modify datastream @dsid from @pid
code: @code
message: @msg', array( - '@pid' => $pid, - '@dsid' => $dsid, - '@code' => $e->getCode(), - '@msg' => $e->getMessage()), WATCHDOG_ERROR); - throw $e; + if ($context['block']) { + throw new Exception('Modify Datastream was blocked.'); } + return parent::modifyDatastream($pid, $dsid, $params); } /** @@ -254,24 +298,10 @@ class IslandoraFedoraApiM extends FedoraApiM { ); islandora_alter_object($object, $context); $params = $context['params']; - try { - if ($context['block']) { - throw new Exception('Modify Object was blocked.'); - } - $ret = parent::modifyObject($pid, $params); - islandora_invoke_object_hooks(ISLANDORA_OBJECT_MODIFIED_HOOK, $object->models, $object); - if (isset($params['state']) && $params['state'] == 'D') { - islandora_invoke_object_hooks(ISLANDORA_OBJECT_PURGED_HOOK, $object->models, $object->id); - } - return $ret; - } - catch (Exception $e) { - watchdog('islandora', 'Failed to modify object: @pid
code: @code
message: @msg', array( - '@pid' => $pid, - '@code' => $e->getCode(), - '@msg' => $e->getMessage()), WATCHDOG_ERROR); - throw $e; + if ($context['block']) { + throw new Exception('Modify Object was blocked.'); } + return parent::modifyObject($pid, $params); } /** @@ -377,6 +407,66 @@ class IslandoraNewFedoraDatastream extends NewFedoraDatastream { class IslandoraFedoraDatastream extends FedoraDatastream { protected $fedoraRelsIntClass = 'IslandoraFedoraRelsInt'; protected $fedoraDatastreamVersionClass = 'IslandoraFedoraDatastreamVersion'; + + /** + * Magical magic, to allow recursive modifications. + * + * So... Magic functions in PHP are not re-entrant... Meaning that if you + * have something which tries to call __set on an object anywhere later in + * the callstack after it has already been called, it will not call the + * magic method again; instead, it will set the property on the object + * proper. Here, we detect the property being set on the object proper, and + * restore the magic functionality as long as it keeps getting set... + * + * Not necessary to try to account for this in Tuque proper, as Tuque itself + * does not have a mechanism to trigger modifications resulting from other + * modifications. + * + * @param string $name + * The name of the property being set. + * @param mixed $value + * The value to which the property should be set. + */ + public function __set($name, $value) { + parent::__set($name, $value); + + // XXX: Due to the structure of the code, we cannot use property_exists() + // (because many of the properties are declared in the class, and the magic + // triggers due them being NULLed), nor can we use isset() (because it is + // implemented as another magic function...). + $vars = get_object_vars($this); + while (isset($vars[$name])) { + $new_value = $this->$name; + unset($this->$name); + parent::__set($name, $new_value); + $vars = get_object_vars($this); + } + } + + /** + * Inherits. + * + * Calls parent and invokes modified and purged hooks. + * + * @see FedoraDatastream::modifyDatastream() + */ + protected function modifyDatastream(array $args) { + try { + parent::modifyDatastream($args); + islandora_invoke_datastream_hooks(ISLANDORA_DATASTREAM_MODIFIED_HOOK, $this->parent->models, $this->id, $this->parent, $this); + if ($this->state == 'D') { + islandora_invoke_datastream_hooks(ISLANDORA_DATASTREAM_PURGED_HOOK, $this->parent->models, $this->id, $this->parent, $this->id); + } + } + catch (Exception $e) { + watchdog('islandora', 'Failed to modify datastream @dsid from @pid
code: @code
message: @msg', array( + '@pid' => $this->parent->id, + '@dsid' => $this->id, + '@code' => $e->getCode(), + '@msg' => $e->getMessage()), WATCHDOG_ERROR); + throw $e; + } + } } class IslandoraFedoraDatastreamVersion extends FedoraDatastreamVersion { diff --git a/includes/utilities.inc b/includes/utilities.inc index 050921cc..26633df5 100644 --- a/includes/utilities.inc +++ b/includes/utilities.inc @@ -30,16 +30,16 @@ function islandora_convert_bytes_to_human_readable($bytes, $precision = 2) { return $bytes . ' B'; } elseif (($bytes >= $kilobyte) && ($bytes < $megabyte)) { - return round($bytes / $kilobyte, $precision) . ' KB'; + return round($bytes / $kilobyte, $precision) . ' KiB'; } elseif (($bytes >= $megabyte) && ($bytes < $gigabyte)) { - return round($bytes / $megabyte, $precision) . ' MB'; + return round($bytes / $megabyte, $precision) . ' MiB'; } elseif (($bytes >= $gigabyte) && ($bytes < $terabyte)) { - return round($bytes / $gigabyte, $precision) . ' GB'; + return round($bytes / $gigabyte, $precision) . ' GiB'; } elseif ($bytes >= $terabyte) { - return round($bytes / $terabyte, $precision) . ' TB'; + return round($bytes / $terabyte, $precision) . ' TiB'; } else { return $bytes . ' B'; @@ -649,54 +649,6 @@ function islandora_system_settings_form_default_value($name, $default_value, arr return isset($form_state['values'][$name]) ? $form_state['values'][$name] : variable_get($name, $default_value); } -/** - * Returns basic information about DS-COMPOSITE-MODEL. - * - * @deprecated - * The pre-existing--and more flexible-- - * islandora_get_datastreams_requirements_from_content_model() should be - * preferred, as it addresses the case where a stream can be allowed to have - * one of a set of mimetypes (this functions appears to only return the last - * declared mimetype for a given datastream). - * - * @param string $pid - * The PID of content model containing DS_COMP stream. - * - * @return array - * An associative array mapping datastream IDs to an associative array - * representing the parsed DS-COMPOSITE-MODEL of the form: - * - DSID: A string containing the datastream ID. - * - "mimetype": A string containing the last mimetype declared for the - * given datastream ID. - * - "optional": An optional boolean indicating that the given datastream - * is optional. - */ -function islandora_get_comp_ds_mappings($pid) { - $message = islandora_deprecated('7.x-1.2', t('Refactor to use the more flexible islandora_get_datastreams_requirements_from_content_model().')); - trigger_error(filter_xss($message), E_USER_DEPRECATED); - - $cm_object = islandora_object_load($pid); - if (!isset($cm_object) || !isset($cm_object['DS-COMPOSITE-MODEL'])) { - return FALSE; - } - $datastream = $cm_object['DS-COMPOSITE-MODEL']; - $ds_comp_stream = $datastream->content; - $sxml = new SimpleXMLElement($ds_comp_stream); - $mappings = array(); - foreach ($sxml->dsTypeModel as $ds) { - $dsid = (string) $ds['ID']; - $optional = (string) $ds['optional']; - foreach ($ds->form as $form) { - $mime = (string) $form['MIME']; - if ($optional) { - $mappings[$dsid]['optional'] = $optional; - } - $mappings[$dsid]['mimetype'] = $mime; - } - } - return $mappings; -} - /** * Checks that the given/current account has all the given permissions. * diff --git a/islandora.module b/islandora.module index 31ea4e65..f0bf796b 100644 --- a/islandora.module +++ b/islandora.module @@ -184,7 +184,6 @@ function islandora_menu() { ISLANDORA_INGEST, ), 2), ); - $islandora_path = drupal_get_path('module', 'islandora'); $items['islandora/object/%islandora_object/manage/overview'] = array( 'title' => 'Overview', 'type' => MENU_DEFAULT_LOCAL_TASK, @@ -1906,6 +1905,22 @@ function islandora_find_package($package_name) { return $found && user_access('administer site configuration'); } +/** + * Helper function for ingest steps and batches. + * + * When batches within batches are triggered within ingest steps + * the submit handler becomes out of scope. When it becomes time to execute the + * submit the function cannot be found and fails. This pre-submit is to + * get around this problem. + * + * @see https://www.drupal.org/node/2300367 + * + * @see https://www.drupal.org/node/1300928 + */ +function islandora_ingest_form_pre_submit($form, &$form_state) { + module_load_include('inc', 'islandora', 'includes/ingest.form'); +} + /** * Implements hook_menu_local_tasks_alter(). */ diff --git a/tests/hooks.test b/tests/hooks.test index d08c537b..b8846c52 100644 --- a/tests/hooks.test +++ b/tests/hooks.test @@ -109,9 +109,11 @@ class IslandoraHooksTestCase extends IslandoraWebTestCase { $this->repository->ingestObject($object); $_SESSION['islandora_hooks']['hook'][ISLANDORA_OBJECT_MODIFIED_HOOK] = FALSE; $_SESSION['islandora_hooks']['alter'][ISLANDORA_OBJECT_MODIFIED_HOOK] = FALSE; + $_SESSION['islandora_hooks']['iteration'][ISLANDORA_OBJECT_MODIFIED_HOOK] = 0; $object->label = "New Label!"; $this->assert($_SESSION['islandora_hooks']['alter'][ISLANDORA_OBJECT_MODIFIED_HOOK], 'Called "hook_islandora_object_alter" when modifying via set magic functions.'); $this->assert($_SESSION['islandora_hooks']['hook'][ISLANDORA_OBJECT_MODIFIED_HOOK], 'Called ISLANDORA_OBJECT_MODIFIED_HOOK when modifying via set magic functions.'); + $this->assertEqual('New Label! + 3', $object->label, 'Re-entered ISLANDORA_OBJECT_MODIFIED_HOOK when modifying via set magic functions.'); // Test blocking the modification. try { @@ -191,10 +193,12 @@ class IslandoraHooksTestCase extends IslandoraWebTestCase { $ds = $object->constructDatastream('TEST'); $object->ingestDatastream($ds); $_SESSION['islandora_hooks']['hook'][ISLANDORA_DATASTREAM_MODIFIED_HOOK] = FALSE; + $_SESSION['islandora_hooks']['iteration'][ISLANDORA_DATASTREAM_MODIFIED_HOOK] = 0; $_SESSION['islandora_hooks']['alter'][ISLANDORA_DATASTREAM_MODIFIED_HOOK] = FALSE; $ds->label = "New Label!"; $this->assert($_SESSION['islandora_hooks']['alter'][ISLANDORA_DATASTREAM_MODIFIED_HOOK], 'Called "hook_islandora_datastream_alter" when modifying via set magic functions.'); $this->assert($_SESSION['islandora_hooks']['hook'][ISLANDORA_DATASTREAM_MODIFIED_HOOK], 'Called ISLANDORA_DATASTREAM_MODIFIED_HOOK when modifying via set magic functions.'); + $this->assertEqual('New Label! + 3', $ds->label, 'Re-entered ISLANDORA_DATASTREAM_MODIFIED_HOOK when modifying via set magic functions.'); // Test blocking modifying. try { diff --git a/tests/islandora_hooks_test.module b/tests/islandora_hooks_test.module index a6b8a5b6..cceb4dbc 100644 --- a/tests/islandora_hooks_test.module +++ b/tests/islandora_hooks_test.module @@ -112,6 +112,10 @@ function islandora_hooks_test_islandora_object_ingested(AbstractObject $object) function islandora_hooks_test_islandora_object_modified(AbstractObject $object) { if ($object->id == 'test:testModifiedObjectHook') { $_SESSION['islandora_hooks']['hook'][ISLANDORA_OBJECT_MODIFIED_HOOK] = TRUE; + if ($_SESSION['islandora_hooks']['iteration'][ISLANDORA_OBJECT_MODIFIED_HOOK]++ < 3) { + $new_label = 'New Label! + ' . $_SESSION['islandora_hooks']['iteration'][ISLANDORA_OBJECT_MODIFIED_HOOK]; + $object->label = $new_label; + } } } @@ -139,6 +143,10 @@ function islandora_hooks_test_islandora_datastream_ingested(AbstractObject $obje function islandora_hooks_test_islandora_datastream_modified(AbstractObject $object, AbstractDatastream $datastream) { if ($object->id == 'test:testModifiedDatastreamHook' && $datastream->id == "TEST") { $_SESSION['islandora_hooks']['hook'][ISLANDORA_DATASTREAM_MODIFIED_HOOK] = TRUE; + if ($_SESSION['islandora_hooks']['iteration'][ISLANDORA_DATASTREAM_MODIFIED_HOOK]++ < 3) { + $new_label = 'New Label! + ' . $_SESSION['islandora_hooks']['iteration'][ISLANDORA_DATASTREAM_MODIFIED_HOOK]; + $datastream->label = $new_label; + } } }