TightMVC

От доста време базирам всичките си проекти на MVC PHP frameworks. Наскоро обаче се натъкнах на един проблем – почти няма framework, който да поддържа само основните неща – дори любимият ми CodeIgniter е тлъстичък, когато стане въпрос за малки сайтове – макар да не се използват по подразбиране, библиотеките му си седят в дистрибуцията и заемат ненужно (според мен) място. Да не говорим какъв слон е ZendFramework, въпреки всичките му предимства.

За някои от проектите си наистина имах нужда от нещо доста по-леко, възможно най-минимална имаплементация на MVC pattern-a. Преди време бях попадал на една много добра статия от Anand Garg в която той даваше много добри съвети (и код) за разработване на собствен MVC framework.

От доста време базирам всичките си проекти на MVC PHP frameworks. Наскоро обаче се натъкнах на един проблем – почти няма framework, който да поддържа само основните неща – дори любимият ми CodeIgniter е тлъстичък, когато стане въпрос за малки сайтове. Mакар да не се използват по подразбиране, библиотеките му си седят в дистрибуцията и заемат ненужно (според мен) място. Да не говорим какъв слон е ZendFramework, въпреки всичките му предимства.

За някои от проектите си наистина имах нужда от нещо доста по-леко, възможно най-минимална имаплементация на MVC pattern-a. Преди време бях попадал на една много добра статия от Anand Garg в която той даваше много добри съвети (и код) за разработване на собствен MVC framework.

Започнах от неговия код, целейки само и единствено поддръжка на PHP5. Изхвърлих всичко ненужно, добавих поддръжка на PDO за комуникация с базата данни, добавих поддръжка за Layouts, Helpers и Modules и в крайна сметка получих един доста приличен framework с много малък codebase.

Резултатът е качен тук, а не много пълна документация можете да откриете във wiki-то към проекта тук.

На който му се стори интересно – може да тегли, тества, праща bug reports и т.н.

plupload and CodeIgniter 1.7.2

CodeIgniter logo

Ако някога сте ползвали чудесният плъгин за качване на файлове на Moxiecode, plupload, то вероятно сте харесали решението за качване на много файлове наведнъж.

Ако пък сте ползвали CodeIgniter, би трябвало в момента, в който сте погледнали примера в download-натия файл от сайта на plupload, да сте забелязали променливите в URL-a (т.нар. query string). Точно те са причината връзката между CodeIgniter и plupload да не се получава.

CodeIgniter logo

Ако някога сте ползвали чудесният плъгин за качване на файлове на Moxiecode, plupload, то вероятно сте харесали решението за качване на много файлове наведнъж.

Ако пък сте ползвали CodeIgniter, би трябвало в момента, в който сте погледнали примера в download-натия файл от сайта на plupload, да сте забелязали променливите в URL-a (т.нар. query string). Точно те са причината връзката между CodeIgniter и plupload да не се получава.

Аз лично не понасям query_strings, а използването на $_GET параметри, поне според мен, трябва да става в URI. Това е и поведението на CodeIgniter, в документацията на който е написано следното:

GET, POST, and COOKIE Data

GET data is simply disallowed by CodeIgniter since the system utilizes URI segments rather than traditional URL query strings (unless you have the query string option enabled in your config file). The global GET array is unset by the Input class during system initialization.

Накратко, за да си решите проблема с интеграцията на plupload и CodeIgniter ще трябва малко повечко работа.

Първо – plupload изпраща името на файла, който се качва в момента като query string променлива, която би трябвало да получите като $_GET параметър. Input class-ът на CodeIgniter обаче маха целия $_GET, затова ще embed-нем името на файла в URI. Същото ще стане и с двете променливи chunk и chunks. Целта ни е да получим URL от сорта на:

http://example.com/uploader/upload_file/filename.ext/0/4

където 0 и 4 са стойностите съответно на chunk и chunks. Забележете, че тези стойности варират според големината на качвания файл и стойността на конфигурационния параметър chunk_size.

За пример ще взема html5 widget-ът. Малката промяна, която престои да направим, е във plupload.js, в частност във функцията :

buildUrl : function(url, items) {
  var query = '';
  plupload.each(items, function(value, name) {
    query += (query ? '&' : '') + encodeURIComponent(name) + 
    '=' + encodeURIComponent(value);
  });
 
  if (query) {
   url += (url.indexOf('?') > 0 ? '&' : '?') + query;
  }
 
	return url;
}

Крайната цел е да изглежда така:

buildUrl : function(url, items) {
  var query = '';
  plupload.each(items, function(value, name) {
    query += '/' + encodeURIComponent(value);
  });
 
  if (query) {
   url += query;
  }
 
	return url;
}

При това положение достатъчно е в controller-a да имаме следния метод:

<?php
class Uploader extends Controller {
  function Uploader()
  {
    parent::Controller();
  }
 
  function upload_file($fileName, $chunk, $chunks)
  {
    // Validate input
    if ((filter_var($chunk, FILTER_VALIDATE_INT) === TRUE) || 
    (filter_var($chunks, FILTER_VALIDATE_INT) === TRUE))
    {
       die('{"jsonrpc" : "2.0", "error" : {"code": 104, "message": "Incorrect upload data."}, "id" : "id"}');
    }
 
    // HTTP headers for no cache etc
    header('Content-type: text/plain; charset=UTF-8');
    header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
    header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
    header("Cache-Control: no-store, no-cache, must-revalidate");
    header("Cache-Control: post-check=0, pre-check=0", false);
    header("Pragma: no-cache");
 
    // Settings
    $targetDir = './some_target_dir_name';
    $cleanupTargetDir = false; // Remove old files
    $maxFileAge = 60 * 60; // Temp file age in seconds
 
    // 5 minutes execution time
    @set_time_limit(5 * 60);
 
    // Clean the fileName for security reasons
    $fileName = preg_replace ('/_(jpg|jpeg|png|gif)$/i', '.$1', $fileName);
    $fileName = preg_replace ('/[^\w\.\-_]+/', '', $fileName);
 
    // upload.php code from the plupload /example dir follows 
    // (from line 37 on)
  }
}

По този начин CodeIgniter извлича стойностите за chunk и chunks директно от URI-то и plupload започва да работи по очаквания начин. За flash-версията (заради IE и Opera) ще трябва да вземете нещата от src/flash директорията и да преправите src/com/plupload/File.as със следния patch:

Masonry for Prototype JS

Prototype Masonry in action

За един от проектите си имах нужда от layout manager, който да разполага обекти в определено пространство с възможно най-малка загуба на място. Решението беше да си отделя един ден и да port-на jQuery Masonry към Prototype framework. Еквивалент на първото демо от сайта на David можете да намерите на Masonry Prototype страницата. От нея можете и да свалите и plugin-а, в случай че ви трябва.

Prototype Masonry in action

Prototype JS е страхотна библиотека за работа с JavaScript, документирана перфектно и с богата селекция от ефекти, благодарение на script.aculo.us.

За един от проектите си имах нужда от layout manager, който да разполага обекти в определено пространство с възможно най-малка загуба на място. Търсейки такова решение разбрах две неща: първо, читав layout manager за Prototype JS няма и , второ, има готово решение на търсения от мен алгоритъм в лицето на отличния jQuery Masonry на David DeSandro.

Проблемът в моя случай беше, че за този проект ползвах Prototype и jQuery-плъгина не ме устройваше. Решението беше да си отделя един ден и да port-на jQuery Masonry към Prototype framework. Еквивалент на първото демо от сайта на David можете да намерите на Masonry Prototype страницата. От нея можете и да свалите и plugin-а, в случай че ви трябва.

Prototype версията напълно покрива basic демото, както и това с блога, за Infinite Scroll Example-a пича ползва third-party jQuery plugin, затова не съм го тествал…

Drupalized

The Drupal Logo

Всички, които следим малко по-внимателно web-а през последните няколко месеца, нямаше как да не забележим нарастващата вълна от Drupal-базирани сайтове. За добро или лошо, бизнесът с open source, особено извън татковината, винаги е имал нужда от солидна доза аргументация.

Със сигурност една от най-важните причини Drupal да започне такава сериозна експанзия, че чак Microsoft да започнат кампания против него в Google AdWords е http://www.whitehouse.gov/. От това по-добра реклама – здраве му кажи.

The Drupal Logo

Всички, които следим малко по-внимателно web-а през последните няколко месеца, нямаше как да не забележим нарастващата вълна от Drupal-базирани сайтове. За добро или лошо, бизнесът с open source, особено извън татковината, винаги е имал нужда от солидна доза аргументация.

Със сигурност една от най-важните причини Drupal да започне такава сериозна експанзия, че чак Microsoft да започнат кампания против него в Google AdWords е http://www.whitehouse.gov/. От това по-добра реклама – здраве му кажи.

За самият Drupal са ми малко думите – страхотен, повтарям страхотен Content Management System, който е в състояние да сложи в малкия си джоб дузина комерсиални конкуренти. С изчерпателната си документация, и огромната общност от разработчици зад гърба си, Drupal със сигурност е в пъти по-добро решение от всякаквите самоделки, налични като “решения” в повечето от родните ни web компании.

Всъщност, сега се сещам за една молба към web разработчиците: ако имате задачка пред себе си и не сте с много умения в писането на PHP код, дайте един шанс на Drupal, ще спестите адски много време на хората, които ще fix-ват грешките ви по-късно. В случай, че имате опит и още не сте преминали на утвърдени практики като MVC (Zend Framework, CodeIgniter или Symphony) – направете го, няма да съжалявате.

Next-gen Flash development?

Adobe Flash Catalyst

Не е истина какво прави конкуренцията – след като Microsoft добутаха H264/AAC в Silverlight 3, както и smooth streaming, пуснаха и някакъв 3D support, и в един момент Adobe започнаха да изглеждат леко смешни с 10-тата версия на Flash Player, която (спорно) май остана само с по-добрия рендеринг на шрифтовете и междуплатформената си поддръжка. И, според мен, ако е имало нещо, което отново да върне Adobe там, където им е мястото, то това е само и единствено Flex-платформата. Ясно е, че в областта на дизайна Adobe са ненадминати. Също толкова ясно е, че Microsoft са напред в областта на development-a.

Adobe Flash Catalyst

Не е истина какво прави конкуренцията – след като Microsoft добутаха H264/AAC в Silverlight 3, както и smooth streaming, пуснаха и някакъв 3D support, и в един момент Adobe започнаха да изглеждат леко смешни с 10-тата версия на Flash Player, която (спорно) май остана само с по-добрия рендеринг на шрифтовете и междуплатформената си поддръжка. И, според мен, ако е имало нещо, което отново да върне Adobe там, където им е мястото, то това е само и единствено Flex-платформата. Ясно е, че в областта на дизайна Adobe са ненадминати. Също толкова ясно е, че Microsoft са напред в областта на development-a.

За да надделее, някой от двата “претендента” трябва да стъпи в областта на популярност на другия. Аз лично, освен че съм супер пристрастен по ред причини, с чиста съвест ще заложа на Adobe. Първо, защото MS така и не успяха да направят читав дизайнерски инструмент вече повече от 20 години и с всеки наченат и захвърлен експеримент в тази насока търпят само критики. Второ, защото Adobe знаят как да поддържат общност, и се опитват да се вслушват в гласа на потребителската си база. От години следя http://labs.adobe.com не само заради интересните неща там, но и заради възможността да видиш зараждането на технология и дискусиите по оформянето й.

Преди около година и нещо, когато започнаха първите дискусии по Flex 4 имаше сериозна дискусия накъде да се фокусира следващата версия. Контроли вече имаше (за разлика от Silverlight), имаше и горе-долу ясна концепция за типа RIA които ще бъдат разработвани и тогавашният модел работеше някак си. Не мога да кажа успешно, но поне беше форма на development която вършеше работа за поставянето на основата. После се появи някакъв чешит, който бил бачкал в Microsoft и даде идеята да се напише инструмент, който да помогне на дизайнерите да влязат по-надълбоко във Flex. Последиците от това днес са налични като версия beta на продукта Adobe Flash Catalyst. Базиран на Eclipse, Flash Catalyst поне от видеото, налично на сайта на Adobe ме кара да мисля за напълно нов подход към Flash разработката. А факта, че нещото, което преди носеше името Flash Builder вече се казва Adobe Flash Builder само потвърждава мнението ми.

Излиза, че Adobe са стъпили на солидна среда за разработка, каквато е Eclipse и с типичната си находчивост изглежда ще успеят отново да бутнат Flash технологията с една стъпка напред, Което е екстра, аз лично, колкото и да мразя банерите се кефя неистово на нещата в The FWA.

Mandate

Mandate

Последният месец при мен мина изцяло в разработка на сайта, който можете да видите, щраквайки върху линка по-горе. По-доволен няма как да съм, понеже това е първият PHP проект, в който не ползвам собствените си модули за администрация на съдържание, а вместо тях се спрях на един проект с отворен код, който ме интересува от известно време насам – Drupal

Mandate

Последният месец при мен мина изцяло в разработка на сайта, който можете да видите, щраквайки върху линка по-горе. По-доволен няма как да съм, понеже това е първият PHP проект, в който не ползвам собствените си модули за администрация на съдържание, а вместо тях се спрях на един проект с отворен код, който ме интересува от известно време насам – Drupal

Всъщност, това, което е по-интересно е, че реално проблемите с разработката на сайта бяха доста по-малко от колкото очаквах. Единствената реална трудност беше мигрирането на съдържанието от стария блог на клиента (базиран на WordPress) към собствената блог-система на Dupal, но наличният модул за импорт на съдържанието от WP работи отлично.

Дребни проблеми можете да имате само, ако import-вате огромно количество съдържание, и те са свързани не толкова с Drupal, колкото с time limit ограничението за изпълнение на PHP скриптове в Apache. Иначе CMS-ът е с отлична документация и архитектура и съм сигурен, че Mandate няма да са единственият случай, в който работя с него. Писането на custom модули е максимално улеснено и не помня кога за последно съм се радвал като малко дете на резултатите от работа с тривиални операции.

Освен това имах и малко време да помисля над система за заместване на шрфитове, подобна на sIFR, но с по-малко баласт, и резултата определено ме обнадеждава – с малко помощ от jQuery системата използва един 14k .swf файл за всички заглавия и подзаглавия в сайта.

Иначе обичайните благодарности за всички замесени са задължителни, а резултатът, поне на мен, ми харесва доста.

Sitecore: Proxying MediaItem

Sitecore

За един от проектите наскоро имахме интересен казус – част от upload-натите файлове в Media Library-то на Sitecore трябваше да са достъпни за сваляне само от регистрирани потребители. Неприятното беше, че всъщност съдържанието на всеки от Item-ите в Media Library вече е достъпно чрез proxy, и едно от решенията беше писане на разширение за pipeline обектите. Другото решение беше написване на собствено proxy, което със сигурност ми харесва повече.

Sitecore

За един от проектите наскоро имахме интересен казус – част от upload-натите файлове в Media Library-то на Sitecore трябваше да са достъпни за сваляне само от регистрирани потребители. Неприятното беше, че всъщност съдържанието на всеки от Item-ите в Media Library вече е достъпно чрез proxy, и едно от решенията беше писане на разширение за pipeline обектите. Другото решение беше написване на собствено proxy, което със сигурност ми харесва повече.

Подчертавам дебело, че това е първият ми ASP.NET модул изобщо, така че бъдете снизходителни. Решението (с махнати подробностите по проверка на достъпа) изглежда така:

Response.Clear();
Sitecore.Data.Database database =
Sitecore.Configuration.Factory.GetDatabase("master");
Sitecore.Data.Items.MediaItem MediaFile = 
database.GetItem(ItemID);
 
Stream fileStream = MediaFile.GetMediaStream();
 
Response.ContentType = MediaFile.MimeType;
Response.AppendHeader("Content-Length", 
fileStream.Length.ToString());
Response.AppendHeader("Content-Disposition", 
"attachment; filename="+MediaFile.Name+"."+MediaFile.Extension);
 
byte[] fileContent = BufferStream(fileStream,0);
Response.BinaryWrite(fileContent);

BufferSream е собствен метод, който load-ва съдържанието на MediaStream-а преди да го представи на потребителя. Ето и какво представлява, всъщност:

public static byte[] BufferStream(Stream stream,int initialLength)
{
  if (initialLength &lt; 1) { initialLength = 32768; }
  byte[] buffer = new byte[initialLength];
  int read=0;
  int chunk;
  while ((chunk = stream.Read(buffer,read,buffer.Length-read))>0)
  {
    read += chunk;
    if (read == buffer.Length)
    {
      int nextByte = stream.ReadByte();
      if (nextByte==-1) { return buffer; }
      byte[] newBuffer = new byte[buffer.Length*2];
      Array.Copy(buffer, newBuffer, buffer.Length);
      newBuffer[read]=(byte)nextByte;
      buffer = newBuffer;
      read++;
    }
  }
  byte[] ret = new byte[read];
  Array.Copy(buffer, ret, read);
  return ret;
}

sthoughts adds mobile support

sthoughts mobile version - home page

Е, време беше и аз да се включа в модата с преправянето на сайтове за мобилни телефони, и в този ред на мисли едва ли щях да имам по-добро опитно поле от блога си. В крайна сметка редизайна, заедно с имплементацията, отне по-малко от ден, а тестовете успешно минаха мобилната версия на Internet Explorer, webkit-базираният Iris и, разбира се, Opera Mobile. Търси се тестер с iPhone, който само да потвърди дали сайта изглежда като на screenshot-ите.

sthoughts mobile version - home page

Е, време беше и аз да се включа в модата с преправянето на сайтове за мобилни телефони, и в този ред на мисли едва ли щях да имам по-добро опитно поле от блога си. В крайна сметка редизайна, заедно с имплементацията, отне по-малко от ден, а тестовете успешно минаха мобилната версия на Internet Explorer, webkit-базираният Iris и, разбира се, Opera Mobile. Търси се тестер с iPhone, който само да потвърди дали сайта изглежда като на screenshot-ите.

sthoughts mobile version - article

Иначе да взема да похваля поне веднъж Microsoft – мобилната им версия на Windows е доста по-обмислена от desktop еквивалента си и с малко GNU софтуер почти става за ползване. Естествено, има и мизерии – за да спра приложение трябва да цъкам през 5 менюта, ама Task Manager-и за Windows Mobile дал господ…

При писането на мобилната версия на сайта гледах максимално да се придържам до стандартния й еквивалент като цветова схема, изхвърлих ненужни неща като архивите по месеци, запазих линковете към архивите по категории и добавих опция за преход към стандартната версия (за тези, който ползват Opera Mobile). Разстоянието между заглавията на отделните постове нарочно е оставено по-голямо – открих, че така по-малко се объркваш при целене на линковете с пръсти вместо със stylus-a.

Надявам се цялото упражнение да се окаже ползено. За предложения или критики – използвайте коментарите…

jQuery 1.3

jQuery 1.3 is released

Вчера, точно на 3 годишнината от създаването си, проекта jQuery официално обяви появата на новата версия на популярната си JavaScript библиотека. Вероятно изобщо нямаше да съм толкова въодушевен, ако все още ползвах комбинацията Prototype + Scriptaculous и бях прочел тези Release Notes – подобрение на производителността в почти всяка област на цената на 18k (minified).

jQuery 1.3 is released

Вчера, точно на 3 годишнината от създаването си, проекта jQuery официално обяви появата на новата версия на популярната си JavaScript библиотека. Вероятно изобщо нямаше да съм толкова въодушевен, ако все още ползвах комбинацията Prototype + Scriptaculous и бях прочел тези Release Notes – подобрение на производителността в почти всяка област на цената на 18k (minified).

Не че Prototype е лоша библиотека – дори напротив, но 126k са си тежест при първоначално зареждане. Освен това съм забелязал, че с jQuery дори custom скриптовете и plugin-ите се получават по-компактни като код. Единственият проблем досега беше липсата на event delegation, но с появата на 1.3 и този проблем отпадна. И като капак на всичко – изцяло новата система за селектиране, Sizzle, освен малка (само 3k, minified) е и уникално бърза.

Хубавинките не свършват дотук и от jQuery твърдят:

Right now we’re working with Prototype, Dojo, Yahoo UI, MochiKit, and TinyMCE (and many others) on Sizzle, honing it to perfection.

Това, при положение че не остане само на хартия, означава, че на разработчиците няма да им се налага да се нагаждат към всяко API, поне по отношение на селекторите.

Разбира се, като при всяка нова версия ще трябва да измине малко време преди по-сериозните plugin-и да излязат с официална поддръжка на 1.3, но поне от това което тествах в офиса, миграцията няма да е толкова трудна. Пък и пренаписването на разни неща с цел подобряване на производителността винаги си е струвало усилията 🙂

P. S.: Можете да link-вате директно 1.3 версията от Google-сървърите за да свалите още повече времето за зареждане. Намира се тук:

http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js

Ubiquity

Пичовете в Mozilla Labs изглежда вършат доста работа в последните месеци и резултатите не закъсняват. Ubiquity for Firefox е убийствено як plug-in, с помощта на който престоят в Internet се превръща в още по-приятно изживяване. Ако още не сте гледали видеото над този текст – направете го, няма да съжалявате.

Пичовете в Mozilla Labs изглежда вършат доста работа в последните месеци и резултатите не закъсняват. Ubiquity for Firefox е убийствено як plug-in, с помощта на който престоят в Internet се превръща в още по-приятно изживяване. Ако още не сте гледали видеото над този текст – направете го, няма да съжалявате.

Хубавото на цялата далаверка е, че е разширяема, а пък и всеки с малко познания по CSS може да създаде нов или да преправи някой от съществуващите skin-ове. Комадите използват чист AJAX за връзка със сайтовете и, ако developer-ите са толкова въодушевени от Ubiquity колкото съм и аз, е въпрос на време да видим команди за интеграция с Facebook, или още по-интензивно използване на Yahoo Pipes, например.

Съществуващите команди дори сега ми спестяват огромно количество време при проверка на детайлите по разни API-та, така че за мен този инструмент върши повече от чудесна работа. Блогвам го, защото не вярвам да има developer, който да не иска документацията на PHP, Rails или jQuery да му е “на един select разстояние”…