1 <?php
  2 /**
  3  * @package     Joomla.Platform
  4  * @subpackage  Cache
  5  *
  6  * @copyright   Copyright (C) 2005 - 2017 Open Source Matters, Inc. All rights reserved.
  7  * @license     GNU General Public License version 2 or later; see LICENSE
  8  */
  9 
 10 defined('JPATH_PLATFORM') or die;
 11 
 12 /**
 13  * Public cache handler
 14  *
 15  * @since  11.1
 16  * @note   As of 4.0 this class will be abstract
 17  */
 18 class JCacheController
 19 {
 20     /**
 21      * JCache object
 22      *
 23      * @var    JCache
 24      * @since  11.1
 25      */
 26     public $cache;
 27 
 28     /**
 29      * Array of options
 30      *
 31      * @var    array
 32      * @since  11.1
 33      */
 34     public $options;
 35 
 36     /**
 37      * Constructor
 38      *
 39      * @param   array  $options  Array of options
 40      *
 41      * @since   11.1
 42      */
 43     public function __construct($options)
 44     {
 45         $this->cache = new JCache($options);
 46         $this->options = & $this->cache->_options;
 47 
 48         // Overwrite default options with given options
 49         foreach ($options as $option => $value)
 50         {
 51             if (isset($options[$option]))
 52             {
 53                 $this->options[$option] = $options[$option];
 54             }
 55         }
 56     }
 57 
 58     /**
 59      * Magic method to proxy JCacheController method calls to JCache
 60      *
 61      * @param   string  $name       Name of the function
 62      * @param   array   $arguments  Array of arguments for the function
 63      *
 64      * @return  mixed
 65      *
 66      * @since   11.1
 67      */
 68     public function __call($name, $arguments)
 69     {
 70         return call_user_func_array(array($this->cache, $name), $arguments);
 71     }
 72 
 73     /**
 74      * Returns a reference to a cache adapter object, always creating it
 75      *
 76      * @param   string  $type     The cache object type to instantiate; default is output.
 77      * @param   array   $options  Array of options
 78      *
 79      * @return  JCacheController
 80      *
 81      * @since   11.1
 82      * @throws  RuntimeException
 83      */
 84     public static function getInstance($type = 'output', $options = array())
 85     {
 86         self::addIncludePath(JPATH_PLATFORM . '/joomla/cache/controller');
 87 
 88         $type = strtolower(preg_replace('/[^A-Z0-9_\.-]/i', '', $type));
 89 
 90         $class = 'JCacheController' . ucfirst($type);
 91 
 92         if (!class_exists($class))
 93         {
 94             // Search for the class file in the JCache include paths.
 95             jimport('joomla.filesystem.path');
 96 
 97             $path = JPath::find(self::addIncludePath(), strtolower($type) . '.php');
 98 
 99             if ($path !== false)
100             {
101                 JLoader::register($class, $path);
102             }
103 
104             // The class should now be loaded
105             if (!class_exists($class))
106             {
107                 throw new RuntimeException('Unable to load Cache Controller: ' . $type, 500);
108             }
109         }
110 
111         return new $class($options);
112     }
113 
114     /**
115      * Add a directory where JCache should search for controllers. You may either pass a string or an array of directories.
116      *
117      * @param   array|string  $path  A path to search.
118      *
119      * @return  array  An array with directory elements
120      *
121      * @since   11.1
122      */
123     public static function addIncludePath($path = '')
124     {
125         static $paths;
126 
127         if (!isset($paths))
128         {
129             $paths = array();
130         }
131 
132         if (!empty($path) && !in_array($path, $paths))
133         {
134             jimport('joomla.filesystem.path');
135             array_unshift($paths, JPath::clean($path));
136         }
137 
138         return $paths;
139     }
140 
141     /**
142      * Get stored cached data by ID and group
143      *
144      * @param   string  $id     The cache data ID
145      * @param   string  $group  The cache data group
146      *
147      * @return  mixed  Boolean false on no result, cached object otherwise
148      *
149      * @since   11.1
150      * @deprecated  4.0  Implement own method in subclass
151      */
152     public function get($id, $group = null)
153     {
154         $data = $this->cache->get($id, $group);
155 
156         if ($data === false)
157         {
158             $locktest = $this->cache->lock($id, $group);
159 
160             // If locklooped is true try to get the cached data again; it could exist now.
161             if ($locktest->locked === true && $locktest->locklooped === true)
162             {
163                 $data = $this->cache->get($id, $group);
164             }
165 
166             if ($locktest->locked === true)
167             {
168                 $this->cache->unlock($id, $group);
169             }
170         }
171 
172         // Check again because we might get it from second attempt
173         if ($data !== false)
174         {
175             // Trim to fix unserialize errors
176             $data = unserialize(trim($data));
177         }
178 
179         return $data;
180     }
181 
182     /**
183      * Store data to cache by ID and group
184      *
185      * @param   mixed    $data        The data to store
186      * @param   string   $id          The cache data ID
187      * @param   string   $group       The cache data group
188      * @param   boolean  $wrkarounds  True to use wrkarounds
189      *
190      * @return  boolean  True if cache stored
191      *
192      * @since   11.1
193      * @deprecated  4.0  Implement own method in subclass
194      */
195     public function store($data, $id, $group = null, $wrkarounds = true)
196     {
197         $locktest = $this->cache->lock($id, $group);
198 
199         if ($locktest->locked === false && $locktest->locklooped === true)
200         {
201             // We can not store data because another process is in the middle of saving
202             return false;
203         }
204 
205         $result = $this->cache->store(serialize($data), $id, $group);
206 
207         if ($locktest->locked === true)
208         {
209             $this->cache->unlock($id, $group);
210         }
211 
212         return $result;
213     }
214 }
215