sie 26 2010

bash + imagemagic dla miniaturek

Czasem fajnie byłoby uprościć sobie życie i generować automatycznie miniaturki zdjęć, często korzystam z narzędzia phpThumb które spełnia swoją rolę ale jeśli chcemy kierować działaniem generowania miniaturek to z pomocą przychodzi narzędzie convert wchodzące w skład imagemagick, napisałem więc skrypt który pomaga w tworzeniu miniaturek wycentrowanych o określonych wymiaarach


#!/bin/bash

# created by Łukasz Adamczewski (lukasz@tworzenie-web.pl)
#
# skrypt tworzący miniaturkę zdjęć zawartych w bierzącej lokalizacji
#
#

thumb="thumb";

if [ ! -d $thumb ]; then
mkdir -m755 $thumb
fi

find . -type f \( -name "*.jpg" -o -name "*.jpeg" \) | while read f;
do

fName="${f##*/}";
new="${fName// /_}";

if [ "$new" != "$fName" ]  &&  [ "$new" != "" ];
then
mv "$fName" "$new"
convert $new -resize '100x100^' -gravity center -crop 100x100+0+0 +repage $thumb/$new;
else
convert $fName -resize '100x100^' -gravity center -crop 100x100+0+0 +repage $thumb/$fName;
fi

done

touch completed

cze 24 2010

sfDoctrineRoute i własne zapytanie pobierania obiektu z routingu

Przydatny kod konfiugracji do routing.yml


show_message:
url:   /chat/show/:id/
param: { module: chatMessage, action: show }
class:   sfDoctrineRoute
options: { model: ArchivedChat, type: object, method_for_query: getWithConversation }
requirements:
id: \d+
sf_method: [get]

Powyższy wpis powoduje że przy wykonuwaniu metody


$this->getRoute()->getObject();

wykona się wczesniej zdefiniowane zapytanie getWithConversation z klasy ArchivedChatTable


maj 3 2010

Jquery Clear Default Value

Często podczas pracy z formularzami przydatne staje się wyczyszczenie domyślnej wartości pola i pozwolenie użytkownikowi wpisanie własnej. Podczas projektowania takiego zachowania należy jednak mieć na uwadze by nie czyścić tej wartości za każdym razem, tylko w wypadku kiedy wartość ta jest wartością defaultowa zdefiniowaną w polu value danej formatki


(function($){
$.fn.clearDefault = function(){
return this.each(function(){
var default_value = $(this).val();
$(this).focus(function(){
if ($(this).val() == default_value) $(this).val("");
});
$(this).blur(function(){
if ($(this).val() == "") $(this).val(default_value);
});
});
};
})(jQuery);

kwi 28 2010

Prezentacja Seminaryjna Tematu

Tydzień temu prezentowałem na swoich seminariach inżynierskich ogólne zapatrywania na swój temat dla zainteresowanych załączam prezentację.
Wykorzystanie frameworku Symfony


kwi 22 2010

Wykorzystanie Frameworka Symfony do Tworzenia Aplikacji w języku PHP

Rozpocząłem pracę nad pracą inżynierską o powyższym temacie. Pragnąłbym zawrzeć w niej kurs zgodnie z ideą 30 dniowego samouczka, po której będzie można wykonać zaawansowaną aplikację. Moim marzeniem byłoby, aby publikacja była rzetelnym polskim źródłem na temat tegoż frameworka


lut 24 2010

Jquery i podwójny submit

Poniższy kod rozwiązuje problem podwójnego wysyłania formularza ze strony javascriptu, zabezpieczenie winno również występować po stronie serwera


$("form").submit(function() {
`$(":submit",this).attr("disabled", "disabled");
});

lut 18 2010

Zgodność pól tabeli

Załóżmy, że mamy następującą sytuację:

określ procentowy stopień dopasowania jednego użytkownika względem drugiego na podstawie zgodności wartości pól przy załóżeniu różnych wag dopasowań.

Problem ten bez odpowiednio rozplanowanej tabeli może stanowić pewien kłopot, zaczynając od projektu bazy uwzględnijmy:


Schemat ten oznacza że każdy użytkownik ma przypisaną pewną pulę atrybutów go określających np wiek, płeć, ulubiony film, hobby etc. których definicja jest określona tabelą attributeDefinition która z kolei w relacji z attributeOption służy do reprezentacji pól wyboru typu select, multiple select, checkbox i multiplecheckbox.

W tabeli attributeDefinition umieszczona jest też kolumna określająca że wartość dla tego pola musi zostać zestawiona z wartością wskazaną przez referenced_attribute. Oznacza to np. że stworzono definicję atrybutu określające preferencje co do muzyki jakiej szukamy u osób które są dla nas potencjalnie ciekawe. Tak więc wartość referenced_attribute powinna wskazywać na definicje atrybutu określania ulubionej muzyki użytkownika. Więc dla określenia zgodności w sensie równości pól musimy złączyć pola attribute_id użytkowników, a dla równości w sensie kto komu odpowiada musimy złączyć pole referenced_attribute_id z polem attribute_id użytkownika.

Problem
Szukając użytkowników zgodnych nie wykonujemy zapytania z użyciem słowa gdzie tylko tak naprawdę podliczamy wagi punktowe w wypadku równości.

Więc jak się za to wziąc?

Przede wszystkim musimy zestawić ze sobą tabele user – okreslającą użytkownika dla którego szukamy dopasowania i  user – dla użytkowników których szukamy.


SELECT u.id, SUM((u.value = u2.value) * a.score) AS matched
FROM user_attribute u
INNER JOIN attribute_definition a ON u.attribute_id = a.id
INNER JOIN user_attribute u2 ON a.reverse_attribute_id = u2.attribute_id
INNER JOIN user_profile u3 ON u2.user_id = u3.id
WHERE u.user_id = 102 AND u2.user_id <> 102 GROUP BY u2.user_id
order by matched desc
select B.user_id, sum(((A.value = B.value)* C.score)) score
from user_attribute A
inner join user_attribute B
on
A.attribute_id = B.attribute_id
inner join
Attribute C on B.attribute_id = c.id
where A.user_id = ?
group by B.user_id
order by sum(((A.value = B.value)* C.score)) desc

lut 16 2010

Przydatne Sztuczki Symfony

Poniżej mnóstwo cennych zastosowań symfony które warto znać do jeszcze lepszego programowania w tymże frameworku

Pobierz wartość z konfiguracji

$wartosc = sfConfig::get("app_sekcja_zmienna");

Pobiera wartość z pliku /apps/current_appname/configs/app.yml, który winien wyglądać tak:

all:
sekcja:
zmienna: wartość

Istnieje możliwość dalszego zagłębiania sekcji, np.

all:
sekcja:
podsekcja:
zmienna: wartość

Ale wówczas należy skorzystać:

$temp = sfConfig::get("app_sekcja_podsekcja);
$wartosc = $temp["zmienna"];

Logowanie do debuggera Symfony

W Symfony można logować dowolną wartość, która później wyświetla się w pasku debuggera -> logs. W kontrolerze można skorzystać z:

$this->logMessage("Twój debug");

W innym miejscu, np. w modelu można skorzystać z:

sfContext::getInstance()->getLogger()->log("Twój debug");

Stosowanie globalnych części szablonu (partials)

Normalnie używam

include_partial('errors', array('form' => $form)) ?>

Wówczas Symfony szuka części w apps/current_app/modules/current_module/templates/_errors.php

Jeśli chcemy wskazać konkretny moduł:

include_partial(nazwa_modulu/errors',
array('form' => $form)) ?>

Wówczas Symfony szuka części w apps/current_app/modules/nazwa_modulu/templates/_errors.php

Gdy użyjemy:

include_partial('global/errors', array('form' => $form)) ?>

Wówczas Symfony będzie szukało części w apps/current_app/templates/_errors.php. Wniosek nasuwa się sam, nie nalezy używać nazwy ‘global’ jako nazwy modułu

Wyświetlenie dowolnej zawartości

echo sfYamlInline::dump($dowolna_zmienna);

$dowolna_zmienna może być naprawdę dowolną zmienną, również obiektem i tablicą. Zmienna zostanie tak sformatowana aby była czytelna dla człowieka.

I18n

Przy wielojęzycznej stronie w szablonach korzystamy z

echo __("Polski string") ; ?>

Po stronie kontrolera lub modelu:

sfContext::getInstance()->getI18N()->__('Polski string');

Przydaje się szczególnie do określania etykiet dla formularzy po stronie modelu.

Cacheowanie

Jeśli korzystamy z cacheowania, zawartość strony dostępna jest w kilku językach, musimy wziąć pod uwagę że czasem partial może pozostać zcachowany w pierwszym wybranym języku strony, żeby temu zapobiec warto przekazać do komponentu, partiala dodatkowy parametr np

<? include_component('article', 'videos', array('sf_cache_key' =>  $sf_user->getCulture())) ?>

ten zapis spowoduje że cache tego partiala będzie dostępny w 2 wersjach zależnych od języka i właśnie to jest cel który chcieliśmy osiągnąć


lut 16 2010

Grupowanie po kluczu i wyświetlanie krotek których wartość dla tego klucza osiąga wartość skrajną

Zadanie: Dla każdego artykułu, znajdź dilerów lub dilerów z największymi cenami

Problem ten możemy rozwiązać przy użyciu zapytań skorelowanych


SELECT article, dealer, price
FROM   shop s1
WHERE  price=(SELECT MAX(s2.price)
FROM shop s2
WHERE s1.article = s2.article);

+---------+--------+-------+
| article | dealer | price |
+---------+--------+-------+
|    0001 | B      |  3.99 |
|    0002 | A      | 10.99 |
|    0003 | C      |  1.69 |
|    0004 | D      | 19.95 |
+---------+--------+-------+

Ten przykład korzysta z dobrodziejstw skorelowanych zapytań które niestety nie są zbyt wydajne. Inną możliwością rozwiązania problemu jest skorzystanie z nieskorelowanych pod zapytań w sekcji from lub używając klauzuli left join


SELECT s1.article, dealer, s1.price
FROM shop s1
JOIN (
SELECT article, MAX(price) AS price
FROM shop
GROUP BY article) AS s2
ON s1.article = s2.article AND s1.price = s2.price;

SELECT s1.article, s1.dealer, s1.price
FROM shop s1
LEFT JOIN shop s2 ON s1.article = s2.article AND s1.price < s2.price
WHERE s2.article IS NULL;

Zapytanie z left joinem opiera się na zasadzie że kiedy s1.price jest w maksymalnej wartości, nie istnieje takie s2.price z większą wartością więc krotki s2 będą miały wartość null


lut 16 2010

Sortowanie Losowe w Doctrine

Wbrew temu co można wyczytać z różnych artykułów i pomysłów domorosłych programistów

$user = Doctrine::getTable('User')
->createQuery()
->orderBy('RAND()')
->fetchOne();

Ta metoda uzyskiwania losowych wpisów jest po pierwsze mało przenośna na inne systemy baz danych oraz bardzo mało efektywna. Zaleca się bardziej stosowanie takiej metody


$userCount = current(Doctrine::getTable('User')
->createQuery()->select('count(*)')
->fetchOne(array(), Doctrine::HYDRATE_NONE));

$user = Doctrine::getTable('User')
->createQuery()
->limit(1)
->offset(rand(0, $userCount - 1))
->fetchOne();

przy okazji przypomnienie:

There are two important differences between {{HYDRATE_ARRAY}} and {{HYDRATE_NONE}} which you should consider before choosing which to use. {{HYDRATE_NONE}} is the fastest but the result is an array with numeric keys and so results would be referenced as {{$result[0][0]}} instead of {{$result[0]['my_field']}} with {{HYDRATE_ARRAY}}. Best practice would to use {{HYDRATE_NONE}} when retrieving large record sets or when doing many similar queries. Otherwise, {{HYDRATE_ARRAY}} is more comfortable and should be preferred.


Improve the web with Nofollow Reciprocity.