Don't put large blob data in objectcache
[gitphp.git] / include / git / blob / Blob.class.php
blob:a/include/git/blob/Blob.class.php -> blob:b/include/git/blob/Blob.class.php
<?php <?php
/** /**
* Represents a single blob * Represents a single blob
* *
* @author Christopher Han <xiphux@gmail.com> * @author Christopher Han <xiphux@gmail.com>
* @copyright Copyright (c) 2010 Christopher Han * @copyright Copyright (c) 2010 Christopher Han
* @package GitPHP * @package GitPHP
* @subpackage Git\Blob * @subpackage Git\Blob
*/ */
class GitPHP_Blob extends GitPHP_FilesystemObject implements GitPHP_Observable_Interface, GitPHP_Cacheable_Interface class GitPHP_Blob extends GitPHP_FilesystemObject implements GitPHP_Observable_Interface, GitPHP_Cacheable_Interface
{ {
   
/** /**
  * Large blob threshold
  *
  * @var int
  */
  const LargeBlobSize = 5242880; // 5 megs
   
  /**
* The blob data * The blob data
* *
* @var string * @var string
*/ */
protected $data; protected $data;
   
/** /**
* Whether data has been read * Whether data has been read
* *
* @var boolean * @var boolean
*/ */
protected $dataRead = false; protected $dataRead = false;
   
/** /**
* The blob size * The blob size
* *
* @var int * @var int
*/ */
protected $size = null; protected $size = null;
   
/** /**
* Whether the data is binary * Whether the data is binary
* *
* @var boolean|null * @var boolean|null
*/ */
protected $binary = null; protected $binary = null;
   
/** /**
* Whether data has been encoded for serialization * Whether data has been encoded for serialization
* *
* @var boolean * @var boolean
*/ */
protected $dataEncoded = false; protected $dataEncoded = false;
   
/** /**
* Observers * Observers
* *
* @var array * @var array
*/ */
protected $observers = array(); protected $observers = array();
   
/** /**
* Data load strategy * Data load strategy
* *
* @var GitPHP_BlobLoadStrategy_Interface * @var GitPHP_BlobLoadStrategy_Interface
*/ */
protected $strategy; protected $strategy;
   
/** /**
* Instantiates object * Instantiates object
* *
* @param GitPHP_Project $project the project * @param GitPHP_Project $project the project
* @param string $hash object hash * @param string $hash object hash
* @param GitPHP_BlobLoadStrategy_Interface $strategy load strategy * @param GitPHP_BlobLoadStrategy_Interface $strategy load strategy
*/ */
public function __construct($project, $hash, GitPHP_BlobLoadStrategy_Interface $strategy) public function __construct($project, $hash, GitPHP_BlobLoadStrategy_Interface $strategy)
{ {
parent::__construct($project, $hash); parent::__construct($project, $hash);
   
if (!$strategy) if (!$strategy)
throw new Exception('Blob load strategy is required'); throw new Exception('Blob load strategy is required');
   
$this->SetStrategy($strategy); $this->SetStrategy($strategy);
} }
   
/** /**
* Gets the blob data * Gets the blob data
* *
* @param boolean $explode true to explode data into an array of lines * @param boolean $explode true to explode data into an array of lines
* @return string|string[] blob data * @return string|string[] blob data
*/ */
public function GetData($explode = false) public function GetData($explode = false)
{ {
if (!$this->dataRead) if (!$this->dataRead)
$this->ReadData(); $this->ReadData();
   
if ($this->dataEncoded) if ($this->dataEncoded)
$this->DecodeData(); $this->DecodeData();
   
if ($explode) if ($explode)
return explode("\n", $this->data); return explode("\n", $this->data);
else else
return $this->data; return $this->data;
} }
   
/** /**
* Set the load strategy * Set the load strategy
* *
* @param GitPHP_BlobLoadStrategy_Interface $strategy load strategy * @param GitPHP_BlobLoadStrategy_Interface $strategy load strategy
*/ */
public function SetStrategy(GitPHP_BlobLoadStrategy_Interface $strategy) public function SetStrategy(GitPHP_BlobLoadStrategy_Interface $strategy)
{ {
if (!$strategy) if (!$strategy)
return; return;
   
$this->strategy = $strategy; $this->strategy = $strategy;
} }
   
/** /**
* Reads the blob data * Reads the blob data
*/ */
private function ReadData() private function ReadData()
{ {
$this->dataRead = true; $this->dataRead = true;
   
$this->data = $this->strategy->Load($this); $this->data = $this->strategy->Load($this);
   
$this->dataEncoded = false; $this->dataEncoded = false;
   
foreach ($this->observers as $observer) { foreach ($this->observers as $observer) {
$observer->ObjectChanged($this, GitPHP_Observer_Interface::CacheableDataChange); $observer->ObjectChanged($this, GitPHP_Observer_Interface::CacheableDataChange);
} }
} }
   
/** /**
* Gets the blob size * Gets the blob size
* *
* @return integer size * @return integer size
*/ */
public function GetSize() public function GetSize()
{ {
if ($this->size === null) { if ($this->size === null) {
$this->size = $this->strategy->Size($this); $this->size = $this->strategy->Size($this);
} }
return $this->size; return $this->size;
} }
   
/** /**
* Sets the blob size * Sets the blob size
* *
* @param integer $size size * @param integer $size size
*/ */
public function SetSize($size) public function SetSize($size)
{ {
$this->size = $size; $this->size = $size;
} }
   
/** /**
* Tests if this blob is a binary file * Tests if this blob is a binary file
* *
* @return boolean true if binary file * @return boolean true if binary file
*/ */
public function IsBinary() public function IsBinary()
{ {
if ($this->binary === null) { if ($this->binary === null) {
$data = $this->GetData(); $data = $this->GetData();
if (strlen($data) > 8000) if (strlen($data) > 8000)
$data = substr($data, 0, 8000); $data = substr($data, 0, 8000);
   
$this->binary = (strpos($data, chr(0)) !== false); $this->binary = (strpos($data, chr(0)) !== false);
} }
   
return $this->binary; return $this->binary;
} }
   
/** /**
* Encodes data so it can be serialized safely * Encodes data so it can be serialized safely
*/ */
private function EncodeData() private function EncodeData()
{ {
if ($this->dataEncoded) if ($this->dataEncoded)
return; return;
   
$this->data = base64_encode($this->data); $this->data = base64_encode($this->data);
   
$this->dataEncoded = true; $this->dataEncoded = true;
} }
   
/** /**
* Decodes data after unserialization * Decodes data after unserialization
*/ */
private function DecodeData() private function DecodeData()
{ {
if (!$this->dataEncoded) if (!$this->dataEncoded)
return; return;
   
$this->data = base64_decode($this->data); $this->data = base64_decode($this->data);
   
$this->dataEncoded = false; $this->dataEncoded = false;
} }
   
/** /**
* Add a new observer * Add a new observer
* *
* @param GitPHP_Observer_Interface $observer observer * @param GitPHP_Observer_Interface $observer observer
*/ */
public function AddObserver($observer) public function AddObserver($observer)
{ {
if (!$observer) if (!$observer)
return; return;
   
if (array_search($observer, $this->observers) !== false) if (array_search($observer, $this->observers) !== false)
return; return;
   
$this->observers[] = $observer; $this->observers[] = $observer;
} }
   
/** /**
* Remove an observer * Remove an observer
* *
* @param GitPHP_Observer_Interface $observer observer * @param GitPHP_Observer_Interface $observer observer
*/ */
public function RemoveObserver($observer) public function RemoveObserver($observer)
{ {
if (!$observer) if (!$observer)
return; return;
   
$key = array_search($observer, $this->observers); $key = array_search($observer, $this->observers);
   
if ($key === false) if ($key === false)
return; return;
   
unset($this->observers[$key]); unset($this->observers[$key]);
} }
   
/** /**
* Called to prepare the object for serialization * Called to prepare the object for serialization
* *
* @return string[] list of properties to serialize * @return string[] list of properties to serialize
*/ */
public function __sleep() public function __sleep()
{ {
if (!$this->dataEncoded) $properties = array('data', 'dataRead', 'dataEncoded', 'binary', 'size');
   
  if ($this->dataRead && strlen($this->data) > GitPHP_Blob::LargeBlobSize) {
  $this->data = null;
  $this->dataRead = false;
  }
   
  if ($this->dataRead && !$this->dataEncoded)
$this->EncodeData(); $this->EncodeData();
   
$properties = array('data', 'dataRead', 'dataEncoded', 'binary', 'size');  
   
return array_merge($properties, parent::__sleep()); return array_merge($properties, parent::__sleep());
} }
   
/** /**
* Gets the cache key to use for this object * Gets the cache key to use for this object
* *
* @return string cache key * @return string cache key
*/ */
public function GetCacheKey() public function GetCacheKey()
{ {
return GitPHP_Blob::CacheKey($this->project->GetProject(), $this->hash); return GitPHP_Blob::CacheKey($this->project->GetProject(), $this->hash);
} }
   
/** /**
* Generates a blob cache key * Generates a blob cache key
* *
* @param string $proj project * @param string $proj project
* @param string $hash hash * @param string $hash hash
* @return string cache key * @return string cache key
*/ */
public static function CacheKey($proj, $hash) public static function CacheKey($proj, $hash)
{ {
return 'project|' . $proj . '|blob|' . $hash; return 'project|' . $proj . '|blob|' . $hash;
} }
   
} }
   
comments