I've been working on this for the last few days, trying to learn about OOP design patterns, and I was hoping I could get some feedback on it. I'm very new to design patterns in general.
As the title suggests, I'm attempting a cache system built into a factory pattern, having a static method of Cache return an implementation class. The implementation classes are all forced to implement the CacheMethod interface to be sure they all have the appropriate functionality. This is my first time using an interface class and also my first attempt at namespaces, those areas may need a little extra attention.
Here's the factory Cache class, which holds one static method as described above. Please ignore the tests at the bottom, I just used those to be sure it worked before posting here.
<?php
namespace NovaComponents\Cache;
use NovaComponents\Cache\Implementation as impl;
class Cache
{
public static function file($name='', $type='json')
{
$files = array(
'json' => __DIR__ . '/Implementation/CacheFileJSON.php',
'xml' => __DIR__ . '/Implementation/CacheFileXML.php',
'yaml' => __DIR__ . '/Implementation/CacheFileYAML.php',
'plain' => __DIR__ . '/Implementation/CacheFilePlain.php'
);
if (empty($name) || empty($type)) {
throw new \Exception('Invalid parameter error.');
}
if (!array_key_exists($type, $files)) {
throw new \Exception('Invalid type: ' . $type);
}
$cacheDir = new \SplFileInfo(__DIR__ . '/data/');
if (!$cacheDir->isReadable() || !$cacheDir->isWritable()) {
throw new \Exception('Bad directory permissions for ' . __DIR__ . '/data/: ' . $cacheDir->getPerms());
}
$filename = __DIR__ . '/data/' . $name . '.' . $type;
// Make sure we have a set or rules to follow.
require_once(__DIR__ . '/InterfaceCache.php');
require_once($files[$type]);
switch ($type)
{
case 'json':
$cacheFileObject = new impl\CacheFileJSON(new \SplFileObject($filename, 'a+'), $filename);
break;
case 'xml':
$cacheFileObject = new impl\CacheFileXML(new \SplFileObject($filename, 'a+'), $filename);
break;
case 'YAML':
$cacheFileObject = new impl\CacheFileYAML(new \SplFileObject($filename, 'a+'), $filename);
break;
case 'plain':
$cacheFileObject = new impl\CacheFilePlain(new \SplFileObject($filename, 'a+'), $filename);
break;
default:
throw new Exception('Invalid file type.');
}
// Make sure that the file controller implements the model interface.
if (!($cacheFileObject instanceof CacheModel)) {
throw new \Exception('The file controller <strong>must</strong> implement the CacheModel interface.');
}
return $cacheFileObject;
}
}
$test = Cache::file('test', 'json');
$test->write(array('test', 'test'));
echo $test;
Now here's the Interface class that all the implementations are supposed to follow.
<?php
namespace NovaComponents\Cache;
interface CacheModel
{
public function __construct(\SplFileObject $file, $path);
public function write(array $data);
public function read($format_array=false);
public function format(array $data);
public function delete();
public function truncate();
public function __toString();
}
Finally one of the implementation classes. I'm only able to post the JSON one, as that's the only one I've finished so far.
<?php
namespace NovaComponents\Cache\Implementation;
use NovaComponents\Cache as base;
class CacheFileJSON implements base\CacheModel
{
private $file, $path;
public function __construct(\SplFileObject $file, $path)
{
$this->file = $file;
$this->path = $path;
}
public function write(array $data)
{
$this->file->fwrite(json_encode($data));
return $this->read();
}
public function read($format_array=false)
{
$this->file->rewind();
$return_data = '';
while (!$this->file->eof())
{
$return_data = $this->file->fgets();
}
return $format_array === true ? json_decode($return_data, true) : $return_data;
}
public function format(array $data)
{
return json_encode($data);
}
public function truncate()
{
$this->file->ftruncate();
}
public function delete()
{
return @unlink($this->path);
}
public function __toString()
{
return $this->read();
}
}