phpFashion

Na navigaci | Klávesové zkratky

Nette Pro: úplně bez obalu

Blíží se spuštění Nette Pro. Chemix sepsal, o co jde, a já dokončuji web, kde bude vysvětleno, co to přinese. Protože jsem zaznamenal i nějaké obavy, rád bych je rozptýlil a zkusím proto Nette Pro popsat zcela bez obalu.

Například Martin Zlámal se ptal: „chci o frameworku přednášet na školách. Baví mě to – a hodně. Mění se tím pro mě něco? Můžu to vůbec dělat?“ a v tu chvíli jsem si uvědomil, že Nette Pro obestírá jakýsi závoj neporozumění. Takže postupně:

Co je cílem všeho toho snažení? No je jím přesně to, po čem všichni voláme:

  • chceme nové verze plné novinek
  • chceme perfektní release management
  • chceme, aby se řešily hlášené issues nebo pull requesty
  • chceme lepší dokumentaci reflektující novinky
  • chceme stabilitu a minimum BC breaků
  • chceme blog o tom, co se chystá
  • chceme vylepšit web a fórum
  • chceme tutoriály, příklady, videa, podcasty, tipy, triky, řešení
  • chceme ten obsah i v angličtině, protože
  • chceme, aby se o Nette psalo v zahraničí, aby se o něm přednášelo
  • chceme, aby Nette hodně dlouho fungovalo, protože na něm děláme weby

Některé cíle jsou idealistické, jiné velmi hmatatelné, podstatné je, že všechny vám určitě rezonují. Martinova ochota přednášet o Nette na školách do toho pochopitelně zapadá.

Co je důvodem vzniku Nette Pro? Bez obalu: získat peníze na uskutečnění toho všeho.

A proč jsou potřeba peníze? Protože potřebujeme zaplatit lidi.

A proč potřebujeme zaplatit lidi? Protože nemáme dobrovolníky.

Jako že jich je málo? Současná komunita nestačí?

Na rovinu: na Nette pracují vlastně 3 lidé:

  • Milo, který vymýšlí, vyvíjí, opravuje, dokumentuje a píše na blog o Nette Testeru, taktéž spravuje hosting pro nette.org. Dělá to jako dobrovolník ve volném čase mimo zaměstnání a výchovu malého dítěte.
  • Chemix, který organizuje a moderuje Poslední soboty, zajišťuje sponzory, prostory, přednášející. Dělá to jako dobrovolník, jinak působí jako kreativec na volné noze. Neumí anglickou gramatiku tak, aby si troufl vydávat články.
  • já, David, který vymýšlí, vyvíjí, opravuje a releasuje Tracy, Latte a vlastně celé Nette, taky dibi a Texy, psal dokumentaci, udržuje web nette.org a fórum. Dělá to jako dobrovolník v podstatě už veškerý svůj čas. Neumí anglickou gramatiku tak, aby si troufl vydávat články.

A řekl bych, že nás všechny to baví. Jenže to neškáluje :-)

A taky bych řekl, že nás dost nebaví, když (zejména ti velmi dobře obeznámení se situací a možnostmi) nás hejtujou, že vysoká očekávání neplníme.

Z téhle trojky už víc vymáčknout nepůjde a dnes už víme, že na příliv nových sil nelze spoléhat. Zkoušeli jsme leccos včetně hazardérství, ale nic nezabralo. Místo čekání, jestli se někdo chopí třeba vylepšování dokumentace, je lepší si prostě copywritera najít a normálně mu těch několik měsíců práce zaplatit.

Samozřejmě nechci připravit o kredit kluky, kteří věnují čas fóru, což je fakt důležitá činnost.

Jen jsme narazili na hranici toho, co lze na čistě dobrovolné bázi uskutečnit. A hledáme způsob, jak jí překonat. Potřebujeme angažovat i „nedobrovolníky“.

Proč se tito lidé nezaplatí z příjmů Nette? Bez obalu: Nette generuje příjem v řádu tisícikorun měsíčně.

Tudíž potřebujeme ty příjmy zvýšit. Mnohanásobně. Což vůbec není sranda. Ano, Nette je zřejmě nejpopulárnějším webových frameworkem u nás, běží na něm řada nesmírně výdělečných projektů, jenže z toho automaticky neplyne příjem pro Nette. Firmy jsou nemilosrdné, a pokud jim nenabídnete nějakou přidanou hodnotu, korunu nepustí.

A tou přidanou hodnotou (především) pro firmy má být právě Nette Pro.

Svým způsobem přidanou hodnotou je i to, že chceme dělat Nette pro fesionálně.

Samo o sobě to však nestačí. Vyrazili jsme proto do firem a ptali se jich, bez obalu, jak si můžeme být prospěšní. „My potřebujeme peníze, protože bez nich by Nette jen přešlapovalo na místě. Co vám můžeme za ně nabídnout?“ Někdo se chtěl zviditelnit. Někdo chtěl vyřešit issues. Někdo jen chtěl, aby se Nette dál vyvíjelo. Tak jsme myšlenky přetavili do balíčků.

Ony balíčky jsou tedy tím, o čem lidé prohlásili: „jo, tohle dovedu u nás ve firmě prosadit.“

Nebo řekli: „jo, tohle by se nám fakt hodilo.“ Ať už programátorům, nebo třeba HR či marketingu, protože to pomůže zviditelnit firmu nebo najít zaměstnance.

Takže dobrovolníci už nejsou potřeba? Jsou! Setsakramentsky moc!

V Nette bylo a bude téměř vše tvořeno dobrovolníky. Nette Pro je jen záplata jejich chronického/ochromujícího nedostatku.

Doufám, že když se peníze z Nette Pro použijí na vylepšení webu, dokumentace, tutoriálů, že ten tvůrčí kvas povzbudí komunitu k aktivitě. Potřebujeme Martiny, kteří budou jezdit po školách. Potřebujeme autory tutoriálů a doplňků, kteří si tímto způsobem udělají jméno. Potřebujeme nadšence, co o Nette budou psát články do zahraničních magazínů, aby se přitáhla i světová komunita. Nette Pro zaplatí překladatele. Ale práci dobrovolníků nenahradí.

A kdy se to spustí? Během pár dní.


Dibi 3.0 je venku, Texy na cestě

Zmodernizoval jsem kód knihoven Dibi a Texy, třídy přenesl do jmenných prostorů a využil syntaxe PHP 5.4. Zároveň jsem doplnil mechanismus, aby knihovny fungovaly i s existujícím kódem, který používá původní názvy tříd.

Výsledkem je Texy 2.8 (release notes) a Dibi 3.0 (release notes).

Dibi mělo nést původně označení 2.4, protože krom vnitřního refactoringu jsem nechtěl přidávat nebo měnit jakoukoliv funkčnost, jako u Texy 2.8, ale nakonec jsem pár vychytávek přidal a výsledkem je právě verze 3.0:

  • nové výjimky Dibi\ConstraintViolationException, ForeignKeyConstraintViolationException, NotNullConstraintViolationExceptionUniqueConstraintViolationException
  • MySQL: sloupec TIME se převádí na objekty DateInterval namísto DateTime (BC break)
  • SqlsrvDriver: doplněna podpora pro LIMIT & OFFSET
  • vylepšen Dibi\Fluent při použití limit & offset

Zmizely ovladače pro SQLite 2 a MsSqlDriver, které nejsou od PHP 5.3 podporované, a MsSql2005Driver se nyní jmenuje SqlsrvDriver (funguje i starý název). Statická třída dibi zůstává mimo jmenné prostory. Pokud si píšete vlastní ovladač, došlo ke změně v rozhraní u metod escape() & unescape() (viz).

Minimální požadovaná verze PHP je 5.4.4, obě knihovny jsou plně funkční i pod PHP 7. Minifikovaná verze je ve formě archívu PHAR.

Dibi postupně pokrývám testy. Jelikož nepoužívám MS SQL Server, je tento driver víceméně v rukou komunity. Pokud jej používáte, zkuste prosím zjistit, proč neprocházejí testy používané pro jiné servery a co je potřeba změnit.

Velmi pozvolna vzniká i Texy 3.0, ze kterého zmizí dnes už překonané funkce, jako je třeba podpora jiného kódování než UTF-8, jiného formátu než HTML5 atd.


Jak vyvíjet komfotrněji?

Nová verze Nette 2.3.7 přináší spoustu vylepšení, jedno z nich si ale rychle zamilujete. Jsou to chybové hlášky, které se vám pokusí napovědět, pokud uděláte překlep.

Určitě jste už někdy narazili na podobnou chybu:

Chcete v šabloně vykreslit komponentu a ona prý neexistuje. Může to mít celou řadu příčin, od nějakého opomenutí na straně presenteru, až po chybu v šabloně. Nebo se komponenta jmenuje jinak?

Nejhorší ze všeho jsou triviální přelkepy, které nevidíte, takže několikrát prověříte všechny možnosti a strávíte na tom dost času, než chybu odhalíte.

Nejnovější verze Nette má ale šikovnější chybovou hlášku:

Did you mean ‚signInForm‘? Aha! Hned je jasné, že na vině byl překlep a můžete ho rovnou opravit.

Pokud jste se někdy dlouze zasekli na velikosti písmenek, tj. že vám {control MyComponent} hlásil chybu Component with name ‚MyComponent‘ does not exist, o to více oceníte dovětek did you mean ‚myComponent‘?.

Pojďme k Nette\Database. Chybka v názvu databázového sloupce? Opět ji dostanete na stříbrném podnose:

Mimochodem, stejná feature bude i v příští verzi dibi, kterou prosím před vydáním otestujte.

Nette napovídá překlepy v názvech funkcí, metod, proměnných atd. Pokud vyvíjíte v IDE, neměly by se vám podobné chyby stávat, na druhou stranu málokteré IDE dokáže plnohodnotně napovídat třeba v šablonách. Ať už se spletete v názvu filtru nebo makra:

Případně v názvu proměnné:

Hláškou did you mean novinky zvyšující pohodlí nekončí. Nette vás nově upozorní na celou řadu dalších, dříve špatně odhalitelných, chyb. Jako například chybějící []

$myForm->onSuccess = [$this, 'myFormSucceeded'];
// namísto správného
$myForm->onSuccess[] = [$this, 'myFormSucceeded'];

nebo chybějící ()

{foreach $form->getErrors as $error}
// namísto správného
{foreach $form->getErrors() as $error}

či docela nebezpečné opomenutí, jelikož $user->isLoggedIn je vždy truthy:

{if $user->isLoggedIn} ... něco tajného ... {/if}
// namísto správného
{if $user->isLoggedIn()} ... něco tajného ... {/if}

To nyní povede k varování Did you forget parentheses after isLoggedIn?

Poznámka: pokud záměrně píšete v kódu metodu bez závorek, tj. $cb = $obj->getItems, protože chcete využít vlastnosti Nette\Object, která takto do $cb uloží callback na metodu getItems, a objeví se varování, použijte prosím standardní PHP zápis, tj. $cb = [$obj, 'getItems']. Při korektních běžných použitích se varování nezobrazuje.

Dále Latte vás upozorní, když použijete modifikátor na místě, kde se ignoruje, jako například:

{if $var |filter}

Did you mean „komfortněji“?

Nová verze Nette je tu od toho, aby vám usnadnila a zpříjemnila vývoj. A jak je to napovídání boží si doopravdy uvědomíte, až to vyzkoušíte.


Jak na souhlas s cookie ve zkurvené EU

Víte, že nejpozději do 30. září 2015 máte povinnost získat souhlas uživatelů, pokud používáte na svém webu třeba Google AdSense? Proč, nač a jak na to?

(Verze pro příznivce EU)

Evropská unie přišla se zkurvenou směrnicí (tzv. sušenkovým zákonem), podle které musí uživatel webu dát souhlas s používáním cookies nebo obdobných mechanismů. Souhlas musí být také kurva odvolatelný.

Výjimkou jsou cookies, které jsou nezbytné pro poskytnutí služby, kterou si uživatel sám vyžádal, například cookie pro zkurvený nákupní košík. Naopak příkladem cookies, které nejsou nezbytně nutné, jsou cookie pro analýzu návštěvnosti, reklamní systémy nebo zkurvené pluginy sociálních sítí.

Česko zkurvenou evropskou směrnici implementovalo tak, že ji vlastně ignorovalo. Což se zkurveně nelíbí Úřadu pro ochranu osobních údajů, který se tím bude zabývat. Zatím tedy u nás není potřeba uživatele zkurveně žádat o souhlas, nicméně provozovatelé webů mají povinnost informovat o rozsahu a účelu jejich zpracování, například v podmínkách používání na svých stránkách. Uživatelé také musí mít možnost takové zpracování odmítnout, kurva fix.

…pokračování

před 2 lety v rubrice Web


Jak na souhlas s cookie v EU

Víte, že nejpozději do 30. září 2015 máte povinnost získat souhlas uživatelů, pokud používáte na svém webu třeba Google AdSense? Proč, nač a jak na to?

Evropská unie přišla se směrnicí (tzv. sušenkovým zákonem), podle které musí uživatel webu dát souhlas s používáním cookies nebo obdobných mechanismů. A souhlas musí být také odvolatelný.

Výjimkou jsou cookies, které jsou nezbytné pro poskytnutí služby, kterou si uživatel sám vyžádal, například cookie pro nákupní košík. Naopak příkladem cookies, které nejsou nezbytně nutné, jsou cookie pro analýzu návštěvnosti, reklamní systémy nebo pluginy sociálních sítí.

Česko evropskou směrnici implementovalo tak, že ji vlastně ignorovalo. Což se nelíbí Úřadu pro ochranu osobních údajů, který se tím bude zabývat. Zatím tedy u nás není potřeba uživatele žádat o souhlas, nicméně provozovatelé webů mají povinnost informovat o rozsahu a účelu jejich zpracování, například v podmínkách používání na svých stránkách. Uživatelé také musí mít možnost takové zpracování odmítnout.

A teď to podstatné: protože Google nerozlišuje, jak která země implementovala směrnici EU, jste v případě, že používáte jeho služby jako Google AdSense nebo Analytics s některou z inzertních funkcí (remarketing, demografické přehledy), povinni získat souhlas koncového uživatele. A to do 30. září 2015.

Jak na to?

S tím, jak žádost o souhlas formulovat, vám poradí web www.cookiechoices.org. Záleží především na tom, k čemu cookie používáte. Kupříkladu na tomto webu používám AdSense a Analytics, takže jsem použil tuto formulaci:

Tento web používá k poskytování služeb, personalizaci reklam a analýze návštěvnosti soubory cookie. Používáním tohoto webu s tím souhlasíte.

Řeším tím povinnost dát uživateli možnost používání cookie odmítnout (tím, že web opustí) a také odvolatelnost souhlasu (tím, že web opustí).

A teď čistě technicky. Souhlas s používáním cookies si budu ukládat do cookie nazvané např. eu-cookies. Panel s žádostí vložím do layoutu na konec stránky a zobrazím pouze pokud nebyl udělen. Příklad pro Latte:

<div class="eu-cookies" n:if="empty($_COOKIE[eu-cookies])">
    Tento web používá k poskytování služeb, personalizaci reklam a analýze
    návštěvnosti soubory cookie. Používáním tohoto webu s tím souhlasíte.
    <button>V pořádku</button>
    <a href="https://www.google.com/policies/technologies/cookies/">Další informace</a>
</div>
<noscript><style>.eu-cookies { display:none }</style></noscript>

Panel mám napozicovaný fixně, aby byl stále vidět. Sice tak ukrajuje kus prostoru zejména na mobilních zařízeních, ale to nevadí, uživatel stejně nemůže web používat, pokud neprojeví souhlas. Příklad stylu:

.eu-cookies {
    position: fixed;
    left: 0;
    top: 0;
    width: 100%;
    color: white;
    background-color: black;
    z-index: 1000;
}

.eu-cookies button {
    background: green;
    color: white;
}

A nakonec JavaScript, který po stisknutí tlačítka uloží souhlas do cookie (používám jQuery):

$('.eu-cookies button').click(function() {
    var date = new Date();
    date.setFullYear(date.getFullYear() + 10);
    document.cookie = 'eu-cookies=1; path=/; expires=' + date.toGMTString();
    $('.eu-cookies').hide();
});

Pokud používáte subdomény a cookie se má nastavit i pro ně, doplňte za path=/; ještě domain=.vasedomena.cz; (a tečka na začátku je důležitá).

Ještě poznámka: dokud souhlas nezískáte, neměla by vaše stránka obsahovat ani reklamu, ani měřící kódy.


Jak správně načítat webové fonty

Stránka by měla být čitelná ihned. Je velmi protivné, když si například v metru nemůžete přečíst článek jen kvůli tomu, že se nestihl načíst webový font.

Prohlížeče se totiž chovají tak, že text zobrazí až poté, co se font stáhne, aby zabránili tzv. Flash of Unstyled Text (FOUT), tedy nepříjemnému probliknutí jiného fontu. Problém je, že některé browsery nemají žádný timeout, po jehož uplynutí by se použil systémový font namísto žádného (tj. webového, ale nestaženého).

O tomhle tématu jsem psal už dříve a doporučoval pro mobilní zařízení webové fonty vůbec nepoužívat. Stejně krom autora grafiky to nikdy nepozná :-)

Mobilům (nebo lépe řečeno zařízením do šířky 500px) můžeme ulevit tímto způsobem:

/* font stáhneme jen na větších zařízeních */
@import "https://fonts.googleapis.com/css?family=PT+Serif" screen and (min-width: 500px);

/* systémové písmo */
body {
    font: 18px/1.7 Georgia, serif;
}

@media (min-width: 500px) {
    body { /* webový font použijeme jen na větších zařízeních */
        font-family: 'PT Serif', Georgia, serif;
    }
}

Ale co ostatní prohlížeče? Natahování fontu skrze @import vypadá elegantně, ale blokuje zpracování CSS a to zase blokuje vykreslení stránky. Jde tedy o nejhorší možné řešení. Jak se zbavit blokování a zajistit timeout?

Emulace timeoutu

Timeout lze emulovat pomocí JavaScriptu. Jenže zjistit, že se font načetl, není nic triviálního, dělá se to pomocí triků, jako je třeba detekce změny šířky předpřipraveného text atd. Font Loading API zatím podporuje jen Chrome. Takže lepší bude použít hotové řešení, jako je například Web Font Loader.

Web Font Loader

Knihovnu Web Font Loader vyvíjí Google společně s Typekit. Nedávno o ní psal Aleš Roubíček, takže na něj navážu a pokusím se upravit řešení tak, aby se skript načítal asynchronně a neblokoval stránku.

Do hlavičky stránky (!) vložte tento kód, kterým asynchronně načtete Web Font Loader a také font:

<script>
    WebFontConfig = {
        google: { families: ['PT+Serif:400:latin,latin-ext'] }
    };
</script>
<script src="https://ajax.googleapis.com/ajax/libs/webfont/1.5.18/webfont.js" async defer></script>

Web Font Loader umí detekovat stavy, kdy se font načítá a kdy už je načtený, a to pomocí událostí nebo nastavováním tříd elementu <html>. Jakmile je font načtený, nastaví třídu wf-active. Zároveň řeší timeout.

Upravíme styl tak, aby se webový font použil až ve chvíli, kdy bude načtený, a nahradil tak systémové písmo.

/* systémové písmo */
body {
    font: 18px/1.7 Georgia, serif;
}

/* písmo po načtení fontu */
html.wf-active body {
    font-family: 'PT Serif', Georgia, serif;
}

Tohle řešení má ale potíž. Bude docházet k FOUT, tedy k probliknutí systémového fontu. Při prvním načtení stránky, kdy webový font ještě není v cache prohlížeče, může probliknutí trvat sekundu či déle, při každém dalším zobrazení krátký okamžik. A to vypadá velmi ošklivě.

Proto během načítání písmo skryjeme, tak jak to dělají prohlížeče standardně, bez loaderu.

html.wf-loading * {
    color: transparent !important;
}

Dále třídu wf-loading nastavíme ihned, nelze čekat, až se Web Font Loader načte. Ale zároveň ji musíme odstranit, když načtení loaderu selže. Výsledný kód vypadá takto:

<script>
    WebFontConfig = {
        google: { families: ['PT+Serif:400:latin,latin-ext'] }
    };

    var el = document.documentElement;
    el.className += ' wf-loading';
    setTimeout(function() {
        el.className = el.className.replace(/(^|\s)wf-loading(\s|$)/g, ' ');
    }, 1000); // 1 second
</script>
<script src="https://ajax.googleapis.com/ajax/libs/webfont/1.5.18/webfont.js" async defer></script>

Pokud je font v cache, stránka se ihned zobrazí se správným písmem bez probliknutí. Pokud v cache není, text nejprve nebude vidět a pokud se do vteřiny nepodaří font stáhnout, zobrazí se systémovým písmem a po stažení se přepne na webové písmo. Tedy při rychlém stažení k probliknutí vůbec nedojde a při pomalém ano, ale uživatel nebude koukat na prázdnou stránku.

Samozřejmě časovou prodlevu můžete dle libosti snížit.

Doplnění: s alternativním řešením přišel Petr Soukup.

Po načtení fontu si do prohlížeče uloží cookie wfont, která později bude značit, že font by měl být už v cache prohlížeče:

<html>
<script>
    WebFontConfig = {
        google: { families: ['PT+Serif:400:latin,latin-ext'] },
        active: function() { document.cookie ='wfont=1; expires='+(new Date(new Date().getTime() + 86400000)).toGMTString()+'; path=/' }
    };
</script>

A při dalším načtení stránky, pokud tato cookie existuje, generuje trošku jiný kód, kde není Web Font Loader, ale:

<html class="wf-active">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=PT+Serif">

Tedy webový font se použije rovnou a načítá se bez JavaScriptu, nedochází tedy k žádnému probliknutí.

A tip nakonec: aby prohlížeč mohl započít načítání fontu hodně brzy, vlastně ještě před normálním zpracováváním stránky, mu lze poradit pomocí prefetch:

<link rel="prefetch" href="https://fonts.googleapis.com/css?family=PT+Serif">

Implementace v Latte by mohla vypadat třeba takto:

{var $wfont = isset($_COOKIE[wfont])}
<html n:class="$wfont ? wf-active">
<script n:syntax=off n:if=!$wfont>
WebFontConfig = {
    google: { families: ['PT+Serif:400:latin,latin-ext'] },
    active: function() { document.cookie ='wfont=1; expires='+(new Date(new Date().getTime() + 86400000)).toGMTString()+'; path=/' }
};
</script>
<script src="https://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js" async defer n:if=!$wfont></script>
<link rel="{$wfont ? stylesheet : prefetch}" href="https://fonts.googleapis.com/css?family=PT+Serif">

Rychlejší stránky s Google Universal Analytics

Ukáži vám, jak zrychlit načítání Google Analytics nebo Web Loaderu a ještě zjednodušit měřící kód.

Tímto kódem vložíme do stránky měřící bod Google Analytics:

<script>
    (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
    (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
    m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
    })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

    ga('create', 'UA-XXXXX-XX', 'auto');
    ga('send', 'pageview');
</script>

Když si ho odtemníme, vypadá takto:

<script>
    (function() {
        window['GoogleAnalyticsObject'] = 'ga';
        window['ga'] = window['ga'] || function() {
            (window['ga'].q = window['ga'].q || []).push(arguments)
        }, window['ga'].l = 1 * new Date();
        var script = document.createElement('script'),
            firstScript = document.getElementsByTagName('script')[0];
        script.async = 1;
        script.src = '//www.google-analytics.com/analytics.js';
        firstScript.parentNode.insertBefore(script, firstScript)
    })();

    ga('create', 'UA-XXXXX-XX', 'auto');
    ga('send', 'pageview');
</script>

Řádek window['GoogleAnalyticsObject'] = 'ga' říká, že objekt Google Analytics bude uložen v globální proměnné ga, nicméně je zbytečný, protože ga je výchozí hodnota.

Dále následuje vytvoření objektu v proměnné ga, který představuje jen dočasný zásobník, kam se ukládá sekvence volání jednotlivých příkazů, a po načtení skriptu bude nahrazen skutečným objektem Google Analytics. Uvedený kód se dá výrazně zjednodušit vypuštěním window a pokud na stránce není víc měřících kódu, můžeme zrušit i podmínky ga = ga || ... a dostáváme se k jednoduchému:

ga = function() { ga.q.push(arguments) };
ga.q = [];
ga.l = +new Date;

Dále následuje vytvoření elementu <script> a jeho vložení do stránky. Nastavení script.async = 1 je zbytečné, protože podle HTML specifikace je každý skriptem vkládaný <script> asynchronní.

Nicméně – neexistuje žádný důvod, proč element <script> vytvářet JavaScriptem. Je mnohem výhodnější použít normální HTML. Stránka se díky tomu načte rychleji, nedochází k blokování a může se využít preload scanner v moderních prohlížečích. Tím se dostáváme k této podobě:

<script>
    ga = function() { ga.q.push(arguments) };
    ga.q = [];
    ga.l = +new Date;
    ga('create', 'UA-XXXXX-XX','auto');
    ga('send','pageview');
</script>
<script src="//www.google-analytics.com/analytics.js" async></script>

Aby se kód načítal asynchronně i v prohlížečích IE 5.5 – 9, je nutné kromě atributu async přidat ještě defer.

V dnešní době se relativní URL //www.google-analytics.com dá považovat za antipattern, vhodnější je vždy používat https.

Finální podoba

Konečná podoba včetně minifikace vypadá takto:

<script>
    ga=function(){ga.q.push(arguments)};ga.q=[];ga.l=+new Date;
    ga('create','UA-XXXXX-XX','auto');ga('send','pageview');
</script>
<script src="https://www.google-analytics.com/analytics.js" async defer></script>

Rychlejší, kratší a ještě navíc hezčí. Nechť slouží :-)

Web Font Loader

Podobným způsobem je vhodné načítat i Web Font Loader, tj. místo v dokumentaci uvedeného

<script>
   WebFontConfig = {
      typekit: { id: 'xxxxxx' }
   };

   (function(d) {
      var wf = d.createElement('script'), s = d.scripts[0];
      wf.src = 'https://ajax.googleapis.com/ajax/libs/webfont/1.5.18/webfont.js';
      s.parentNode.insertBefore(wf, s);
   })(document);
</script>

používejte

<script>
   WebFontConfig = {
      typekit: { id: 'xxxxxx' }
   };
</script>
<script src="https://ajax.googleapis.com/ajax/libs/webfont/1.5.18/webfont.js" async defer></script>

Google Tag Manager

Protože adresa skriptu se v kódu Tag Manageru skládá, uvedenou optimalizaci nelze bohužel použít.


Chrome a nekonečné přesměrování

Chrome 44 (beta) odesílá nově hlavičku HTTPS: 1, která může způsobovat problémy.

Na některých hostinzích (z těch co používám třeba WebSupport už to opravili) si pak PHP myslí, že požadavek je pod šifrovaným spojením HTTPS. Tj. proměnná $_SERVER['HTTPS'] === 'on'.

U aplikací v Nette, které neběží pod https, to pak způsobí nekonečný redirect. Aplikace si prostě myslí, že k ní přistupujete přes URL https://example.com a přesměrovává na http://example.com.

Můžete to vyzkoušet z příkazové řádky pomocí:

curl -I --header "HTTPS: 1" http://example.com`

Že je hlavička HTTPS: 1 problematická se už ví, takže je možné, že se změní a do Chrome nedostane. Každopádně jako rychlý workaround, aby nedocházelo ke smyčce přesměrování v betaverzi Chrome, je přidat na začátek bootstrap.php:

unset($_SERVER['HTTPS']);

Zároveň je dobré si uvědomit, že na některých hostinzích lze detekci šifrovaného spojení velmi snadno ošálit.

Doplnění: Chrome 45 už hlavičku HTTPS: 1 neodesílá.


Jak se opouští PHP 5.3

PHP 5.3 je stále nejpoužívanější verzí PHP. Nicméně jde o verzi nepodporovanou, nevycházejí už ani záplaty na závažné bezpečnostní díry. Podle trendů se zdá, že verze 5.4 by ji mohla vystřídat po prázdninách. Ironií je, že v ten moment i jí skončí podpora.

Jisté je, že v době vydání další verze Nette bude PHP 5.3 dávno passé, tudíž jsem v masteru změnil minimální požadovanou verzi z PHP 5.3.1 na PHP 5.4.4.

Právě tohle setinkové číslo jsem zvolil s ohledem na Debian 7.0 Wheezy.

Opuštění větve 5.3 znamenalo řadu spíš kosmetických změn (DI, Tracy), odstranění drobného počtu workaroundů (magic quotes u Http, Reflection, Utils) a výjimečně i užití nových tříd (Finder nebo Component-Model). Což potvrzuje, že verze PHP 5.3 byla skutečně hodně dobrá.

PHP 5.4 zároveň skýtá nové možnosti, první implementovanou byla žádaná serializace objektu DateTime do JSON. Dále se nabízí možnost nahradit Nette\Object za trait atd.

Na co jsem se ale hodně těšil byla normální syntax pro zápis polí pomocí [] namísto šíleného array(). A také možnost používat v šablonách <?= místo dlouhého <?php echo.

S jejich nasazením v masteru jsem ale váhal, protože by to udělalo z cherry-pickování do starších větví peklo. Nicméně verze Nette 2.1 a od května i 2.2 jsou ve stádiu, kdy se opravují jen závažné chyby, které se v Nette objevují jen zřídkakdy, a v aktuální verzi 2.3 se nové komity objevují jen svátečně, tudíž jsem si řekl, že netřeba to odkládat a všechny repozitáře převedl na hezčí syntax.

(Rebasování větví byl docela oříšek, rozepsal jsem se o tom včera. Takový převod tabulátorů na mezery by musel být hotové peklo.)

Nástroj Code Checker nyní kontroluje, aby se v repozitářích používala výhradně nová syntax a nedocházelo k míchání obou zápisů polí.

Přechod na PHP 5.5 by přinesl taky jednu byť drobnou syntaktickou změnu: konstantu ::class. A mohly by se použít nové funkce v Nette\Utils\Image a případně Nette\Security\Password, typ DateTime by se v typehintech nahradil za DateTimeInterface.

Přechod na PHP 5.6 by přinesl zejména nahrazení většiny func_get_args() & call_user_func_array() za trojtečky (včetně operátoru (expand) v Latte). V pár případech by se dalo využít i konstant obsahujících pole.

A přechod na PHP 7 by byla revoluce.


Jak na převod array() na [] v Gitu

Jak jsem v projektech, které používají PHP 5.4 a vyšší, převáděl starou syntaxi pro zápis polí array() na novou [].

Samotný převod PHP souborů je úplně jednoduchý. Stačí použít PHP 5.4 Short Arrays Converter a v repozitáři zavolat:

php /php54-arrays/convert.php .

Nástroj zamění syntax ve všech souborech *.php a *.phpt v aktuálním adresáři a také ve všech podadresářích. Změněné soubory jsem pak komitnul (příklad).

Oříšek je ale rebasování dalších větví na takto změněný master.

Nakonec jsem na to šel přes filtry. Ale plně zautomatizovat se mi to nepovedlo.

Nejprve je vhodné všechny větve rebasovat na master těsně před samotnou změnou syntaxe.

Poté jsem si vytvořil filtr nazvaný phparray, který bude on-the-fly překládat v PHP souborech [] na array() při checkoutu a obráceně při komitování. Tedy aby slučování probíhalo při použití staré syntaxe, ale komitnulo se s novou.

Filtr se vytvoří v souboru .git/config, v mém případě to vypadalo takto:

[filter "phparray"]
    clean = c:/php/php.exe w:/php54-arrays/convert.php
    smudge = c:/php/php.exe w:/php54-arrays/convert.php -r
    required

Aby se filtr při slučování používal (ale i při každém checkoutu, cherry-picku atd), je nutné doplnit do .git/config ještě následující:

[merge]
    renormalize = true

Filtr se bude aplikovat na soubory *.php a *.phpt, což se definuje v souboru .git/info/attributes (nepoužívejte .gitattributes, protože jde o dočasnou záležitost a nechceme ji komitovat):

*.php filter=phparray
*.phpt filter=phparray

Teď by ve větvi mělo fungovat git rebase master. Bez konfliktů, které by bylo nutné ručně řešit. Jenže ouha, konflikty se mi vytvářely (na Windows; je možné, že na Linuxu to půjde) a když jsem je chtěl řešit v TortoiseGit, objevovala se hláška, že na souboru .git/index.lock je zámek atd. Zkoušel jsem experimentovat s dalšími nastaveními pro merge, ale bez výsledku.

Zkusil jsem dělat rebase ručně: což znamená nejprve větev resetnout na master (git reset master --hard) a pak jednotlivé komity přidávat pomocí git cherry-pick <hash>. Nedělal jsem to z příkazové řádky, ale pomocí TortoiseGit. I nadále mi hlásil, že některé soubory neumí automaticky sloučit a je vyžadován ruční zásah, ale vždy stačilo soubor rozkliknout do TortoiseGitMerge a rovnou stisknout Mark as resolved.

Bylo to otravné, ale fungovalo to a postupně jsem „rebasoval“ všechny větve. Poté jsem filtr z .git/config a .git/info/attributes smazal.

Proč to nešlo úplně automaticky, nemám páru, nicméně bylo snazší hodinu klikat, než dva dny studovat Git.


phpFashion © 2004, 2017 David Grudl | o blogu

Pokud není uvedeno jinak, podléhá obsah těchto stránek licenci Creative Commons BY-NC-ND Creative Commons License BY-NC-ND

Ukázky zdrojových kódů smíte používat s uvedením autora a URL tohoto webu bez dalších omezení.