annotate vendor/zendframework/zend-feed/src/PubSubHubbub/Publisher.php @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents 129ea1e6d783
children
rev   line source
Chris@0 1 <?php
Chris@0 2 /**
Chris@0 3 * Zend Framework (http://framework.zend.com/)
Chris@0 4 *
Chris@0 5 * @link http://github.com/zendframework/zf2 for the canonical source repository
Chris@0 6 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
Chris@0 7 * @license http://framework.zend.com/license/new-bsd New BSD License
Chris@0 8 */
Chris@0 9
Chris@0 10 namespace Zend\Feed\PubSubHubbub;
Chris@0 11
Chris@0 12 use Traversable;
Chris@0 13 use Zend\Feed\Uri;
Chris@0 14 use Zend\Http\Request as HttpRequest;
Chris@0 15 use Zend\Stdlib\ArrayUtils;
Chris@0 16
Chris@0 17 class Publisher
Chris@0 18 {
Chris@0 19 /**
Chris@0 20 * An array of URLs for all Hub Servers used by the Publisher, and to
Chris@0 21 * which all topic update notifications will be sent.
Chris@0 22 *
Chris@0 23 * @var array
Chris@0 24 */
Chris@0 25 protected $hubUrls = [];
Chris@0 26
Chris@0 27 /**
Chris@0 28 * An array of topic (Atom or RSS feed) URLs which have been updated and
Chris@0 29 * whose updated status will be notified to all Hub Servers.
Chris@0 30 *
Chris@0 31 * @var array
Chris@0 32 */
Chris@0 33 protected $updatedTopicUrls = [];
Chris@0 34
Chris@0 35 /**
Chris@0 36 * An array of any errors including keys for 'response', 'hubUrl'.
Chris@0 37 * The response is the actual Zend\Http\Response object.
Chris@0 38 *
Chris@0 39 * @var array
Chris@0 40 */
Chris@0 41 protected $errors = [];
Chris@0 42
Chris@0 43 /**
Chris@0 44 * An array of topic (Atom or RSS feed) URLs which have been updated and
Chris@0 45 * whose updated status will be notified to all Hub Servers.
Chris@0 46 *
Chris@0 47 * @var array
Chris@0 48 */
Chris@0 49 protected $parameters = [];
Chris@0 50
Chris@0 51 /**
Chris@0 52 * Constructor; accepts an array or Zend\Config\Config instance to preset
Chris@0 53 * options for the Publisher without calling all supported setter
Chris@0 54 * methods in turn.
Chris@0 55 *
Chris@0 56 * @param array|Traversable $options
Chris@0 57 */
Chris@0 58 public function __construct($options = null)
Chris@0 59 {
Chris@0 60 if ($options !== null) {
Chris@0 61 $this->setOptions($options);
Chris@0 62 }
Chris@0 63 }
Chris@0 64
Chris@0 65 /**
Chris@0 66 * Process any injected configuration options
Chris@0 67 *
Chris@0 68 * @param array|Traversable $options Options array or Traversable object
Chris@0 69 * @return Publisher
Chris@0 70 * @throws Exception\InvalidArgumentException
Chris@0 71 */
Chris@0 72 public function setOptions($options)
Chris@0 73 {
Chris@0 74 if ($options instanceof Traversable) {
Chris@0 75 $options = ArrayUtils::iteratorToArray($options);
Chris@0 76 }
Chris@0 77
Chris@12 78 if (! is_array($options)) {
Chris@0 79 throw new Exception\InvalidArgumentException('Array or Traversable object'
Chris@0 80 . 'expected, got ' . gettype($options));
Chris@0 81 }
Chris@0 82 if (array_key_exists('hubUrls', $options)) {
Chris@0 83 $this->addHubUrls($options['hubUrls']);
Chris@0 84 }
Chris@0 85 if (array_key_exists('updatedTopicUrls', $options)) {
Chris@0 86 $this->addUpdatedTopicUrls($options['updatedTopicUrls']);
Chris@0 87 }
Chris@0 88 if (array_key_exists('parameters', $options)) {
Chris@0 89 $this->setParameters($options['parameters']);
Chris@0 90 }
Chris@0 91 return $this;
Chris@0 92 }
Chris@0 93
Chris@0 94 /**
Chris@0 95 * Add a Hub Server URL supported by Publisher
Chris@0 96 *
Chris@0 97 * @param string $url
Chris@0 98 * @return Publisher
Chris@0 99 * @throws Exception\InvalidArgumentException
Chris@0 100 */
Chris@0 101 public function addHubUrl($url)
Chris@0 102 {
Chris@12 103 if (empty($url) || ! is_string($url) || ! Uri::factory($url)->isValid()) {
Chris@0 104 throw new Exception\InvalidArgumentException('Invalid parameter "url"'
Chris@0 105 . ' of "' . $url . '" must be a non-empty string and a valid'
Chris@0 106 . 'URL');
Chris@0 107 }
Chris@0 108 $this->hubUrls[] = $url;
Chris@0 109 return $this;
Chris@0 110 }
Chris@0 111
Chris@0 112 /**
Chris@0 113 * Add an array of Hub Server URLs supported by Publisher
Chris@0 114 *
Chris@0 115 * @param array $urls
Chris@0 116 * @return Publisher
Chris@0 117 */
Chris@0 118 public function addHubUrls(array $urls)
Chris@0 119 {
Chris@0 120 foreach ($urls as $url) {
Chris@0 121 $this->addHubUrl($url);
Chris@0 122 }
Chris@0 123 return $this;
Chris@0 124 }
Chris@0 125
Chris@0 126 /**
Chris@0 127 * Remove a Hub Server URL
Chris@0 128 *
Chris@0 129 * @param string $url
Chris@0 130 * @return Publisher
Chris@0 131 */
Chris@0 132 public function removeHubUrl($url)
Chris@0 133 {
Chris@12 134 if (! in_array($url, $this->getHubUrls())) {
Chris@0 135 return $this;
Chris@0 136 }
Chris@0 137 $key = array_search($url, $this->hubUrls);
Chris@0 138 unset($this->hubUrls[$key]);
Chris@0 139 return $this;
Chris@0 140 }
Chris@0 141
Chris@0 142 /**
Chris@0 143 * Return an array of unique Hub Server URLs currently available
Chris@0 144 *
Chris@0 145 * @return array
Chris@0 146 */
Chris@0 147 public function getHubUrls()
Chris@0 148 {
Chris@0 149 $this->hubUrls = array_unique($this->hubUrls);
Chris@0 150 return $this->hubUrls;
Chris@0 151 }
Chris@0 152
Chris@0 153 /**
Chris@0 154 * Add a URL to a topic (Atom or RSS feed) which has been updated
Chris@0 155 *
Chris@0 156 * @param string $url
Chris@0 157 * @return Publisher
Chris@0 158 * @throws Exception\InvalidArgumentException
Chris@0 159 */
Chris@0 160 public function addUpdatedTopicUrl($url)
Chris@0 161 {
Chris@12 162 if (empty($url) || ! is_string($url) || ! Uri::factory($url)->isValid()) {
Chris@0 163 throw new Exception\InvalidArgumentException('Invalid parameter "url"'
Chris@0 164 . ' of "' . $url . '" must be a non-empty string and a valid'
Chris@0 165 . 'URL');
Chris@0 166 }
Chris@0 167 $this->updatedTopicUrls[] = $url;
Chris@0 168 return $this;
Chris@0 169 }
Chris@0 170
Chris@0 171 /**
Chris@0 172 * Add an array of Topic URLs which have been updated
Chris@0 173 *
Chris@0 174 * @param array $urls
Chris@0 175 * @return Publisher
Chris@0 176 */
Chris@0 177 public function addUpdatedTopicUrls(array $urls)
Chris@0 178 {
Chris@0 179 foreach ($urls as $url) {
Chris@0 180 $this->addUpdatedTopicUrl($url);
Chris@0 181 }
Chris@0 182 return $this;
Chris@0 183 }
Chris@0 184
Chris@0 185 /**
Chris@0 186 * Remove an updated topic URL
Chris@0 187 *
Chris@0 188 * @param string $url
Chris@0 189 * @return Publisher
Chris@0 190 */
Chris@0 191 public function removeUpdatedTopicUrl($url)
Chris@0 192 {
Chris@12 193 if (! in_array($url, $this->getUpdatedTopicUrls())) {
Chris@0 194 return $this;
Chris@0 195 }
Chris@0 196 $key = array_search($url, $this->updatedTopicUrls);
Chris@0 197 unset($this->updatedTopicUrls[$key]);
Chris@0 198 return $this;
Chris@0 199 }
Chris@0 200
Chris@0 201 /**
Chris@0 202 * Return an array of unique updated topic URLs currently available
Chris@0 203 *
Chris@0 204 * @return array
Chris@0 205 */
Chris@0 206 public function getUpdatedTopicUrls()
Chris@0 207 {
Chris@0 208 $this->updatedTopicUrls = array_unique($this->updatedTopicUrls);
Chris@0 209 return $this->updatedTopicUrls;
Chris@0 210 }
Chris@0 211
Chris@0 212 /**
Chris@0 213 * Notifies a single Hub Server URL of changes
Chris@0 214 *
Chris@0 215 * @param string $url The Hub Server's URL
Chris@0 216 * @return void
Chris@0 217 * @throws Exception\InvalidArgumentException
Chris@0 218 * @throws Exception\RuntimeException
Chris@0 219 */
Chris@0 220 public function notifyHub($url)
Chris@0 221 {
Chris@12 222 if (empty($url) || ! is_string($url) || ! Uri::factory($url)->isValid()) {
Chris@0 223 throw new Exception\InvalidArgumentException('Invalid parameter "url"'
Chris@0 224 . ' of "' . $url . '" must be a non-empty string and a valid'
Chris@0 225 . 'URL');
Chris@0 226 }
Chris@0 227 $client = $this->_getHttpClient();
Chris@0 228 $client->setUri($url);
Chris@0 229 $response = $client->getResponse();
Chris@0 230 if ($response->getStatusCode() !== 204) {
Chris@0 231 throw new Exception\RuntimeException('Notification to Hub Server '
Chris@0 232 . 'at "' . $url . '" appears to have failed with a status code of "'
Chris@0 233 . $response->getStatusCode() . '" and message "'
Chris@0 234 . $response->getContent() . '"');
Chris@0 235 }
Chris@0 236 }
Chris@0 237
Chris@0 238 /**
Chris@0 239 * Notifies all Hub Server URLs of changes
Chris@0 240 *
Chris@0 241 * If a Hub notification fails, certain data will be retained in an
Chris@0 242 * an array retrieved using getErrors(), if a failure occurs for any Hubs
Chris@0 243 * the isSuccess() check will return FALSE. This method is designed not
Chris@0 244 * to needlessly fail with an Exception/Error unless from Zend\Http\Client.
Chris@0 245 *
Chris@0 246 * @return void
Chris@0 247 * @throws Exception\RuntimeException
Chris@0 248 */
Chris@0 249 public function notifyAll()
Chris@0 250 {
Chris@0 251 $client = $this->_getHttpClient();
Chris@0 252 $hubs = $this->getHubUrls();
Chris@0 253 if (empty($hubs)) {
Chris@0 254 throw new Exception\RuntimeException('No Hub Server URLs'
Chris@0 255 . ' have been set so no notifications can be sent');
Chris@0 256 }
Chris@0 257 $this->errors = [];
Chris@0 258 foreach ($hubs as $url) {
Chris@0 259 $client->setUri($url);
Chris@0 260 $response = $client->getResponse();
Chris@0 261 if ($response->getStatusCode() !== 204) {
Chris@0 262 $this->errors[] = [
Chris@0 263 'response' => $response,
Chris@0 264 'hubUrl' => $url
Chris@0 265 ];
Chris@0 266 }
Chris@0 267 }
Chris@0 268 }
Chris@0 269
Chris@0 270 /**
Chris@0 271 * Add an optional parameter to the update notification requests
Chris@0 272 *
Chris@0 273 * @param string $name
Chris@0 274 * @param string|null $value
Chris@0 275 * @return Publisher
Chris@0 276 * @throws Exception\InvalidArgumentException
Chris@0 277 */
Chris@0 278 public function setParameter($name, $value = null)
Chris@0 279 {
Chris@0 280 if (is_array($name)) {
Chris@0 281 $this->setParameters($name);
Chris@0 282 return $this;
Chris@0 283 }
Chris@12 284 if (empty($name) || ! is_string($name)) {
Chris@0 285 throw new Exception\InvalidArgumentException('Invalid parameter "name"'
Chris@0 286 . ' of "' . $name . '" must be a non-empty string');
Chris@0 287 }
Chris@0 288 if ($value === null) {
Chris@0 289 $this->removeParameter($name);
Chris@0 290 return $this;
Chris@0 291 }
Chris@12 292 if (empty($value) || (! is_string($value) && $value !== null)) {
Chris@0 293 throw new Exception\InvalidArgumentException('Invalid parameter "value"'
Chris@0 294 . ' of "' . $value . '" must be a non-empty string');
Chris@0 295 }
Chris@0 296 $this->parameters[$name] = $value;
Chris@0 297 return $this;
Chris@0 298 }
Chris@0 299
Chris@0 300 /**
Chris@0 301 * Add an optional parameter to the update notification requests
Chris@0 302 *
Chris@0 303 * @param array $parameters
Chris@0 304 * @return Publisher
Chris@0 305 */
Chris@0 306 public function setParameters(array $parameters)
Chris@0 307 {
Chris@0 308 foreach ($parameters as $name => $value) {
Chris@0 309 $this->setParameter($name, $value);
Chris@0 310 }
Chris@0 311 return $this;
Chris@0 312 }
Chris@0 313
Chris@0 314 /**
Chris@0 315 * Remove an optional parameter for the notification requests
Chris@0 316 *
Chris@0 317 * @param string $name
Chris@0 318 * @return Publisher
Chris@0 319 * @throws Exception\InvalidArgumentException
Chris@0 320 */
Chris@0 321 public function removeParameter($name)
Chris@0 322 {
Chris@12 323 if (empty($name) || ! is_string($name)) {
Chris@0 324 throw new Exception\InvalidArgumentException('Invalid parameter "name"'
Chris@0 325 . ' of "' . $name . '" must be a non-empty string');
Chris@0 326 }
Chris@0 327 if (array_key_exists($name, $this->parameters)) {
Chris@0 328 unset($this->parameters[$name]);
Chris@0 329 }
Chris@0 330 return $this;
Chris@0 331 }
Chris@0 332
Chris@0 333 /**
Chris@0 334 * Return an array of optional parameters for notification requests
Chris@0 335 *
Chris@0 336 * @return array
Chris@0 337 */
Chris@0 338 public function getParameters()
Chris@0 339 {
Chris@0 340 return $this->parameters;
Chris@0 341 }
Chris@0 342
Chris@0 343 /**
Chris@0 344 * Returns a boolean indicator of whether the notifications to Hub
Chris@0 345 * Servers were ALL successful. If even one failed, FALSE is returned.
Chris@0 346 *
Chris@0 347 * @return bool
Chris@0 348 */
Chris@0 349 public function isSuccess()
Chris@0 350 {
Chris@17 351 return ! $this->errors;
Chris@0 352 }
Chris@0 353
Chris@0 354 /**
Chris@0 355 * Return an array of errors met from any failures, including keys:
Chris@0 356 * 'response' => the Zend\Http\Response object from the failure
Chris@0 357 * 'hubUrl' => the URL of the Hub Server whose notification failed
Chris@0 358 *
Chris@0 359 * @return array
Chris@0 360 */
Chris@0 361 public function getErrors()
Chris@0 362 {
Chris@0 363 return $this->errors;
Chris@0 364 }
Chris@0 365
Chris@0 366 /**
Chris@0 367 * Get a basic prepared HTTP client for use
Chris@0 368 *
Chris@0 369 * @return \Zend\Http\Client
Chris@0 370 * @throws Exception\RuntimeException
Chris@0 371 */
Chris@12 372 // @codingStandardsIgnoreStart
Chris@0 373 protected function _getHttpClient()
Chris@0 374 {
Chris@12 375 // @codingStandardsIgnoreEnd
Chris@0 376 $client = PubSubHubbub::getHttpClient();
Chris@0 377 $client->setMethod(HttpRequest::METHOD_POST);
Chris@0 378 $client->setOptions([
Chris@0 379 'useragent' => 'Zend_Feed_Pubsubhubbub_Publisher/' . Version::VERSION,
Chris@0 380 ]);
Chris@0 381 $params = [];
Chris@0 382 $params[] = 'hub.mode=publish';
Chris@0 383 $topics = $this->getUpdatedTopicUrls();
Chris@0 384 if (empty($topics)) {
Chris@0 385 throw new Exception\RuntimeException('No updated topic URLs'
Chris@0 386 . ' have been set');
Chris@0 387 }
Chris@0 388 foreach ($topics as $topicUrl) {
Chris@0 389 $params[] = 'hub.url=' . urlencode($topicUrl);
Chris@0 390 }
Chris@0 391 $optParams = $this->getParameters();
Chris@0 392 foreach ($optParams as $name => $value) {
Chris@0 393 $params[] = urlencode($name) . '=' . urlencode($value);
Chris@0 394 }
Chris@0 395 $paramString = implode('&', $params);
Chris@0 396 $client->setRawBody($paramString);
Chris@0 397 return $client;
Chris@0 398 }
Chris@0 399 }