Foxtrott has uploaded a new change for review.

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

Change subject: Add StashingDOMDocument; error handling for invalid link targets
......................................................................

Add StashingDOMDocument; error handling for invalid link targets

Change-Id: I028ef68e6e73f55a58f7c46ccb72b6b54645cd5b
---
M extension.json
M i18n/en.json
M i18n/qqq.json
M src/Element.php
M src/Lingo.php
M src/LingoParser.php
A src/StashingDOMDocument.php
7 files changed, 126 insertions(+), 31 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/Lingo 
refs/changes/81/280581/1

diff --git a/extension.json b/extension.json
index 688f010..3d9ca13 100644
--- a/extension.json
+++ b/extension.json
@@ -67,6 +67,7 @@
                "Lingo\\Backend": "/src/Backend.php",
                "Lingo\\BasicBackend": "/src/BasicBackend.php",
                "Lingo\\MessageLog": "/src/MessageLog.php",
+               "Lingo\\StashingDOMDocument": "/src/StashingDOMDocument.php",
                "Lingo\\Tests\\Util\\XmlFileProvider": 
"/tests/phpunit/Util/XmlFileProvider.php"
        },
        "callback": "Lingo\\Lingo::initExtension",
diff --git a/i18n/en.json b/i18n/en.json
index b4904f7..10d3902 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -7,5 +7,6 @@
        "lingo-noterminologypage": "The terminology page \"$1\" does not 
exist.",
        "lingo-notatextpage": "The terminology page \"$1\" is not a text page.",
        "lingo-terminologypagenotlocal": "Page \"$1\" is not a local page.",
-       "lingo-noapprovedrevs": "Support for ApprovedRevs is enabled in Lingo. 
But ApprovedRevs was not found."
+       "lingo-noapprovedrevs": "Support for ApprovedRevs is enabled in Lingo. 
But ApprovedRevs was not found.",
+       "lingo-invalidlinktarget" : "Invalid link target for term \"$1\": $2"
 }
diff --git a/i18n/qqq.json b/i18n/qqq.json
index 3924b3a..e9f5079 100644
--- a/i18n/qqq.json
+++ b/i18n/qqq.json
@@ -10,5 +10,6 @@
        "lingo-noterminologypage": "Used as warning message. Parameters:\n* $1 
- terminology page title (value of <code>$wgexLingoPage</code>), or 
{{msg-mw|lingo-terminologypagename}}\nSee also:\n* 
{{msg-mw|lingo-terminologypagenotlocal}}",
        "lingo-notatextpage": "Used as error message. Parameters:\n* $1 - 
terminology page title (value of <code>$wgexLingoPage</code>), or 
{{msg-mw|lingo-terminologypagename}}\nSee also:\n* 
{{msg-mw|lingo-noterminologypage}}",
        "lingo-terminologypagenotlocal": "Used as error message. Parameters:\n* 
$1 - terminology page title (value of <code>$wgexLingoPage</code>), or 
{{msg-mw|lingo-terminologypagename}}\nSee also:\n* 
{{msg-mw|lingo-noterminologypage}}",
-       "lingo-noapprovedrevs": "Used as warning message when the ApprovedRevs 
extension is not installed."
+       "lingo-noapprovedrevs": "Used as warning message when the ApprovedRevs 
extension is not installed.",
+       "lingo-invalidlinktarget" : "Used as error message when the link target 
$2 is not a valid wiki page name."
 }
diff --git a/src/Element.php b/src/Element.php
index ba22f5a..b17f639 100644
--- a/src/Element.php
+++ b/src/Element.php
@@ -28,11 +28,10 @@
  */
 
 namespace Lingo;
-use DOMDocument;
+
 use DOMElement;
 use DOMNode;
 use DOMText;
-use MWException;
 use Title;
 
 /**
@@ -49,7 +48,9 @@
        const ELEMENT_STYLE = 4;
 
        const ELEMENT_FIELDCOUNT = 5;  // number of fields stored for each 
element; (last field's index) + 1
-       static private $mLinkTemplate = null;
+
+       const LINK_TEMPLATE_ID = 'LingoLink';
+
        private $mFullDefinition = null;
        private $mDefinitions = array();
        private $mTerm = null;
@@ -77,10 +78,10 @@
        }
 
        /**
-        * @param DOMDocument $doc
+        * @param StashingDOMDocument $doc
         * @return DOMNode|DOMText
         */
-       public function getFullDefinition( DOMDocument &$doc ) {
+       public function getFullDefinition( StashingDOMDocument &$doc ) {
 
                global $wgexLingoDisplayOnce;
 
@@ -95,10 +96,9 @@
        }
 
        /**
-        * @param DOMDocument $doc
-        * @return DOMDocument
+        * @param StashingDOMDocument $doc
         */
-       private function buildFullDefinition( DOMDocument &$doc ) {
+       private function buildFullDefinition( StashingDOMDocument &$doc ) {
 
                // only create if not yet created
                if ( $this->mFullDefinition === null || 
$this->mFullDefinition->ownerDocument !== $doc ) {
@@ -121,21 +121,29 @@
        }
 
        /**
-        * @param DOMDocument $doc
-        *
+        * @param StashingDOMDocument $doc
         * @return DOMElement
-        * @throws MWException
+        * @throws \MWException
         */
-       protected function getFullDefinitionAsLink( DOMDocument &$doc ) {
+       protected function getFullDefinitionAsLink( StashingDOMDocument &$doc ) 
{
 
                // create Title object for target page
                $target = Title::newFromText( $this->mDefinitions[ 0 ][ 
self::ELEMENT_LINK ] );
+
+               if ( !$target instanceof Title ) {
+                       $errorMessage = wfMessage( 'lingo-invalidlinktarget', 
$this->mTerm, $this->mDefinitions[ 0 ][ self::ELEMENT_LINK ] )->text();
+                       $errorDefinition = array( self::ELEMENT_DEFINITION => 
$errorMessage, self::ELEMENT_STYLE => 'invalid-link-target' );
+                       $this->addDefinition( $errorDefinition );
+                       return $this->getFullDefinitionAsTooltip( $doc );
+               }
 
                // create link element
                $link = $doc->createElement( 'a', $this->mDefinitions[ 0 ][ 
self::ELEMENT_TERM ] );
 
                // set the link target
                $link->setAttribute( 'href', $target->getLinkUrl() );
+
+
                $link = $this->addClassAttributeToLink( $target, $link );
                $link = $this->addTitleAttributeToLink( $target, $link );
 
@@ -145,6 +153,7 @@
        /**
         * @param $target
         * @param $link
+        * @return mixed
         */
        protected function &addClassAttributeToLink( $target, &$link ) {
 
@@ -152,18 +161,19 @@
                // Cleanest would probably be to use Linker::link and parse it
                // back into a DOMElement, but we are in a somewhat 
time-critical
                // part here.
-               $classes = '';
+
+               // set style
+               $classes = string( $this->mDefinitions[ 0 ][ 
self::ELEMENT_STYLE ] );
 
                if ( !$target->isKnown() ) {
-                       $classes .= 'new ';
+                       $classes .= ' new';
                }
 
                if ( $target->isExternal() ) {
-                       $classes .= 'extiw ';
+                       $classes .= ' extiw';
                }
 
-               // set style
-               $classes .= $this->mDefinitions[ 0 ][ self::ELEMENT_STYLE ];
+               $classes = trim( $classes );
 
                if ( $classes !== '' ) {
                        $link->setAttribute( 'class', $classes );
@@ -175,6 +185,7 @@
        /**
         * @param $target
         * @param $link
+        * @return mixed
         */
        protected function &addTitleAttributeToLink( $target, &$link ) {
 
@@ -191,12 +202,11 @@
        }
 
        /**
-        * @param DOMDocument $doc
-        *
+        * @param StashingDOMDocument $doc
         * @return string
-        * @throws MWException
+        * @throws \MWException
         */
-       protected function getFullDefinitionAsTooltip( DOMDocument &$doc ) {
+       protected function getFullDefinitionAsTooltip( StashingDOMDocument 
&$doc ) {
 
                // Wrap term and definition in <span> tags
                $span = $doc->createElement( 'span' );
@@ -238,22 +248,27 @@
        }
 
        /**
-        * @param DOMDocument $doc
+        * @param StashingDOMDocument $doc
         * @return DOMNode
         */
-       private function getLinkTemplate( DOMDocument &$doc ) {
+       private function getLinkTemplate( StashingDOMDocument &$doc ) {
+
+               $mLinkTemplate = $doc->stashGet( self::LINK_TEMPLATE_ID );
+
                // create template if it does not yet exist
-               if ( !self::$mLinkTemplate || ( 
self::$mLinkTemplate->ownerDocument !== $doc ) ) {
+               if ( $mLinkTemplate === null ) {
                        global $wgScriptPath;
 
                        $linkimage = $doc->createElement( 'img' );
                        $linkimage->setAttribute( 'src', $wgScriptPath . 
'/extensions/Lingo/styles/linkicon.png' );
 
-                       self::$mLinkTemplate = $doc->createElement( 'a' );
-                       self::$mLinkTemplate->appendChild( $linkimage );
+                       $mLinkTemplate = $doc->createElement( 'a' );
+                       $mLinkTemplate->appendChild( $linkimage );
+
+                       $doc->stashSet( $mLinkTemplate, self::LINK_TEMPLATE_ID 
);
                }
 
-               return self::$mLinkTemplate->cloneNode( true );
+               return $mLinkTemplate->cloneNode( true );
        }
 
        /**
diff --git a/src/Lingo.php b/src/Lingo.php
index e74db7c..9ff89ee 100644
--- a/src/Lingo.php
+++ b/src/Lingo.php
@@ -31,7 +31,7 @@
  * Class Lingo
  *
  * @package Lingo
- * @ingroup Skins
+ * @ingroup Lingo
  */
 class Lingo {
 
diff --git a/src/LingoParser.php b/src/LingoParser.php
index da4d039..5de6d42 100644
--- a/src/LingoParser.php
+++ b/src/LingoParser.php
@@ -230,7 +230,7 @@
                // Parse HTML from page
                \MediaWiki\suppressWarnings();
 
-               $doc = new DOMDocument( '1.0', 'utf-8' );
+               $doc = new StashingDOMDocument( '1.0', 'utf-8' );
                $doc->loadHTML( '<html><head><meta http-equiv="content-type" 
content="charset=utf-8"/></head><body>' . $text . '</body></html>' );
 
                \MediaWiki\restoreWarnings();
diff --git a/src/StashingDOMDocument.php b/src/StashingDOMDocument.php
new file mode 100644
index 0000000..74a2436
--- /dev/null
+++ b/src/StashingDOMDocument.php
@@ -0,0 +1,77 @@
+<?php
+/**
+ * File containing the StashingDOMDocument class
+ *
+ * @copyright (C) 2013 - 2016, Stephan Gambke
+ * @license   GNU General Public License, version 3 (or any later version)
+ *
+ * The Lingo extension is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by the 
Free
+ * Software Foundation, either version 3 of the License, or (at your option) 
any
+ * later version.
+ *
+ * The Lingo extension is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 
more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @file
+ * @ingroup Lingo
+ */
+
+namespace Lingo;
+
+/**
+ * Class StashingDOMDocument
+ *
+ * @package Lingo
+ * @ingroup Lingo
+ * @since 2.0.2
+ */
+class StashingDOMDocument extends \DOMDocument {
+
+       private $mStash = array();
+
+       /**
+        * @param \DOMElement $element
+        * @param null $key
+        * @return null
+        */
+       public function stashSet( \DOMElement $element, $key = null ) {
+               
+               if ( $key === null ) {
+                       $key = uniqid( '', true );
+               }
+
+               $this->mStash[ $key ] = $element;
+
+               return $key;
+       }
+
+       /**
+        * @param $key
+        * @return \DOMElement | null
+        */
+       public function stashGet( $key ) {
+               return @$this->mStash[ $key ];
+       }
+
+       /**
+        * @param $key
+        */
+       public function stashDelete( $key ) {
+               unset ( $this->mStash[ $key ] );
+       }
+
+       /**
+        * @param $key
+        * @return bool
+        */
+       public function isStashed ( $key ) {
+               return isset( $this->mStash[ $key ] );
+       }
+
+}

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

Gerrit-MessageType: newchange
Gerrit-Change-Id: I028ef68e6e73f55a58f7c46ccb72b6b54645cd5b
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/Lingo
Gerrit-Branch: master
Gerrit-Owner: Foxtrott <[email protected]>

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

Reply via email to