Completed
Push — master ( c18f14...017364 )
by mw
292:38 queued 257:37
created

includes/dataitems/SMW_DI_URI.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
use SMW\Exception\DataItemException;
4
5
/**
6
 * This class implements URI data items.
7
 *
8
 * @since 1.6
9
 *
10
 * @author Markus Krötzsch
11
 * @ingroup SMWDataItems
12
 */
13
class SMWDIUri extends SMWDataItem {
14
15
	/**
16
	 * URI scheme such as "html" or "mailto".
17
	 * @var string
18
	 */
19
	protected $m_scheme;
20
	/**
21
	 * "Hierpart" of the URI (usually some authority and path).
22
	 * @var string
23
	 */
24
	protected $m_hierpart;
25
	/**
26
	 * Query part of the URI.
27
	 * @var string
28
	 */
29
	protected $m_query;
30
	/**
31
	 * Fragment part of the URI.
32
	 * @var string
33
	 */
34
	protected $m_fragment;
35
36
	/**
37
	 * Initialise a URI by providing its scheme (e.g. "html"), 'hierpart'
38
	 * following "scheme:" (e.g. "//[email protected]/path), query (e.g.
39
	 * "q=Search+term", and fragment (e.g. "section-one"). The complete URI
40
	 * with these examples would be
41
	 * http://[email protected]/path?q=Search+term#section-one
42
	 * @param $scheme string for the scheme
43
	 * @param $hierpart string for the "hierpart"
44
	 * @param $query string for the query
45
	 * @param $fragment string for the fragment
46
	 *
47
	 * @todo Implement more validation here.
48
	 */
49 175
	public function __construct( $scheme, $hierpart, $query, $fragment ) {
50 175
		if ( ( $scheme === '' ) || ( preg_match( '/[^a-zA-Z]/u', $scheme ) ) ) {
51
			throw new DataItemException( "Illegal URI scheme \"$scheme\"." );
52
		}
53 175
		if ( $hierpart === '' ) {
54
			throw new DataItemException( "Illegal URI hierpart \"$hierpart\"." );
55
		}
56 175
		$this->m_scheme   = $scheme;
57 175
		$this->m_hierpart = $hierpart;
58 175
		$this->m_query    = $query;
59 175
		$this->m_fragment = $fragment;
60 175
	}
61
62 174
	public function getDIType() {
63 174
		return SMWDataItem::TYPE_URI;
64
	}
65
66
	/// @todo This should be changed to the spelling getUri().
67 174
	public function getURI() {
68
		$schemesWithDoubleslesh = array(
69 174
			'http', 'https', 'ftp'
70
		);
71
72 174
		$uri = $this->m_scheme . ':'
73 174
			. ( in_array( $this->m_scheme, $schemesWithDoubleslesh ) ? '//' : '' )
74 174
			. $this->m_hierpart
75 174
			. ( $this->m_query ? '?' . $this->m_query : '' )
76 174
			. ( $this->m_fragment ? '#' . $this->m_fragment : '' );
77
78 174
		// #1878
79
		// https://tools.ietf.org/html/rfc3986
80
		// Normalize spaces to use `_` instead of %20 and so ensure
81 26
		// that http://example.org/Foo bar === http://example.org/Foo_bar === http://example.org/Foo%20bar
82 26
		return str_replace( array( ' ', '%20'), '_', $uri );
83
	}
84
85 6
	public function getScheme() {
86 6
		return $this->m_scheme;
87
	}
88
89 6
	public function getHierpart() {
90 6
		return $this->m_hierpart;
91
	}
92
93 169
	public function getQuery() {
94 169
		return $this->m_query;
95
	}
96
97 3
	public function getFragment() {
98 3
		return $this->m_fragment;
99
	}
100
101 174
	/**
102 174
	 * @since 1.6
103
	 *
104
	 * @return string
105
	 */
106
	public function getSortKey() {
107
		return urldecode( $this->getURI() );
108
	}
109
110 42
	public function getSerialization() {
111 42
		return $this->getURI();
112 42
	}
113
114
	/**
115 42
	 * Create a data item from the provided serialization string and type
116 42
	 * ID.
117 42
	 * @return SMWDIUri
118
	 */
119
	public static function doUnserialize( $serialization ) {
120
		$parts = explode( ':', $serialization, 2 ); // try to split "schema:rest"
121
		if ( count( $parts ) <= 1 ) {
122
			throw new DataItemException( "Unserialization failed: the string \"$serialization\" is no valid URI." );
123 42
		}
124 42
		$scheme = $parts[0];
125 42
		$parts = explode( '?', $parts[1], 2 ); // try to split "hier-part?queryfrag"
126 42
		if ( count( $parts ) == 2 ) {
127
			$hierpart = $parts[0];
128
			$parts = explode( '#', $parts[1], 2 ); // try to split "query#frag"
129 42
			$query = $parts[0];
130
			$fragment = ( count( $parts ) == 2 ) ? $parts[1] : '';
131 42
		} else {
132
			$query = '';
133
			$parts = explode( '#', $parts[0], 2 ); // try to split "hier-part#frag"
134 2
			$hierpart = $parts[0];
135 2
			$fragment = ( count( $parts ) == 2 ) ? $parts[1] : '';
136
		}
137
138
		$hierpart = ltrim( $hierpart, '/' );
139 2
140
		return new SMWDIUri( $scheme, $hierpart, $query, $fragment );
141
	}
142
143
	public function equals( SMWDataItem $di ) {
144
		if ( $di->getDIType() !== SMWDataItem::TYPE_URI ) {
145
			return false;
146
		}
147
148
		return $di->getURI() === $this->getURI();
0 ignored issues
show
It seems like you code against a specific sub-type and not the parent class SMWDataItem as the method getURI() does only exist in the following sub-classes of SMWDataItem: SMWDIUri. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
149
	}
150
}
151