<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>webbricks &#187; behavior</title>
	<atom:link href="http://blog.grzegorzpawlik.com/tag/behavior/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.grzegorzpawlik.com</link>
	<description>Doświadczenie, to coś, co zdobywamy tuż po chwili w której było nam potrzebne ...</description>
	<lastBuildDate>Tue, 07 Feb 2012 10:09:24 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>ImageBehavior &#8211; uploaduj pliki prosto do bazy</title>
		<link>http://blog.grzegorzpawlik.com/2009/03/imagebehavior-uploaduj-pliki-prosto-do-bazy/</link>
		<comments>http://blog.grzegorzpawlik.com/2009/03/imagebehavior-uploaduj-pliki-prosto-do-bazy/#comments</comments>
		<pubDate>Tue, 03 Mar 2009 13:01:00 +0000</pubDate>
		<dc:creator>Greg</dc:creator>
				<category><![CDATA[CakePHP]]></category>
		<category><![CDATA[behavior]]></category>
		<category><![CDATA[DRY]]></category>
		<category><![CDATA[RAD]]></category>

		<guid isPermaLink="false">http://meta.vipserv.org/blog.grzegorzpawlik.com/?p=56</guid>
		<description><![CDATA[Jakiś czas temu napisałem o pomyśle cake&#8217;owego Behavior (http://webbricks.blogspot.com/2009/02/pliki-w-formie-binarnej-w-bazie.html). Poniżej prezentuję pierwsze podejście do problemu: /** * ImageBehavior - take best from database blobs adn file image storage * requires ’content’ field that is a blob (mediumblob or longblob), and &#8230; <a href="http://blog.grzegorzpawlik.com/2009/03/imagebehavior-uploaduj-pliki-prosto-do-bazy/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Jakiś czas temu napisałem o pomyśle cake&#8217;owego Behavior (<a href="http://webbricks.blogspot.com/2009/02/pliki-w-formie-binarnej-w-bazie.html">http://webbricks.blogspot.com/2009/02/pliki-w-formie-binarnej-w-bazie.html</a>). Poniżej prezentuję pierwsze podejście do problemu:</p>
<p><code lang="php"><br />
/**<br />
 * ImageBehavior - take best from database blobs adn file image storage</p>
<p> * requires ’content’ field that is a blob (mediumblob or longblob), and<br />
 * ’ext’ varchar(10) field  and</p>
<p> * ’modified’ datetime field<br />
 * @author Grzegorz Pawlik<br />
 * @version 1.0<br />
 */<br />
class ImageBehavior extends ModelBehavior {</p>
<p>   /**<br />
    * directory in which cached files will be stored<br />
    *<br />
    * @var string<br />
    */<br />
   var $cacheSubdir = ‘filecache’;</p>
<p>   /**<br />
    * if set to false - never check if cached file is present (nor actual)<br />
    *</p>
<p>    * @var bool<br />
    */<br />
   var $usecache = true;</p>
<p>   function setup(&#038;$Model) {<br />
      // no setup at this time</p>
<p>   }</p>
<p>   /**<br />
    * Insert proper blob when standard data after upload is present<br />
    *<br />
    * @param object $Model</p>
<p>    * @return bool true<br />
    */<br />
   function beforeSave(&#038;$Model) {</p>
<p>      if(isset($Model->data[$Model->name]['file']['tmp_name']) &#038;&#038; is_uploaded_file($Model->data[$Model->name]['file']['tmp_name'])) {</p>
<p>      // podnieś wyżej parametry<br />
      $Model->data[$Model->name] = array_merge($Model->data[$Model->name],  $Model->data[$Model->name]['file']);</p>
<p>      // przygotuj blob<br />
      $this->_prepareBlob($Model);</p>
<p>      $this->_getExt($Model);<br />
      }</p>
<p>      return true;<br />
   }</p>
<p>   /**<br />
    * prepares blob contents<br />
    *<br />
    * @param object $Model</p>
<p>    */<br />
   function _prepareBlob(&#038;$Model) {<br />
      App::import(‘Core’, ‘File’);<br />
      $file = new File($Model->data['Medium']['tmp_name'], false);</p>
<p>      $content = $this->addSlashes( $file->read() );<br />
      $Model->data[$Model->name]['content'] = $content;</p>
<p>   }</p>
<p>   /**<br />
    * Get uploaded file extension<br />
    *<br />
    * @param object $Model<br />
    */<br />
   function _getExt(&#038;$Model) {</p>
<p>      $file = explode(‘.’, $Model->data['Medium']['name']);<br />
      $ext = array_pop($file);</p>
<p>      $Model->data[$Model->name]['ext'] = $ext;<br />
   }</p>
<p>   /**<br />
    * replace blob contents with file path</p>
<p>    * After reading database checks if cached file is present. If not creates it (from blob contents) and</p>
<p>    * returns a ’file’ field with path relative to /app/webroot/img<br />
    *<br />
    *<br />
    * @param object $model</p>
<p>    * @param array $results<br />
    * @param unknown_type $primary<br />
    * @return unknown<br />
    */<br />
   function afterFind(&#038;$model, $results, $primary) {</p>
<p>      foreach($results as $key => $val) {</p>
<p>         $relpath = $this->cacheSubdir . DS .</p>
<p>                 $val[$model->name]['id'] . ‘_’ . $model->name . ‘_’ .</p>
<p>                 $val[$model->name]['modified'] . ‘.’ . $val[$model->name]['ext'];</p>
<p>         $relpath = str_replace( array(‘ ’, ‘:’) , ‘_’, $relpath);</p>
<p>         $fullpath = IMAGES . $relpath;</p>
<p>         if(!file_exists($fullpath) || !$this->usecache ) {<br />
            file_put_contents($fullpath, $this->stripSlashes($results[$key][$model->name]['content']));</p>
<p>         }</p>
<p>         $results[$key][$model->name]['file'] = $relpath;<br />
         // remove blob from results (its messy when You want to output results in debug)</p>
<p>         unset($results[$key][$model->name]['content']);<br />
      }<br />
      return $results;<br />
   }</p>
<p>   /**<br />
    * add slashes (just wrapper)<br />
    *<br />
    * @param string $string<br />
    * @return string with slashes<br />
    */</p>
<p>   function addSlashes($string) {<br />
      return addslashes($string);<br />
   }</p>
<p>   /**<br />
    * strip slashes (just wrapper)</p>
<p>    *<br />
    * @param string $string<br />
    * @return string without slashes<br />
    */<br />
   function stripSlashes($string) {</p>
<p>      return stripslashes($string);<br />
   }<br />
}<br />
</code></p>
<p>Zasada działania jest dość prosta. Wyjaśnię ją na przykładzie.<br />
Tabela media:<br />
<code lang="mysql"><br />
CREATE TABLE IF NOT EXISTS `media` (<br />
`id` int(11) NOT NULL auto_increment,<br />
`name` varchar(50) NOT NULL,</p>
<p>`ext` varchar(10) NOT NULL,<br />
`content` longblob NOT NULL,<br />
`size` int(11) NOT NULL,<br />
`created` datetime NOT NULL,<br />
`modified` datetime NOT NULL,</p>
<p>`type` varchar(20) NOT NULL,<br />
PRIMARY KEY  (`id`)<br />
) ENGINE=MyISAM;<br />
</code><br />
Model:<br />
<code lang="php"><br />
class Medium extends AppModel {</p>
<p>var $name = ‘Medium’;<br />
var $actsAs = array(‘Image’);</p>
<p>}<br />
</code></p>
<p>Kontroler:<br />
<code lang="php"><br />
class MediaController extends AppController {</p>
<p>var $name = ‘Media’;<br />
var $helpers = array(‘Html’, ‘Form’);<br />
function index() {</p>
<p>$this->set(‘media’, $this->Medium->findAll());<br />
}</p>
<p>function add() {<br />
if(!empty($this->data)) {<br />
$this->Medium->save($this->data);</p>
<p>}<br />
}</p>
<p>}<br />
</code></p>
<p>Przy uploadzie ImageBehavior oczekuje, że plik będzie przekazany w poly ModelName.file (tutaj Media.file).</p>
<p>add.ctp:<br />
<code lang="php"><br />
<?php<br />
echo $form->create(<br />
array(‘url’ => array(<br />
‘controller’ => ‘media’,</p>
<p>‘action’ => ‘add’<br />
),<br />
‘enctype’ => ‘multipart/form-data’<br />
)<br />
);<br />
?></p>
<p><?php echo $form->file(‘Medium.file’); ?><br />
<?php echo $form->end(’submit’); ?><br />
</code></p>
<p>Przy odczycie dzieje się to co mnie najbardziej interesowało. Zamiast dostać zawartość (BLOB) pliku, dostajemy w polu file ścieżkę (relatywną do app/webroot/img). Domyślne ustawienia wymagają, żeby był tam katalog filecache (z możliwością zapisu). Przy operacji read behavior sprawdzi, czy istnieje aktualy plik w filecache, i jesli nie &#8211; utworzy go.</p>
<p>index.ctp:<br />
<code lang="php"><br />
<?php foreach($media as $medium): ?><br />
<?php echo $html->image($medium['Medium']['file']); ?><br />
</code></p>
<p>To rozwiązanie ma przynajmniej dwa zauważalne braki:</p>
<ol>
<li>Gdy dodamy taki plik do treści np. postu, po jego updacie &#8211; nie będą widoczne zmiany</li>
<li>Dobrze byłoby, gdyby przy operacji read nie zwracał zawartości BLOB (ważne, gdy baza jest gdzieś dalej), ale odpytywał tylko wtedy, gdy jest potrzebne zaktualizowanie zawartości pliku w filecache.</li>
</ol>
<p>To rzeczy do zrobienia w kolejnym podejściu ;)</p>
<hr/>
Aktualizacja: po umieszczeniu tego pomysłu na bakery niejaki Travis Rowland wrzucił ciekawe poprawki. Nie miałem okazji ich wypróbować, ale dla zainteresowanych: <a href="http://bakery.cakephp.org/articles/view/imagebehavior-best-from-database-blobs-and-file-storage">http://bakery.cakephp.org/articles/view/imagebehavior-best-from-database-blobs-and-file-storage</a></p>
<!-- PHP 5.x -->]]></content:encoded>
			<wfw:commentRss>http://blog.grzegorzpawlik.com/2009/03/imagebehavior-uploaduj-pliki-prosto-do-bazy/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Co się dzieje, gdy dane są nie tylko w bazie?</title>
		<link>http://blog.grzegorzpawlik.com/2008/10/co-sie-dzieje-gdy-dane-sa-nie-tylko-w-bazie/</link>
		<comments>http://blog.grzegorzpawlik.com/2008/10/co-sie-dzieje-gdy-dane-sa-nie-tylko-w-bazie/#comments</comments>
		<pubDate>Mon, 06 Oct 2008 08:30:00 +0000</pubDate>
		<dc:creator>Greg</dc:creator>
				<category><![CDATA[Inne]]></category>
		<category><![CDATA[behavior]]></category>
		<category><![CDATA[CakePHP]]></category>

		<guid isPermaLink="false">http://meta.vipserv.org/blog.grzegorzpawlik.com/?p=39</guid>
		<description><![CDATA[Z tym problemem często spotykam się w pracy. Standardowe zagadnienie &#8211; klient chce wrzucać obrazki na stronę, a my ze względu na bazę zapisujemy je jako pliki, a w bazie co najwyżej ścieżkę do niego.No i niestety przeniesienie systemu na &#8230; <a href="http://blog.grzegorzpawlik.com/2008/10/co-sie-dzieje-gdy-dane-sa-nie-tylko-w-bazie/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Z tym problemem często spotykam się w pracy.</p>
<p>Standardowe zagadnienie &#8211; klient chce wrzucać obrazki na stronę, a my ze względu na bazę zapisujemy je jako pliki, a w bazie co najwyżej ścieżkę do niego.<br />No i niestety przeniesienie systemu na inny serwer (np. produkcyjny) to, oprócz kopiowania kodu i bazy, przenoszenie multimediów, które nie zawsze jest miłe i przyjemne.</p>
<p>Dlatego od jakiegoś czasu chodzi mi po głowie pewna koncepcja, która ten problem mogłaby rozwiązać.<br />Otóż pliki binarne, podczas uploadu należało by jednak zapisać w bazie. Do tego należałoby opracować komponent, który w przypadku żądania obrazka o id = 1 sprawdziłby odpowiedni katalog i po znalezieniu go &#8211; zwrócił jako odpowiedź. Z kolei przy jego braku w systemie plików &#8211; utworzył takowy na podstawie danych w bazie i w standardowy sposób zwrócił plik jako odpowiedź.</p>
<p>Świetnie by się do tego nadawały cake&#8217;owe behaviors. Do tego można by go sprząc z jeszcze jedną funkcjonalnością- plik mógłby być w bazie zapisywany (w razie podmiany zawartości) za każdym razem pod inną nazwą (np. id_kolejny_numer_wersji). Dzięki temu możnaby tym plikom ustawić nagłówki Expire z odległą przyszłością i korzystać z dobrodziejstw bufora przeglądarek&#8230;</p>
<!-- PHP 5.x -->]]></content:encoded>
			<wfw:commentRss>http://blog.grzegorzpawlik.com/2008/10/co-sie-dzieje-gdy-dane-sa-nie-tylko-w-bazie/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>

