Gentics Portal.Node PHP API
 All Classes Namespaces Functions Variables Pages
RepositoryApi.php
1 <?php
2 /**
3  * Gentics Portal.Node PHP
4  * Author & Copyright (c) by Gentics Software GmbH
5  * sales@gentics.com
6  * http://www.gentics.com
7  * Licenses can be found in the LICENSE.txt file in the root-folder of this installation
8  * You must not use this software without a valid license agreement.
9  *
10  * Class for working with Gentics Content Connector
11  */
12 class RepositoryApi extends CApplicationComponent
13 {
14  const OBJ_TYPE_FOLDER = 10002;
15  const OBJ_TYPE_PAGE = 10007;
16  const OBJ_TYPE_BINARY = 10008;
17 
18  /**
19  * @var string api url
20  */
21  public $url;
22 
23  /**
24  * @var array possible content connector failover urls
25  */
26  public $failover_urls = array();
27 
28  /**
29  * @var string content connector repository search(ccr) path
30  */
31  public $contentRepositorySearch;
32 
33  /**
34  * @var string binary content service path
35  */
36  public $binaryContent;
37 
38  /**
39  * @var string content connector navigation path
40  */
41  public $navigation;
42 
43  /**
44  * @var string content connector activePath link
45  */
46  public $activePath;
47 
48  /**
49  * @var string content connector autosuggest path
50  */
51  public $autosuggest;
52 
53  /**
54  * @var string content connector search path
55  */
56  public $search;
57 
58  /**
59  * @var string content connector clear cache path
60  */
61  public $clearCache;
62 
63  /**
64  * @var string external host, which can be used as host instead of only relative path
65  */
66  public $contentExternalHost;
67 
68  /**
69  * @var array parameters which will be added to every request to gentics content connector
70  */
71  public $additionalRequestParameters = array();
72 
73  /**
74  * @var array Attributes, which will be added to every request as "&attribute=something"
75  */
76  public $additionalAttributes = array();
77 
78  /**
79  * @var array Sorting-Rules, that can be added to spezific requests
80  */
81  public $additionalSortingRules = array();
82 
83  /**
84  * Get api url which used to retrieve CMS objects
85  *
86  * @return string
87  */
88  protected function getContentRepositorySearchUrl()
89  {
90  return $this->getUrl() . $this->contentRepositorySearch;
91  }
92 
93  /**
94  * Get api url which used to retrieve static objects(images, js, css, etc.)
95  *
96  * @return string
97  */
98  protected function getBinaryContentUrl()
99  {
100  return $this->getUrl() . $this->binaryContent;
101  }
102 
103  /**
104  * Get api url which used to retrieve navigation data
105  *
106  * @return string
107  */
108  protected function getNavigationUrl()
109  {
110  return $this->getUrl() . $this->navigation;
111  }
112 
113  /**
114  * Get api url which used to retrieve active path data
115  *
116  * @return string
117  */
118  protected function getActivePathUrl()
119  {
120  return $this->getUrl() . $this->activePath;
121  }
122 
123  /**
124  * Get api url which used to retrieve autosuggest data
125  *
126  * @return string
127  */
128  protected function getAutosuggestUrl()
129  {
130  return $this->getUrl() . $this->autosuggest;
131  }
132 
133  /**
134  * Get api url which used to retrieve search data
135  *
136  * @return string
137  */
138  protected function getSearchUrl()
139  {
140  return $this->getUrl() . $this->search;
141  }
142 
143  /**
144  * Set base options
145  */
146  public function __construct()
147  {
148  if (isset($_GET['lang']) && is_string($_GET['lang'])) {
149  Yii::app()->language = $_GET['lang'];
150  }
151  }
152 
153  protected function getUrl()
154  {
155  // The main API was failed and we check if there
156  //is detected auxiliary API server in the cache
157  if ($failover_URL = Yii::app()->cache->get('failover_URL', false)) {
158  $this->failover_urls[] = $this->url;
159  $this->url = $failover_URL;
160  }
161  return $this->url;
162  }
163 
164  /**
165  * Do almost the same as getCmsObject. But in case relative path $path not found in the CMS it adds host address
166  * in front of $path and try second time
167  *
168  * @param $path
169  * @param array $attributes
170  * @return array|bool
171  */
172  public function getCmsObjectCanBeExternal($path, $attributes = array())
173  {
174  $cmsObject = $this->getCmsObject($path, $attributes);
175  if (!$cmsObject && !preg_match('/.+\.(php|html)$/', $path)) {
176  $externalPath = (!empty($this->contentExternalHost) ? $this->contentExternalHost : Yii::app()->request->getHostInfo()) . $path;
177  return $this->getCmsObject($externalPath, $attributes);
178  }
179 
180  return $cmsObject;
181  }
182 
183  /**
184  * Get CMS content last modification time
185  *
186  * @param string $path path of node
187  *
188  * @return bool
189  */
190  public function getLastModificationTime($path)
191  {
192  $cacheId = 'updateTMSTMP_'.md5($path);
193  $updateTMSTMP = false;
194  if (!($updateTMSTMP = Yii::app()->cache->get($cacheId, false))
195  || (isset($_GET['refresh']) && $_GET['refresh']=='true')) {
196  $attributes = $this->getContentAttributes($path, array('updatetimestamp'));
197  if($attributes) {
198  $updateTMSTMP = $attributes['updatetimestamp'];
199  Yii::app()->cache->set($cacheId, $updateTMSTMP, Yii::app()->getModule('contentSource')->cacheTime);
200  }
201  }
202  return $updateTMSTMP;
203  }
204 
205  /**
206  * This method is used for retrieving only content attributes from Gentics Content Connector
207  *
208  * @param string $path content path
209  * @param array $attributes array of personalization attributes
210  *
211  * @return array
212  */
213  public function getContentAttributes($path, $attributes)
214  {
215  $cmsObject = $this->getCmsObject($path, array_filter($attributes, function ($el) {
216  return $el != 'content';
217  }));
218  return $cmsObject['attributes'];
219  }
220 
221  /**
222  * Get CMS content object
223  * If object is binary, make additional request to get binarycontent and put it to 'content' field
224  *
225  * @param string $path content path
226  * @param array $attributes requested content attributes
227  *
228  * @return array|bool
229  */
230  public function getCmsObject($path, $attributes = array())
231  {
232  $params = array(
233  'filter' => "object.url==\"$path\"",
234  'type' => 'php',
235  );
236 
237  $params = $this->addAdditionalParameters($params, 'contentRepositorySearch');
238  $response = $this->_request($this->getContentRepositorySearchUrl(), $params, $attributes);
239  $cmsObject = self::_prepareResponse($response);
240  if (!$cmsObject) {
241  return false;
242  }
243  if (in_array('content', $attributes) && $cmsObject['obj_type'] == self::OBJ_TYPE_BINARY) {
244  $cmsObject['attributes']['content'] = $this->getBinaryContent($path);
245  }
246 
247  return $cmsObject;
248  }
249 
250  /**
251  * Download binary content
252  *
253  * @param string $path content path
254  *
255  * @return string binary content
256  */
257  public function getBinaryContent($path)
258  {
259  $params = array(
260  'filter' => "object.url==\"$path\"",
261  );
262  $params = $this->addAdditionalParameters($params, 'binaryContent');
263 
264  $response = $this->_request($this->getBinaryContentUrl(), $params);
265  return $response;
266  }
267 
268  /**
269  * Adds parameters to certain requests
270  *
271  * @param array $params array of preset parameters
272  * @param string $type type of request from
273  *
274  * @return array
275  */
276  public function addAdditionalParameters($params, $type)
277  {
278  if (!empty($this->additionalRequestParameters[$type])) {
279  foreach ($this->additionalRequestParameters[$type] as $name => $val) {
280  $params[$name] = !empty($params[$name]) ? $params[$name] . ' AND ' . $val : $params[$name];
281  }
282  }
283  return $params;
284  }
285 
286  /**
287  * clears the CCR cache
288  *
289  * @param string $url url of CCR, if not set use configured url
290  * @param string $contentid content-ID of page
291  *
292  * @return array
293  */
294  public function clearCache($contentid, $url="")
295  {
296  if (empty($url) || $url="") {
297  $url = $this->clearCache;
298  }
299  // /ccr/clearcache?contentid=10007.123
300  $url = $url . '?contentid=' . $contentid;
301  /* do not remove the @ sign below, it is required for exception handling */
302  @$content = file_get_contents($url, false);
303 
304  return $content;
305  }
306  /**
307  * Gets additional attribute by request type
308  *
309  * @param string $type request type (navigation/content/search)
310  *
311  * @return string additional attributes
312  */
313  protected function getAdditionalAttributesByRequestType($type) {
314 
315  $attributes = false;
316  if (isset($this->additionalAttributes[$type])) {
317  $attributes = $this->additionalAttributes[$type];
318  }
319  if ($attributes && $attributes = explode(',',$attributes)) {
320  $attributes = array_map('trim',$attributes);
321  $attributes = array_unique($attributes);
322  $attributes = '&attributes=' . implode('&attributes=', $attributes);
323  }
324  return $attributes;
325  }
326  /**
327  * Gets additional attribute by url
328  *
329  * @param string $url url
330  *
331  * @return string additional attributes
332  */
333  protected function getAdditionalAttributesByUrl($url)
334  {
335  $type = false;
336  if (strpos($url, $this->navigation)) {
337  $type = 'navigation';
338  } elseif(strpos($url, $this->binaryContent)) {
339  $type = 'content';
340  } elseif(strpos($url, $this->contentRepositorySearch)
341  || strpos($url, $this->search)) {
342  $type = 'search';
343  }
344  return $this->getAdditionalAttributesByRequestType($type);
345  }
346 
347  /**
348  * Make request to API
349  *
350  * @param string $url url
351  * @param array $params parameters
352  * @param array $attributes array of Gentics Content Connector attributes which should be fetched
353  * @param string $timeout specific request timeout in seconds (if not set standard timeout 60 seconds is used)
354  *
355  * @throws Exception
356  * @return string raw response
357  */
358  private function _request($url, $params, $attributes = array(), $timeout = "")
359  {
360  $attr = array();
361  array_walk($attributes, function ($item) use (&$attr) {
362  $attr[] = "attributes=$item";
363  });
364 
365  $url = $url . '?' . http_build_query($params);
366  foreach($this->additionalSortingRules as $addRuleK => $addRuleV) {
367  if( strpos($url,$addRuleK)) {
368  $url .= '&sorting='.$addRuleV;
369  }
370  }
371 
372  /* append the requested attributes, if there are any */
373  if (!empty($attr)) {
374  $url .= '&' . implode('&', $attr);
375  }
376 
377  /* adding additional attributes depends on request type */
378  $url .= $this->getAdditionalAttributesByUrl($url);
379 
380  Yii::trace($url, 'Api requests(start)');
381  $start = microtime(true);
382 
383  if (!isset( $timeout ) || $timeout == "") {
384  $ctx=stream_context_create(array('http'=>
385  array(
386  'timeout' => 60 // 1 minute - if request is longer than go to failover
387  )
388  ));
389  }
390 
391  /* do not remove the @ sign below, it is required for exception handling */
392  @$content = file_get_contents($url, false, $ctx);
393 
394  $failover_attempt = 0;
395 
396  while (($content == false || strpos($content,'DatasourceException')!==false) && ($failover_attempt < count($this->failover_urls))) {
397  if (isset( $this->failover_urls[$failover_attempt])) {
398  $this->url = $this->failover_urls[$failover_attempt];
399  $exploded_url = explode('://',$url);
400  $exploded_url = explode('/',$exploded_url[1]);
401  $exploded_url[0] = $this->url;
402  $url = implode('/', $exploded_url);
403  @$content = file_get_contents($url, false, $ctx);
404  }
405 
406  if ($content !== false) {
407  Yii::app()->cache->set('failover_URL', $this->url, Yii::app()->getModule('contentSource')->cacheTime);
408  break;
409  }
410  $failover_attempt++;
411  }
412  if ($content == false) {
413  throw new Exception('Repository API error: could not complete API request.');
414  }
415  Yii::trace($url, 'Api requests(end). Time s.: ' . round(microtime(true) - $start, 4));
416 
417  return $content;
418  }
419 
420  /**
421  * Requesting for content object
422  *
423  * @param array $params url params
424  * @param array $attributes requested attributes
425  * @param string $timeout specific request timeout in seconds (if not set standard timeout 60 seconds is used)
426  *
427  * @return string
428  */
429  public function request($params, $attributes = array(), $timeout = "")
430  {
431  return $this->_request($this->getContentRepositorySearchUrl(), $params, $attributes, $timeout);
432  }
433 
434  /**
435  * Requesting for navigation object
436  *
437  * @param array $params url params
438  * @param array $attributes requested attributes
439  * @param string $timeout specific request timeout in seconds (if not set standard timeout 60 seconds is used)
440  *
441  * @return string
442  */
443  public function requestNavigation($params, $attributes = array(), $timeout = "")
444  {
445  return $this->_request($this->getNavigationUrl(), $params, $attributes, $timeout);
446  }
447 
448  /**
449  * Requesting for active path object
450  *
451  * @param array $params url params
452  * @param array $attributes requested attributes
453  * @param string $timeout specific request timeout in seconds (if not set standard timeout 60 seconds is used)
454  *
455  * @return string
456  */
457  public function requestActivePath($params, $attributes = array(), $timeout = "")
458  {
459  return $this->_request($this->getActivePathUrl(), $params, $attributes, $timeout);
460  }
461 
462  /**
463  * Requesting for autosuggest data
464  *
465  * @param array $params url params
466  * @param array $attributes requested attributes
467  * @param string $timeout specific request timeout in seconds (if not set standard timeout 60 seconds is used)
468  *
469  * @return string
470  */
471  public function requestAutosuggest($params, $attributes = array(), $timeout = "")
472  {
473  return $this->_request($this->getAutosuggestUrl(), $params, $attributes, $timeout);
474  }
475 
476  /**
477  * Requesting for search data
478  *
479  * @param array $params url params
480  * @param array $attributes requested attributes
481  * @param string $timeout specific request timeout in seconds (if not set standard timeout 60 seconds is used)
482  *
483  * @return string
484  */
485  public function requestSearch($params, $attributes = array(), $timeout = "")
486  {
487  return $this->_request($this->getSearchUrl(), $params, $attributes, $timeout);
488  }
489 
490  /**
491  * Prepare API response. Convert response to useful form.
492  *
493  * @param array $response prepared response
494  *
495  * @return array|bool prepared object.
496  *
497  */
498  private static function _prepareResponse($response)
499  {
500  $responseData = unserialize($response);
501  if (@$responseData['status'] == 'ok') {
502  unset($responseData['status']);
503  if (count($responseData) > 0) {
504  return array_shift($responseData);
505  }
506  return false;
507  } else {
508  Yii::log(print_r($responseData, true), CLogger::LEVEL_TRACE);
509  }
510  return false;
511  }
512 }