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  public $failover_urls = array();
24 
25  public $contentRepositorySearch;
26  /**
27  * @var string binary content service path
28  */
29  public $binaryContent;
30 
31  public $navigation;
32 
33  public $activePath;
34 
35  public $autosuggest;
36 
37  public $search;
38 
39  public $contentExternalHost;
40 
41  /**
42  * @var array parameters which will be added to every request to gentics content connector
43  */
44  public $additionalRequestParameters = array();
45 
46  /**
47  * @var array Attributes, which will be added to every request as "&attribute=something"
48  */
49  public $additionalAttributes = array();
50 
51  /**
52  * @var array Sorting-Rules, that can be added to spezific requests
53  */
54  public $additionalSortingRules = array();
55 
56 
57  /**
58  * Get api url which used to retrieve CMS objects
59  *
60  * @return string
61  */
62  protected function getContentRepositorySearchUrl()
63  {
64  return $this->getUrl() . $this->contentRepositorySearch;
65  }
66 
67  /**
68  * Get api url which used to retrieve static objects(images, js, css, etc.)
69  *
70  * @return string
71  */
72  protected function getBinaryContentUrl()
73  {
74  return $this->getUrl() . $this->binaryContent;
75  }
76 
77  /**
78  * Get api url which used to retrieve navigation data
79  *
80  * @return string
81  */
82  protected function getNavigationUrl()
83  {
84  return $this->getUrl() . $this->navigation;
85  }
86 
87  /**
88  * Get api url which used to retrieve active path data
89  *
90  * @return string
91  */
92  protected function getActivePathUrl()
93  {
94  return $this->getUrl() . $this->activePath;
95  }
96 
97  /**
98  * Get api url which used to retrieve autosuggest data
99  *
100  * @return string
101  */
102  protected function getAutosuggestUrl()
103  {
104  return $this->getUrl() . $this->autosuggest;
105  }
106 
107  /**
108  * Get api url which used to retrieve search data
109  *
110  * @return string
111  */
112  protected function getSearchUrl()
113  {
114  return $this->getUrl() . $this->search;
115  }
116 
117  /**
118  * Set base options
119  */
120  public function __construct()
121  {
122  if (isset($_GET['lang']) && is_string($_GET['lang'])) {
123  Yii::app()->language = $_GET['lang'];
124  }
125  }
126 
127  protected function getUrl(){
128  // The main API was failed and we check if there
129  //is detected auxiliary API server in the cache
130  if(($failover_URL = Yii::app()->cache->get('failover_URL'))!==false){
131  $this->failover_urls[] = $this->url;
132  $this->url = $failover_URL;
133  }
134  return $this->url;
135  }
136 
137  /**
138  * Do almost the same as getCmsObject. But in case relative path $path not found in the CMS it adds host address
139  * in front of $path and try second time
140  *
141  * @param $path
142  * @param array $attributes
143  * @return array|bool
144  */
145  public function getCmsObjectCanBeExternal($path, $attributes = array())
146  {
147  $cmsObject = $this->getCmsObject($path, $attributes);
148  if (!$cmsObject && !preg_match('/.+\.(php|html)$/', $path)) {
149  $externalPath = (!empty($this->contentExternalHost) ? $this->contentExternalHost : Yii::app()->request->getHostInfo()) . $path;
150  return $this->getCmsObject($externalPath, $attributes);
151  }
152 
153  return $cmsObject;
154  }
155 
156  /**
157  * Get CMS content last modification time
158  *
159  * @param string $path path of node
160  *
161  * @return bool
162  */
163  public function getLastModificationTime($path)
164  {
165  $cacheId = 'updateTMSTMP_'.md5($path);
166  $updateTMSTMP = false;
167  if(!($updateTMSTMP = Yii::app()->cache->get($cacheId)) || (isset($_GET['refresh']) && $_GET['refresh']=='true')){
168  $attributes = $this->getContentAttributes($path, array('updatetimestamp'));
169  if($attributes){
170  $updateTMSTMP = $attributes['updatetimestamp'];
171  Yii::app()->cache->set($cacheId, $updateTMSTMP, Yii::app()->getModule('contentSource')->cacheTime);
172  }
173  }
174  return $updateTMSTMP;
175  }
176 
177  /**
178  * This method is used for retrieving only content attributes from Gentics Content Connector
179  *
180  * @param string $path content path
181  * @param array $attributes array of personalization attributes
182  *
183  * @return array
184  */
185  public function getContentAttributes($path, $attributes)
186  {
187  $cmsObject = $this->getCmsObject($path, array_filter($attributes, function ($el) {
188  return $el != 'content';
189  }));
190  return $cmsObject['attributes'];
191  }
192 
193  /**
194  * Get CMS content object
195  * If object is binary, make additional request to get binarycontent and put it to 'content' field
196  *
197  * @param string $path content path
198  * @param array $attributes requested content attributes
199  *
200  * @return array|bool
201  */
202  public function getCmsObject($path, $attributes = array())
203  {
204  $params = array(
205  'filter' => "object.url==\"$path\"",
206  'type' => 'php',
207  );
208 
209  $params = $this->addAdditionalParameters($params, 'contentRepositorySearch');
210  $response = $this->_request($this->getContentRepositorySearchUrl(), $params, $attributes);
211  $cmsObject = self::_prepareResponse($response);
212  if (!$cmsObject) {
213  return false;
214  }
215  if (in_array('content', $attributes) && $cmsObject['obj_type'] == self::OBJ_TYPE_BINARY) {
216  $cmsObject['attributes']['content'] = $this->getBinaryContent($path);
217  }
218 
219  return $cmsObject;
220  }
221 
222  /**
223  * Download binary content
224  *
225  * @param string $path content path
226  *
227  * @return string binary content
228  */
229  public function getBinaryContent($path)
230  {
231  $params = array(
232  'filter' => "object.url==\"$path\"",
233  );
234  $params = $this->addAdditionalParameters($params, 'binaryContent');
235 
236  $response = $this->_request($this->getBinaryContentUrl(), $params);
237  return $response;
238  }
239 
240  /**
241  * Adds parameters to certain requests
242  *
243  * @param array $params array of preset parameters
244  * @param string $type type of request from
245  *
246  * @return array
247  */
248  public function addAdditionalParameters($params, $type)
249  {
250  if (!empty($this->additionalRequestParameters[$type])) {
251  foreach ($this->additionalRequestParameters[$type] as $name => $val) {
252  $params[$name] = !empty($params[$name]) ? $params[$name] . ' AND ' . $val : $params[$name];
253  }
254  }
255  return $params;
256  }
257 
258  /**
259  * Make request to API
260  *
261  * @param string $url url
262  * @param array $params parameters
263  * @param array $attributes array of Gentics connector attributes which need to be select
264  *
265  * @throws Exception
266  * @return string raw response
267  */
268  private function _request($url, $params, $attributes = array())
269  {
270  $attr = array();
271  array_walk($attributes, function ($item) use (&$attr) {
272  $attr[] = "attributes=$item";
273  });
274 
275  $url = $url . '?' . http_build_query($params);
276  foreach($this->additionalSortingRules as $addRuleK => $addRuleV){
277  if( strpos($url,$addRuleK)){
278  $url .= '&sorting='.$addRuleV;
279  }
280  }
281  $url .= '&' . implode('&', $attr). '&' . implode('&attributes=', $this->additionalAttributes);
282  $url = rtrim($url, '&');
283  Yii::trace($url, 'Api requests(start)');
284  $start = microtime(true);
285  $ctx=stream_context_create(array('http'=>
286  array(
287  'timeout' => 1
288  )
289  ));
290  /* do not remove the @ sign below, it is required for exception handling */
291  @$content = file_get_contents($url, false, $ctx);
292  $failover_attempt = 0;
293  while(($content == false || strpos($content,'DatasourceException')!==false) && ($failover_attempt < count($this->failover_urls))){
294  $this->url = $this->failover_urls[$failover_attempt];
295  $exploded_url = explode('://',$url);
296  $exploded_url = explode('/',$exploded_url[1]);
297  $exploded_url[0] = $this->url;
298  $url = implode('/', $exploded_url);
299  @$content = file_get_contents($url, false, $ctx);
300  if($content !== false){
301  Yii::app()->cache->set('failover_URL', $this->url, Yii::app()->getModule('contentSource')->cacheTime);
302  break;
303  }
304  $failover_attempt++;
305  }
306  if ($content == false) {
307  throw new Exception('Repository API error: could not complete API request.');
308  }
309  Yii::trace($url, 'Api requests(end). Time s.: ' . round(microtime(true) - $start, 4));
310 
311  return $content;
312  }
313 
314  /**
315  * Requesting for content object
316  *
317  * @param array $params url params
318  * @param array $attributes requested attributes
319  *
320  * @return string
321  */
322  public function request($params, $attributes = array())
323  {
324  return $this->_request($this->getContentRepositorySearchUrl(), $params, $attributes);
325  }
326 
327  /**
328  * Requesting for navigation object
329  *
330  * @param array $params url params
331  * @param array $attributes requested attributes
332  *
333  * @return string
334  */
335  public function requestNavigation($params, $attributes = array())
336  {
337  return $this->_request($this->getNavigationUrl(), $params, $attributes);
338  }
339 
340  /**
341  * Requesting for active path object
342  *
343  * @param array $params url params
344  * @param array $attributes requested attributes
345  *
346  * @return string
347  */
348  public function requestActivePath($params, $attributes = array())
349  {
350  return $this->_request($this->getActivePathUrl(), $params, $attributes);
351  }
352 
353  /**
354  * Requesting for autosuggest data
355  *
356  * @param array $params url params
357  * @param array $attributes requested attributes
358  *
359  * @return string
360  */
361  public function requestAutosuggest($params, $attributes = array())
362  {
363  return $this->_request($this->getAutosuggestUrl(), $params, $attributes);
364  }
365 
366  /**
367  * Requesting for search data
368  *
369  * @param array $params url params
370  * @param array $attributes requested attributes
371  *
372  * @return string
373  */
374  public function requestSearch($params, $attributes = array())
375  {
376  return $this->_request($this->getSearchUrl(), $params, $attributes);
377  }
378 
379  /**
380  * Prepare API response. Convert response to useful form.
381  *
382  * @param array $response prepared response
383  *
384  * @return array|bool prepared object.
385  *
386  */
387  private static function _prepareResponse($response)
388  {
389  $responseData = unserialize($response);
390  if (@$responseData['status'] == 'ok') {
391  unset($responseData['status']);
392  if (count($responseData) > 0) {
393  return array_shift($responseData);
394  }
395  return false;
396  } else {
397  Yii::log(print_r($responseData, true), CLogger::LEVEL_TRACE);
398  }
399  return false;
400  }
401 }