Dan-nl has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/90527


Change subject: item specific categories throws an exception
......................................................................

item specific categories throws an exception

when in step 2 of the upload process, if an item specific category is added 
that uses a
metadata field that has not been used in the metadata mapping, the application 
will throw
an exception because the metadata field is not in 
Mapping->target_dom_elements_mapped.

the solution implemented was to create an array that contains all first level 
elements of
the metadata record instead of only the targeted dom elements based on the 
metadata mapping.
a Metadata and MetadataPhpAdapter class were created that provide current use, 
storage and
retrieval of the new metadata array, and a place for future use, e.g., using 
ContentHandler
to store and retrieve metadata snippets

an issue with wikitext category generation was also corrected. the application 
was hard
coding the namespace name as Category: and not stripping out [] that might be 
in the metadata.
created \GWToolset\getNamespaceName() and 
\GWToolset\stripIllegalCategoryChars() to handle
these issues.

a few clean-up and cosmetic issues spotted in the affected files while working 
on these
issues were also addressed.

* GWToolset.i18n.php
  - got rid of bold around the gwtoolset-developer-issue key

* includes/Config.php
  - added $autoloader_classes
  - removed outdated $autoloader_classes
  - updated the version

* includes/Adapters/Php/MedtadataPhpAdapter.php
  - added file

* includes/Forms/MetadataDetectForm.php
  - changed the way the namespace name is found

* includes/Handlers/Forms/MetadataDetectHandler.php
  - added line breaks to code that is > 100 characters
  - removed unused use namespace FSFile

* includes/Handlers/Forms/MetadataMappingHandler.php
  - added in use of the new Metadata class
  - re-factored processMatchingElement() so that it incorporates the new 
Metadata class
    and uses an $options array instead of individual parameters

* includes/UploadHandler.php
  - added in use of the new Metadata class
  - re-factored wikitext category generation so that it uses 
\GWToolset\getNamespaceName()
    and \GWToolset\stripIllegalCategoryChars()
  - removed getMappedField() and and used Metadata->getConcatenatedField() 
instead for
    getting item specific category values
  - made a few @param types consistent with the rest of the application
  - removed @return {void}s
  - re-factored saveMediafileViaJob() so that it incorporates the new Metadata 
class and
    uses an $options array instead of individual parameters

* includes/Handlers/Xml/XmlMappingHandler.php
  - added getDOMElementAsArray() and addDOMElementToArray() to create the array 
version
    of the metadata to be used in the Metadata class

* includes/Jobs/UploadMediafileJob.php
  - added in use of the new Metadata class
  - adjusted validateParams() to the new $options array provided by 
saveMediaFileViaJob()

* includes/Models/Mapping.php
  - added in use of \GWToolset\getNamespaceName()

* includes/Models/Medtadata.php
  - added file

* includes/functions/functions.php
  - added getNamespaceName()
  - added stripIllegalCategoryChars()
  - adjusted spacing in a comment
  - made a few @param types consistent with the rest of the application
  - handleError() altered the comment and changed ErrorException to MWException

* re: #183/assembla - item specific categories throws an exception

Change-Id: I5b23b8af2d2c572af97ae179761b37091bab6a85
---
M GWToolset.i18n.php
A includes/Adapters/Php/MetadataPhpAdapter.php
M includes/Config.php
M includes/Forms/MetadataDetectForm.php
M includes/Forms/MetadataMappingForm.php
M includes/Handlers/UploadHandler.php
M includes/Handlers/Xml/XmlMappingHandler.php
M includes/Jobs/UploadMediafileJob.php
M includes/Models/Mapping.php
A includes/Models/Metadata.php
M includes/functions/functions.php
11 files changed, 425 insertions(+), 158 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/GWToolset 
refs/changes/27/90527/1

diff --git a/GWToolset.i18n.php b/GWToolset.i18n.php
index 72fdcfe..2af0daa 100644
--- a/GWToolset.i18n.php
+++ b/GWToolset.i18n.php
@@ -34,8 +34,8 @@
        'gwtoolset-could-not-open-xml' => 'Could not open the XML File for 
reading.',
        'gwtoolset-developer-issue' => "Please contact a developer; they will 
need to address this issue before you can continue.
 
-'''$1'''",
-       'gwtoolset-dom-record-issue' => '<code>record-element-name</code>, or 
<code>record-count</code> not provided.',
+$1",
+       'gwtoolset-dom-record-issue' => '<code>record-element-name</code>, or 
<code>record-count</code> or <code>record-current</code> not provided.',
        'gwtoolset-ignorewarnings' => '<code>ignorewarnings</code> not set.',
        'gwtoolset-no-accepted-types' => 'No accepted types provided',
        'gwtoolset-no-callback' => 'No callback passed to this method.',
@@ -53,6 +53,7 @@
        'gwtoolset-no-title' => 'No title provided.',
        'gwtoolset-no-upload-handler' => 'No upload handler was created.',
        'gwtoolset-no-upload-media' => 
"<code>user_options['upload-media']</code> not set.",
+       'gwtoolset-no-url-to-evaluate' => 'No URL was provided for evaluation.',
        'gwtoolset-no-url-to-media' => '<code>url-to-the-media-file</code> not 
set.',
        'gwtoolset-no-user' => 'no user object provided.',
        'gwtoolset-no-xml-element' => 'No XMLReader or DOMElement provided.',
@@ -280,7 +281,7 @@
        'gwtoolset-desc' => 
'{{desc|name=GWToolset|url=https://www.mediawiki.org/wiki/Extension:GWToolset}}',
        'gwtoolset-developer-issue' => "A user-friendly message that lets the 
user know that something went wrong that a developer will need to fix. The 
single parameter takes a message that explains a bit more to the developer what 
the issue may be.",
        'gwtoolset-disk-write-failure' => 'User error message that appears when 
the uploaded file failed to write to disk.',
-       'gwtoolset-dom-record-issue' => 'Hint to the developer that appears 
when record-element-name, or record-count not provided.',
+       'gwtoolset-dom-record-issue' => 'Hint to the developer that appears 
when record-element-name, or record-count or record-current not provided.',
        'gwtoolset-ensure-well-formed-xml' => 'Additional instructions that 
will help the user make sure the XML File is well-formed.',
        'gwtoolset-example-record' => 'Label for the metadata example record.',
        'gwtoolset-file-interpretation-error' => 'Heading that appears when 
there was a problem interpreting the metadata file.',
@@ -347,6 +348,7 @@
        'gwtoolset-no-title' => 'Hint to the developer that appears when no 
title is provided.',
        'gwtoolset-no-upload-handler' => 'Hint to the developer that appears 
when no upload handler was created.',
        'gwtoolset-no-upload-media' => "Hint to the developer that appears when 
user_options['upload-media'] is not set.",
+       'gwtoolset-no-url-to-evaluate' => 'Message that appears when no URL was 
provided for evaluation.',
        'gwtoolset-no-url-to-media' => 'Hint to the developer that appears when 
url-to-the-media-file is not set.',
        'gwtoolset-no-user' => 'Hint to the developer that appears when no user 
object is provided.',
        'gwtoolset-no-xml-element' => 'Hint to the developer that appears when 
no XMLReader or DOMElement is provided.',
diff --git a/includes/Adapters/Php/MetadataPhpAdapter.php 
b/includes/Adapters/Php/MetadataPhpAdapter.php
new file mode 100644
index 0000000..857a4df
--- /dev/null
+++ b/includes/Adapters/Php/MetadataPhpAdapter.php
@@ -0,0 +1,38 @@
+<?php
+/**
+ * GWToolset
+ *
+ * @file
+ * @ingroup Extensions
+ * @license GNU General Public License 3.0 http://www.gnu.org/licenses/gpl.html
+ */
+
+namespace GWToolset\Adapters\Php;
+use GWToolset\Adapters\DataAdapterInterface;
+
+class MetadataPhpAdapter implements DataAdapterInterface {
+
+       /**
+        * @param {array} $options
+        */
+       public function create( array $options = array() ) {
+       }
+
+       /**
+        * @param {array} $options
+        */
+       public function delete( array $options = array() ) {
+       }
+
+       /**
+        * @param {array} $options
+        */
+       public function retrieve( array $options = array() ) {
+       }
+
+       /**
+        * @param {array} $options
+        */
+       public function update( array $options = array() ) {
+       }
+}
diff --git a/includes/Config.php b/includes/Config.php
index f33fa61..548b2f7 100644
--- a/includes/Config.php
+++ b/includes/Config.php
@@ -16,7 +16,7 @@
        public static $url = 
'https://www.mediawiki.org/wiki/Extension:GWToolset';
        public static $descriptionmsg = 'gwtoolset-desc';
        public static $type = 'media';
-       public static $version = '0.1.0';
+       public static $version = '0.1.1';
 
        /**
         * @var {array}
@@ -56,6 +56,7 @@
 
                'GWToolset\Adapters\Php\MappingPhpAdapter' => 
'/includes/Adapters/Php/MappingPhpAdapter.php',
                'GWToolset\Adapters\Php\MediawikiTemplatePhpAdapter' => 
'/includes/Adapters/Php/MediawikiTemplatePhpAdapter.php',
+               'GWToolset\Adapters\Php\MetadataPhpAdapter' => 
'/includes/Adapters/Php/MetadataPhpAdapter.php',
 
                'GWToolset\Forms\MetadataDetectForm' => 
'/includes/Forms/MetadataDetectForm.php',
                'GWToolset\Forms\MetadataMappingForm' => 
'/includes/Forms/MetadataMappingForm.php',
@@ -86,8 +87,7 @@
 
                'GWToolset\Models\Mapping' => '/includes/Models/Mapping.php',
                'GWToolset\Models\MediawikiTemplate' => 
'/includes/Models/MediawikiTemplate.php',
-               'GWToolset\Models\Menu' => '/includes/Models/Menu.php',
-               'GWToolset\Models\ModelAbstract' => 
'/includes/Models/ModelAbstract.php',
+               'GWToolset\Models\Metadata' => '/includes/Models/Metadata.php',
                'GWToolset\Models\ModelInterface' => 
'/includes/Models/ModelInterface.php',
 
                'GWToolset\SpecialGWToolset' => 
'/includes/Specials/SpecialGWToolset.php',
@@ -246,6 +246,7 @@
                        'gwtoolset-cancel'
                ),
                'dependencies' => array(
+                       'jquery.json',
                        'jquery.spinner',
                        'jquery.ui.widget',
                        'jquery.ui.button',
@@ -279,7 +280,7 @@
 
        /**
         * @see SpecialPage __constructor
-        * @var {boolean}
+        * @var {bool}
         * whether the page is listed in Special:Specialpages
         */
        public static $special_page_listed = true;
@@ -307,14 +308,14 @@
        public static $title_separator = '-';
 
        /**
-        * @var {boolean}
+        * @var {bool}
         * tells the upload form to place the $accepted_mime_types in a comma
         * delimited list in the input file’s accept attribute
         */
        public static $use_file_accept_attribute = true;
 
        /**
-        * @var {boolean}
+        * @var {bool}
         */
        public static $use_UploadStash = true;
 
diff --git a/includes/Forms/MetadataDetectForm.php 
b/includes/Forms/MetadataDetectForm.php
index 1cdd77c..6bde13d 100644
--- a/includes/Forms/MetadataDetectForm.php
+++ b/includes/Forms/MetadataDetectForm.php
@@ -28,8 +28,7 @@
         * an html form
         */
        public static function getForm( SpecialPage $SpecialPage ) {
-               $namespace = $SpecialPage->getLanguage()->getNamespaces();
-               $namespace = $namespace[Config::$metadata_namespace] . ':';
+               $namespace = \GWToolset\getNamespaceName( 
Config::$metadata_namespace );
                $MediawikiTemplate = new MediawikiTemplate( new 
MediawikiTemplatePhpAdapter() );
 
                return
diff --git a/includes/Forms/MetadataMappingForm.php 
b/includes/Forms/MetadataMappingForm.php
index 220fad9..65a3ba8 100644
--- a/includes/Forms/MetadataMappingForm.php
+++ b/includes/Forms/MetadataMappingForm.php
@@ -320,7 +320,7 @@
 
                        Html::rawElement(
                                'table',
-                               array(),
+                               array( 'id' => 'global-categories-table' ),
                                Html::rawElement(
                                        'tbody',
                                        array(),
@@ -370,7 +370,7 @@
 
                        Html::rawElement(
                                'table',
-                               array(),
+                               array( 'id' => 'item-specific-categories-table' 
),
                                Html::rawElement(
                                        'thead',
                                        array(),
diff --git a/includes/Handlers/UploadHandler.php 
b/includes/Handlers/UploadHandler.php
index 306c481..fba9cb6 100644
--- a/includes/Handlers/UploadHandler.php
+++ b/includes/Handlers/UploadHandler.php
@@ -17,6 +17,7 @@
        GWToolset\Jobs\UploadFromUrlJob,
        GWToolset\Models\Mapping,
        GWToolset\Models\MediawikiTemplate,
+       GWToolset\Models\Metadata,
        JobQueueGroup,
        Linker,
        LocalRepo,
@@ -48,6 +49,11 @@
         * @var {MediawikiTemplate}
         */
        protected $_MediawikiTemplate;
+
+       /**
+        * @var {Metadata}
+        */
+       protected $_Metadata;
 
        /**
         * @var {SpecialPage}
@@ -88,7 +94,6 @@
 
        /**
         * @param {array} $options
-        * @return {void}
         */
        public function __construct( array $options = array() ) {
                $this->reset();
@@ -103,6 +108,10 @@
 
                if ( isset( $options['MediawikiTemplate'] ) ) {
                        $this->_MediawikiTemplate = 
$options['MediawikiTemplate'];
+               }
+
+               if ( isset( $options['Metadata'] ) ) {
+                       $this->_Metadata = $options['Metadata'];
                }
 
                if ( isset( $options['SpecialPage'] ) ) {
@@ -153,7 +162,11 @@
                        $categories = explode( Config::$category_separator, 
$this->user_options['categories'] );
 
                        foreach ( $categories as $category ) {
-                               $result .= '[[Category:' . Filter::evaluate( 
$category ) . ']]';
+                               $result .=
+                                               '[[' .
+                                                       
\GWToolset\getNamespaceName( NS_CATEGORY ) .
+                                                       
\GWToolset\stripIllegalCategoryChars( Filter::evaluate( $category ) ) .
+                                               ']]';
                        }
                }
 
@@ -187,13 +200,19 @@
                                }
 
                                if ( !empty( 
$this->user_options['category-metadata'][$i] ) ) {
-                                       $metadata = Filter::evaluate(
-                                               $this->getMappedField( 
$this->user_options['category-metadata'][$i] )
-                                       );
+                                       $metadata =
+                                               
$this->_Metadata->getConcatenatedField(
+                                                       
$this->user_options['category-metadata'][$i]
+                                               );
                                }
 
                                if ( !empty( $metadata ) ) {
-                                       $result .= '[[Category:' .  $phrase . 
$metadata . ']]';
+                                       $result .=
+                                               '[[' .
+                                                       
\GWToolset\getNamespaceName( NS_CATEGORY ) .
+                                                       
\GWToolset\stripIllegalCategoryChars( $phrase ) .
+                                                       
\GWToolset\stripIllegalCategoryChars( $metadata ) .
+                                               ']]';
                                }
                        }
                }
@@ -208,7 +227,6 @@
         *
         * @param {array} $accepted_types
         * @throws {MWException}
-        * @return {void}
         */
        protected function augmentAllowedExtensions( array $accepted_types = 
array() ) {
                global $wgFileExtensions;
@@ -269,6 +287,13 @@
        protected function evaluateMediafileUrl( $url ) {
                $result = array( 'content-type' => null, 'extension' => null, 
'url' => null );
                $pathinfo = array();
+
+               if ( empty( $url ) ) {
+                       throw new MWException(
+                               __METHOD__ . ' ' .
+                               wfMessage( 'gwtoolset-no-url-to-evaluate' 
)->escaped()
+                       );
+               }
 
                $Http = MWHttpRequest::factory(
                        $url,
@@ -359,32 +384,6 @@
        }
 
        /**
-        * @param {string} $field
-        *
-        * @return {string}
-        * the string is not filtered
-        */
-       protected function getMappedField( $field ) {
-               $result = null;
-
-               foreach ( $this->_Mapping->target_dom_elements_mapped[$field] 
as $targeted_field ) {
-                       $parameter_as_id = 
$this->_MediawikiTemplate->getParameterAsId( $targeted_field );
-
-                       if ( array_key_exists(
-                                       $targeted_field, 
$this->_MediawikiTemplate->mediawiki_template_array )
-                       ) {
-                               $result .= 
$this->_MediawikiTemplate->mediawiki_template_array[$targeted_field] . ' ';
-                       } elseif ( array_key_exists(
-                                       $parameter_as_id, 
$this->_MediawikiTemplate->mediawiki_template_array )
-                       ) {
-                               $result .= 
$this->_MediawikiTemplate->mediawiki_template_array[$parameter_as_id] . ' ';
-                       }
-               }
-
-               return $result;
-       }
-
-       /**
         * creates the wiki text for the media file page.
         * concatenates several pieces of information in order to create the 
wiki
         * text for the mediafile wiki text
@@ -401,13 +400,13 @@
        }
 
        /**
-        * @param {Array} $options
+        * @param {string} $title
         * @throws {MWException}
         * @return {Title}
         */
-       protected function getTitle( array &$options ) {
+       protected function getTitle( $title ) {
                $result = \GWToolset\getTitle(
-                       \GWToolset\stripIllegalTitleChars( $options['title'] ),
+                       \GWToolset\stripIllegalTitleChars( $title ),
                        Config::$mediafile_namespace,
                        array( 'must-be-known' => false )
                );
@@ -415,7 +414,7 @@
                if ( !( $result instanceof Title ) ) {
                        throw new MWException(
                                wfMessage( 'gwtoolset-title-bad' )
-                                       ->params( $options['title'] )->parse()
+                                       ->params( $title )->parse()
                        );
                }
 
@@ -486,9 +485,6 @@
                return $result;
        }
 
-       /**
-        * @return {void}
-        */
        public function reset() {
                $this->_File = null;
                $this->_Mapping = null;
@@ -505,7 +501,6 @@
         * restores the wiki’s allowed extensions array
         *
         * @param {array} $accepted_types
-        * @return {void}
         */
        protected function restoreAllowedExtensions( array $accepted_types = 
array() ) {
                global $wgFileExtensions;
@@ -594,15 +589,16 @@
        }
 
        /**
-        * controls the workflow for saving media files
+        * @todo does ContentHandler filter $options['text']?
+        * @todo does WikiPage filter $options['comment']?
         *
         * @param {array} $user_options
-        * an array of user options that was submitted in the html form
-        *
+        * @throws {MWException}
         * @return {null|Title}
         */
-       public function saveMediaFile( array &$user_options ) {
-               $result = null;
+       public function saveMediafileAsContent( array &$user_options ) {
+               $Title = null;
+               $Status = null;
                $options = array();
 
                $this->validateUserOptions( $user_options );
@@ -625,27 +621,9 @@
 
                $options['text'] = $this->getText();
 
-               if ( $this->user_options['save-as-batch-job'] ) {
-                       $Status = $this->saveMediafileViaJob( $options );
-               } else {
-                       $result = $this->saveMediafileAsContent( $options );
-               }
-
-               return $result;
-       }
-
-       /**
-        * @todo does ContentHandler filter $options['text']?
-        * @todo does WikiPage filter $options['comment']?
-        * @param {array} $options
-        * @throws {MWException}
-        * @return {Title}
-        */
-       public function saveMediafileAsContent( array &$options ) {
-               $Status = null;
                WikiChecks::increaseHTTPTimeout();
                $this->validatePageOptions( $options );
-               $Title = $this->getTitle( $options );
+               $Title = $this->getTitle( $options['title'] );
 
                if ( !$Title->isKnown() ) {
                        $Status = $this->uploadMediaFileViaUploadFromUrl( 
$options, $Title );
@@ -670,10 +648,19 @@
        }
 
        /**
+        * save a metadata record as a new/updated wiki page
+        *
+        * @param {array} $user_options
+        * an array of user options that was submitted in the html form
+        *
         * @param {array} $options
+        *   {array} $options['metadata-mapped-to-mediawiki-template']
+        *   {array} $options['metadata-as-array']
+        *   {string} $options['metadata-raw']
+        *
         * @return {bool}
         */
-       protected function saveMediafileViaJob( array &$options ) {
+       public function saveMediafileViaJob( array &$user_options, array 
$options ) {
                $result = false;
                $job = null;
                $sessionKey = null;
@@ -682,20 +669,17 @@
                        return;
                }
 
-               $this->validatePageOptions( $options );
-               $Title = $this->getTitle( $options );
+               $this->validateUserOptions( $user_options );
 
                $job = new UploadMediafileJob(
-                       $Title,
+                       Title::newFromText(
+                       'User:' . $this->_User->getName() . '/' . Config::$name 
. ' Mediafile Batch Job'
+                       ),
                        array(
-                               'comment' => $options['comment'],
-                               'ignorewarnings' => $options['ignorewarnings'],
-                               'text' => $options['text'],
-                               'title' => $options['title'],
-                               'url-to-the-media-file' => 
$options['url-to-the-media-file'],
-                               'username' => $this->_User->getName(),
-                               'user_options' => $this->user_options,
-                               'watch' => $options['watch']
+                               'options' => $options,
+                               'post' => $_POST,
+                               'user-name' => $this->_User->getName(),
+                               'user-options' => $user_options
                        )
                );
 
@@ -781,7 +765,6 @@
         *
         * @param {array} $options
         * @throws {MWException}
-        * @return {void}
         */
        protected function validatePageOptions( array &$options ) {
                if ( !isset( $options['ignorewarnings'] ) ) {
@@ -819,7 +802,6 @@
        /**
         * @param {array} $options
         * @throws {MWException}
-        * @return {void}
         */
        protected function validateUserOptions( array &$user_options ) {
                if ( !isset( $user_options['comment'] ) ) {
diff --git a/includes/Handlers/Xml/XmlMappingHandler.php 
b/includes/Handlers/Xml/XmlMappingHandler.php
index 0e21c4c..2df9283 100644
--- a/includes/Handlers/Xml/XmlMappingHandler.php
+++ b/includes/Handlers/Xml/XmlMappingHandler.php
@@ -66,6 +66,53 @@
        }
 
        /**
+        * helper method for getDOMElementAsArray()
+        *
+        * @param {array} $array
+        * @param {DOMElement} $DOMElement
+        */
+       protected function addDOMElementToArray( array &$array, DOMElement 
$DOMElement ) {
+               $is_url = strpos( $DOMElement->nodeValue, '://' ) !== false;
+               $array[] = $this->getFilteredNodeValue( $DOMElement, $is_url );
+
+               if ( $DOMElement->hasAttributes() ) {
+                       foreach ( $DOMElement->attributes as $attribute ) {
+                               $array['@attributes'][$attribute->name] = 
$attribute->value;
+                       }
+               }
+       }
+
+       /**
+        * creates an array based on the dom element provided
+        *   - only goes 1 level down
+        *   - assigns the element name as the array index
+        *   - adds values as an array to the element name index
+        *
+        * we’re using this method instead of a SimpleXMLElement object because 
we have found that some
+        * metadata sources use XML namespaces without declaring them within 
the XML document, which
+        * requires additional logic to sort out the namespaced elements that 
may not be reliable
+        *
+        * @param {DOMElement} $DOMElement
+        * @return {array}
+        */
+       protected function getDOMElementAsArray( DOMElement $DOMElement ) {
+               $result = array();
+
+               foreach ( $DOMElement->childNodes as $childNode ) {
+                       if ( $childNode->nodeType === XML_ELEMENT_NODE ) {
+                               if ( !isset( $result[$childNode->tagName] ) ) {
+                                       $result[$childNode->tagName] = array();
+                                       $this->addDOMElementToArray( 
$result[$childNode->tagName], $childNode );
+                               } else {
+                                       $this->addDOMElementToArray( 
$result[$childNode->tagName], $childNode );
+                               }
+                       }
+               }
+
+               return $result;
+       }
+
+       /**
         * takes in a metadata dom element that represents a targeted
         * record within the metadata that will be saved/updated in the
         * wiki as a wiki page and maps it to the mediawiki template
@@ -81,6 +128,7 @@
         * getting the NS is not always straightforward
         *
         * @todo possibly filter keys and values
+        * @todo possibly refactor so that it works with getDOMElementAsArray
         *
         * @param {DOMELement} $DOMElement
         *
@@ -206,7 +254,7 @@
         *
         * @return {array}
         * - $result['Title'] {Title}
-        * - $result['stop-reading'] {boolean}
+        * - $result['stop-reading'] {bool}
         */
        protected function processDOMElements( $XMLElement, array 
&$user_options ) {
                $result = array( 'Title' => null, 'stop-reading' => false );
@@ -225,6 +273,7 @@
 
                if ( !isset( $user_options['record-element-name'] )
                        || !isset( $user_options['record-count'] )
+                       || !isset( $user_options['record-current'] )
                ) {
                        throw new MWException(
                                wfMessage( 'gwtoolset-developer-issue' )
@@ -248,24 +297,30 @@
                                }
 
                                if ( !empty( $record ) ) {
-                                       $user_options['record-count'] += 1;
+                                       $user_options['record-current'] += 1;
 
-                                       // don’t process the element if the 
record count is not >=
-                                       // the record nr we should start 
processing on
-                                       if ( $user_options['record-count'] < 
$user_options['record-begin'] ) {
+                                       // don’t process the element if the 
current record nr is <
+                                       // the record nr we should begin 
processing on
+                                       if ( $user_options['record-current'] < 
$user_options['record-begin'] ) {
                                                break;
                                        }
 
-                                       // stop processing if the record count 
is > the record nr we should
-                                       // start processing on plus the job 
throttle
-                                       if ( $user_options['record-count'] > 
$user_options['record-begin'] + Config::$job_throttle ) {
+                                       // stop processing if the current 
record nr is >=
+                                       // the record nr we should begin 
processing on plus the job throttle
+                                       if ( $user_options['record-current']
+                                               >= 
$user_options['record-begin'] + Config::$job_throttle
+                                       ) {
                                                $result['stop-reading'] = true;
                                                break;
                                        }
 
                                        $result['Title'] = 
$this->_MappingHandler->processMatchingElement(
-                                               $user_options, 
$this->getDOMElementMapped( $record ),
-                                               $outer_xml
+                                               $user_options,
+                                               array(
+                                                       'metadata-as-array' => 
$this->getDOMElementAsArray( $record ),
+                                                       
'metadata-mapped-to-mediawiki-template' => $this->getDOMElementMapped( $record 
),
+                                                       'metadata-raw' => 
$outer_xml
+                                               )
                                        );
                                }
 
diff --git a/includes/Jobs/UploadMediafileJob.php 
b/includes/Jobs/UploadMediafileJob.php
index 7044554..6ea182c 100644
--- a/includes/Jobs/UploadMediafileJob.php
+++ b/includes/Jobs/UploadMediafileJob.php
@@ -8,27 +8,18 @@
  */
 
 namespace GWToolset\Jobs;
-use GWToolset\Handlers\UploadHandler,
+use GWToolset\Adapters\Php\MappingPhpAdapter,
+       GWToolset\Adapters\Php\MediawikiTemplatePhpAdapter,
+       GWToolset\Adapters\Php\MetadataPhpAdapter,
+       GWToolset\Models\Mapping,
+       GWToolset\Models\MediawikiTemplate,
+       GWToolset\Models\Metadata,
+       GWToolset\Handlers\UploadHandler,
        MWException,
        Job,
        User;
 
 class UploadMediafileJob extends Job {
-
-       /**
-        * {UploadHandler}
-        */
-       protected $_UploadHandler;
-
-       /**
-        * @var {User}
-        */
-       protected $_User;
-
-       /**
-        * @var {string}
-        */
-       public $filename_metadata;
 
        /**
         * @param {Title} $title
@@ -41,38 +32,50 @@
        }
 
        /**
+        * a control method for re-establishing application state so that the 
metadata can be processed.
+        * this is similar to MetadataMappingHandler::processMetadata(), 
however it avoids the necessity
+        * to process the metadata file
+        *
+        * @todo re-factor so that this is able to use 
MetadataMappingHandler::processMetadata(). will
+        * need to add some logic to it so that if a batch job is being process 
it doesn't display a form
+        * or process the metadata again
+        *
         * @return {bool|Title}
         */
        protected function processMetadata() {
                $result = false;
+               $_POST = $this->params['post'];
 
-               $this->_UploadHandler = new UploadHandler(
+               $MediawikiTemplate = new MediawikiTemplate( new 
MediawikiTemplatePhpAdapter() );
+               $MediawikiTemplate->getMediaWikiTemplate( 
$this->params['user-options'] );
+
+               $Mapping = new Mapping( new MappingPhpAdapter() );
+               $Mapping->mapping_array = 
$MediawikiTemplate->getMappingFromArray( $_POST );
+               $Mapping->setTargetElements();
+               $Mapping->reverseMap();
+
+               $Metadata = new Metadata( new MetadataPhpAdapter() );
+
+               $User = User::newFromName( $this->params['user-name'] );
+
+               $UploadHandler = new UploadHandler(
                        array(
-                               'User' => $this->_User
+                               'Mapping' => $Mapping,
+                               'MediawikiTemplate' => $MediawikiTemplate,
+                               'Metadata' => $Metadata,
+                               'User' => $User,
                        )
                );
 
-               $this->_UploadHandler->user_options = 
$this->params['user_options'];
-               $result = $this->_UploadHandler->saveMediafileAsContent( 
$this->params );
+               $MediawikiTemplate->metadata_raw = 
$this->params['options']['metadata-raw'];
+               $MediawikiTemplate->populateFromArray(
+                       
$this->params['options']['metadata-mapped-to-mediawiki-template']
+               );
 
-               return $result;
-       }
+               $Metadata->metadata_raw = 
$this->params['options']['metadata-raw'];
+               $Metadata->metadata_as_array = 
$this->params['options']['metadata-as-array'];
 
-       /**
-        * @return {bool}
-        */
-       protected function validateParams() {
-               $result = true;
-
-               if ( empty( $this->params['username'] ) ) {
-                       error_log( __METHOD__ . ' : no 
$this->params[\'username\'] provided' . PHP_EOL );
-                       $result = false;
-               }
-
-               if ( empty( $this->params['user_options'] ) ) {
-                       error_log( __METHOD__ . ' : no 
$this->params[\'user_options\'] provided' . PHP_EOL );
-                       $result = false;
-               }
+               $result = $UploadHandler->saveMediafileAsContent( 
$this->params['user-options'] );
 
                return $result;
        }
@@ -89,16 +92,53 @@
                        return $result;
                }
 
-               $this->_User = User::newFromName( $this->params['username'] );
-
                try {
                        $result = $this->processMetadata();
                } catch ( MWException $e ) {
-                       error_log( $e->getMessage() );
+                       $this->setLastError(
+                               __METHOD__ . ': ' .
+                               $e->getMessage() .
+                               print_r( $this->params['user-options'], true )
+                       );
                }
 
-               if ( !$result ) {
-                       error_log( "Could not save [ {$this->params['title']} ] 
to the wiki." );
+               return $result;
+       }
+
+       /**
+        * @return {bool}
+        */
+       protected function validateParams() {
+               $result = true;
+
+               if ( empty( $this->params['options'] ) ) {
+                       $this->setLastError( __METHOD__ . ': no 
$this->params[\'options\'] provided' );
+                       $result = false;
+               }
+
+               if ( empty( 
$this->params['options']['metadata-mapped-to-mediawiki-template'] ) ) {
+                       $this->setLastError(
+                               __METHOD__ .
+                               ': no 
$this->params[\'options\'][\'metadata-mapped-to-mediawiki-template\'] provided'
+                       );
+                       $result = false;
+               }
+
+               if ( empty( $this->params['options']['metadata-raw'] ) ) {
+                       $this->setLastError(
+                               __METHOD__ . ': no 
$this->params[\'options\'][\'metadata-raw\'] provided'
+                       );
+                       $result = false;
+               }
+
+               if ( empty( $this->params['user-name'] ) ) {
+                       $this->setLastError( __METHOD__ . ': no 
$this->params[\'user-name\'] provided' );
+                       $result = false;
+               }
+
+               if ( empty( $this->params['user-options'] ) ) {
+                       $this->setLastError( __METHOD__ . ': no 
$this->params[\'user-options\'] provided' );
+                       $result = false;
                }
 
                return $result;
diff --git a/includes/Models/Mapping.php b/includes/Models/Mapping.php
index 3618f3b..5ba42e3 100644
--- a/includes/Models/Mapping.php
+++ b/includes/Models/Mapping.php
@@ -108,18 +108,13 @@
         * relies on a hardcoded path to the metadata mapping url
         *
         * @param {array} $options
-        *
         * @throws {MWException}
-        *
         * @return {string}
         * the string is not filtered
         */
        protected function getMappingName( array $options ) {
                $result = null;
-
-               $Languages = new Language();
-               $namespace = $Languages->getNamespaces();
-               $namespace = $namespace[Config::$metadata_namespace] . ':';
+               $namespace = \GWToolset\getNamespaceName( 
Config::$metadata_namespace );
 
                if ( !empty( $options['Metadata-Mapping-Title'] ) ) {
                        $result = str_replace(
diff --git a/includes/Models/Metadata.php b/includes/Models/Metadata.php
new file mode 100644
index 0000000..0607c47
--- /dev/null
+++ b/includes/Models/Metadata.php
@@ -0,0 +1,114 @@
+<?php
+/**
+ * GWToolset
+ *
+ * @file
+ * @ingroup Extensions
+ * @license GNU General Public License 3.0 http://www.gnu.org/licenses/gpl.html
+ */
+
+namespace GWToolset\Models;
+use GWToolset\Adapters\DataAdapterInterface,
+       GWToolset\Config,
+       Php\Filter;
+
+class Metadata implements ModelInterface {
+       /**
+        * @var {array}
+        */
+       public $metadata_as_array;
+
+       /**
+        * @var {string}
+        * a raw representation of the original metadata
+        */
+       public $metadata_raw;
+
+       /**
+        * @var {DataAdapterInterface}
+        */
+       protected $_DataAdapater;
+
+       /**
+        * @param {DataAdapterInterface} $DataAdapter
+        */
+       public function __construct( DataAdapterInterface $DataAdapter ) {
+               $this->reset();
+               $this->_DataAdapater = $DataAdapter;
+       }
+
+       /**
+        * @param {array} $options
+        */
+       public function create( array $options = array() ) {
+       }
+
+       /**
+        * @param {array} $options
+        */
+       public function delete( array &$options = array() ) {
+       }
+
+       /**
+        * locates an element within the metadata and concatenates its values 
when there is more than
+        * one of the same element within the metadata
+        *
+        * @todo should we cache the concatenated fields or pre-populate all of 
them?
+        *
+        * @param {string}
+        *
+        * @return {null|string}
+        * the string is filtered
+        */
+       public function getConcatenatedField( $field = null ) {
+               $result = null;
+
+               if ( empty( $field ) || !is_string( $field ) ) {
+                       return $result;
+               }
+
+               if ( array_key_exists( $field, $this->metadata_as_array ) ) {
+                       foreach ( $this->metadata_as_array[$field] as $key => 
$value ) {
+                               if ( $key === '@attributes' ) {
+                                       continue;
+                               }
+
+                               if ( strpos( $value, '://' ) !== false ) {
+                                       $result .=
+                                               Filter::evaluate(
+                                                       array(
+                                                               'source' => 
$value,
+                                                               
'filter-sanitize' => FILTER_SANITIZE_URL
+                                                       )
+                                               ) .
+                                               Config::$metadata_separator .
+                                               ' ';
+                               } else {
+                                       $result .= Filter::evaluate( $value ) . 
Config::$metadata_separator . ' ';
+                               }
+                       }
+               }
+
+               $result = rtrim( $result, Config::$metadata_separator );
+
+               return $result;
+       }
+
+       public function reset() {
+               $this->metadata_as_array = array();
+               $this->metadata_raw = null;
+               $this->_DataAdapater = null;
+       }
+
+       /**
+        * @param {array} $options
+        */
+       public function retrieve( array &$options = array() ) {
+       }
+
+       /**
+        * @param {array} $options
+        */
+       public function update( array &$options = array() ) {
+       }
+}
diff --git a/includes/functions/functions.php b/includes/functions/functions.php
index c778330..faf6b26 100644
--- a/includes/functions/functions.php
+++ b/includes/functions/functions.php
@@ -69,13 +69,37 @@
 }
 
 /**
+ * based on a namespace number, returns the namespace name
+ *
+ * @param {int} $namespace
+ * @return {null|string}
+ * the result is not filtered
+ */
+function getNamespaceName( $namespace = 0 ) {
+       $result = null;
+
+       if ( !is_int( $namespace ) ) {
+               return $result;
+       }
+
+       $Languages = new Language();
+       $namespaces = $Languages->getNamespaces();
+
+       if ( isset( $namespaces[$namespace] ) ) {
+               $result = $namespaces[$namespace] . ':';
+       }
+
+       return $result;
+}
+
+/**
  * attempts to retrieve a wiki title based on a given page title, an
  * optional namespace requirement and whether or not the title must be known
  *
- * @param {String} $page_title
+ * @param {string} $page_title
  * @param {Int} $namespace
- * @param {Array} $options
- *   {Boolean} $options['must-be-known']
+ * @param {array} $options
+ *   {boolean} $options['must-be-known']
  *   Whether or not the Title must be known; defaults to true
  *
  * @throws {MWException}
@@ -138,6 +162,23 @@
 }
 
 /**
+ * @param {string} $category
+ * @return {null|string}
+ * the result has not been filtered
+ */
+function stripIllegalCategoryChars( $category = null ) {
+       $result = null;
+
+       if ( empty( $category ) || !is_string( $category ) ) {
+               return $result;
+       }
+
+       $result = str_replace( array( '[', ']' ), '', $category );
+
+       return $result;
+}
+
+/**
  * replaces illegal characters in a title with a replacement character, 
defaults to ‘-’.
  * illegal characters are based on Commons:File_naming and other bad title 
articles.
  * Title::secureAndSplit() allows some of these characters.
@@ -150,10 +191,10 @@
  * @param {string} $title
  *
  * @param {array} $options
- *   {Boolean} $options['allow-subpage']
+ *   {boolean} $options['allow-subpage']
  *   allows for the ‘/’ subpage character
  *
- *   {String} $options['replacement']
+ *   {string} $options['replacement']
  *   the character used to replace illegal characters; defaults to ‘-’
  *
  * @return {string} the string is not filtered
@@ -184,8 +225,8 @@
 
 /**
  * wfSuppressWarnings() lowers the error_reporting threshold because the
- * script that follows it is “allowed” to produce warnings,    thus, only
- * handle errors this way when error_reporting is set to >= E_ALL
+ * script that follows it is “allowed” to produce warnings, thus, only
+ * throw an exception when error_reporting is set to >= E_ALL
  *
  * @param {int} $errno
  * @param {string} $errstr
@@ -203,7 +244,7 @@
 
                if ( $errno > E_WARNING ) {
                        error_log( $errstr . ' in ' . $errfile . ' on line nr ' 
. $errline );
-                       throw new ErrorException( $errormsg, 0, $errno, 
$errfile, $errline );
+                       throw new MWException( $errormsg );
                } else {
                        echo $errormsg;
                }

-- 
To view, visit https://gerrit.wikimedia.org/r/90527
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I5b23b8af2d2c572af97ae179761b37091bab6a85
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/GWToolset
Gerrit-Branch: master
Gerrit-Owner: Dan-nl <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to