<![CDATA[Martin Hujer blog]]> 2018-12-16T21:38:36+00:00 https://blog.martinhujer.cz/ Sculpin <![CDATA[Lanzarote - kam na výlety? Co navštívit?]]> 2018-12-16T00:00:00+00:00 https://blog.martinhujer.cz/lanzarote-kam-na-vylety/ V říjnu 2018 jsme byli dva týdny na Lanzarote, takže mám spoustu tipů na zajímavá místa a obecně k Lanzarote.

Nejdříve jsme byli pár týdnů na Fuerteventuře, takže ty věci, které jsem popsal v prvním článku, už tu nebudu opakovat.

Lanzarote má nádhernou sopečnou krajinu, takže doporučuji se při výletech průběžně zastavovat na odpočívadlech u silnice a prohlížet si výhledy (spolujezdec může koukat, ale jako řidič jsem si moc výhledů z auta neužil).

Lanzarote - Montañas del Fuego - Timanfaya

Auto z půjčovny

Jeli jsme trajektem z Fuerteventury a hned po příjezdu jsme si v Playa Blanca zase půjčili auto od Cicar (dopředu jsme ho zarezervovali přes web). Měli jsme ho na celou dobu, než jsme se vraceli zpět na Fuerteventuru. Stejně jako na Fuerteventuře si neumím představit, jak bychom ty výlety zvládli autobusem.

Arrecife

Na Lanzarote jsme bydleli v hlavním městě Arrecife. Výhoda je, že je docela uprostřed ostrova, takže na všechny výlety je to podobně daleko.

Lanzarote - Arrefice

Parkování ve městě není jednoduché, protože se skládá převážně z úzkých jednosměrek. Většinou jsme parkovali přibližně tady nebo na hliněné ploše o pár metrů dále.

I ve městě toho je spoustu k vidění:

  • Playa del Reducto - městská pláž s pozvolným vstupem do vody
  • Castillo de San Gabriel - na ostrůvku, kam se dostanete po mostě je malá pevnůstka s muzeem uvnitř a hezkým výhledem shora.
  • Charco de San Ginés je uzavřená zátoka s přístavem pro malé lodě. Super na procházení okolo. Je zajímavé se tam jít podívat v různých časech, protože vzhledem k přílivu a odlivu může být třeba půlka zaparkovaných lodiček na suchu. Když už tam budete, tak doporučuji zkusit zmrzlinu v Antiu Xixona nebo se večer zastavit na tapas v La Caja de tapas.
  • Punto Sabroso je malá restaurace s latinsko-americkými a španělskými jídly. Velmi local atmosféra - sice mají menu i v angličtině, ale na případné doplňující dotazy už budete potřebovat španělštinu.
  • pokud se vydáte po cyklostezce podél moře směrem k letišti, tak můžete dojít na další pláže nebo až do Playa Honda. Šli jsme tam pěšky, ale asi by bylo zábavnější půjčit si kolo - je to docela daleko.

Montañas del Fuego - Timanfaya

Nejzajímavější věc na Lanzarote. V národním parku Timanfaya uvidíte měsíční krajinu jako následek sopečných erupcí v letech 1730 a 1736. Doporučuji tam vyrazit brzy po ránu, abyste se vyhnuli frontě.

Lanzarote - Montañas del Fuego - Timanfaya

Dostanete se tam autem a vstupné se platí už na odbočce z hlavní LZ-67 na LZ-602 (pozor, nedá se tam platit kartou). Následně dojedete na parkoviště k Restaurante El Diablo. Až zaparkujete, tak běžte do fronty na autobus. Čekali jsme tam jen chvilku. Autobus vás vezme na projížďku skrz park (výklad ve španělštině, angličtině a němčině). Dnes už je aktivní jen sopka Timanfaya, podle které se celý park jmenuje.

Po projížďce vás ještě čeká ukázka toho, že sopka je aktivní (horkem v díře v zemi tam zapalují nějaké roští). Potom se můžete jít podívat do Restaurante El Diablo, kde kromě jiného nabízejí maso grilované na horku ze sopky. Ten gril stejně jako postavu "ďábla" (logo parku) vymyslel César Manrique (viz dále).

Lanzarote - Montañas del Fuego - Timanfaya - El Diablo

Vstupenky Bonos

Na Lanzarote si můžete zakoupit jednu vstupenku ke vstupu na několik hlavních turistických atrakcí. Je to levnější než si kupovat jednotlivé vstupy zvlášť. Více informací najdete na oficiálním webu.

César Manrique

César Manrique byl slavný lanzarotský umělec, sochař a architekt 20. století. Navrhnul spoustu věcí, které na Lanzarote uvidíte. Takový místní Jára Cimrman.

Casa Museo De César Manrique

Ve městě Haría je Casa Museo De César Manrique - muzeum v domě, kde žil César Manrique. Dovnitř jsme nakonec nešli, protože nám 10€ za vstup přišlo hodně a nechtěli jsme trávit odpoledne vevnitř v muzeu.

Na dvoře mají vystavený SEAT Ibiza, který Manrique natřel na výstavu aut v Barceloně v roce 1987. Zajímavé je, že Cicar (největší kanárská půjčovna aut) se v roce 2015 domluvila se SEATem a nechali si nabarvit 96 nových SEAT Ibiza tak jako ten historický a normálně je půjčují (viděli jsme je několikrát). Našel jsem k tomu docela hezké video.

Lanzarote - César Manrique - SEAT Ibiza

Mirador del Río

Mirador del Río je super vyhlídka v severní části ostrova. Je odtamtud krásný výhled na další kanárský ostrov La Graciosa a případně můžete posedět v zabudované kavárně. Jak vás jistě nepřekvapí, tak to celé navrhl César Manrique.

Lanzarote - Mirador del Río - La Graciosa

Volcán de la Corona (hike)

Cestou z Mirador del Río sí můžete udělat krátký výlet na kráter Volcán de la Corona z vesnice Ye. Doporučuji zastavit u kostela a pak jít podle trasy na Wikiloc. Cesta vede do kopce mezi vinicemi (jednotlivé rostliny révy v ohrádkách z kamenů) až ke kráteru. Byli jsme tam zrovna když bylo zataženo a skoro do deště, takže to vypadalo hodně tajemně. Od kráteru buď můžete pokračovat jako okruh nebo se vrátit po stejné zpět.

Lanzarote - Caldera de Monte Corona

Cueva de los Verdes

Cueva de los Verdes je podzemní jeskyně sopečného původu (vypadá to jako krápníková jeskyně, ale nejsou tam krápníky). Vznikla tak, že tamtudy tekla roztavená láva směrem k moři. Určitě stojí za návštěvu.

Lanzarote - Cueva de los Verdes

Jameos del Agua

Jameos del Agua je jeskyně s velkým podzemním jezírkem, kde žijí bílí mini-krabi. Kromě jiného tam je také muzeum a podzemní koncertní síň. Samozřejmě v tom má zase prsty César Manrique.

Lanzarote - Jameos del Agua

Lanzarote - Jameos del Agua - Sunset

Jardín de Cactus

Jardín de Cactus je obrovská kaktusová zahrada, kterou (jak jinak) navrhl César Manrique. Pokud budete z chození mezi kaktusy unavení, tak si můžete dát kávu v kavárně, která je součástí zahrady. (Baví mě, že i na takhle turisticky exponovaném místě ta káva je docela dobrá a není předražená).

Lanzarote - Jardín de Cactus

Teguise

Historická vesnice Teguise byla kdysi hlavním městem ostrova. Kousek za městem je kopec s výhledy na celý ostrov a na něm pevnost Castillo de Santa Barbara. Zároveň je tam kráter, který si můžete obejít dokola.

Lanzarote - Castillo de Santa Barbara

Casa Museo del Campesino

Casa Museo del Campesino je muzeum zemědělství a řemesel (vstup zdarma). Uprostřed areálu můžete sejít do jeskyně s tunelem. Celé to vymyslel náš známý César Manrique včetně monumentu stojícího před muzeem.

Lanzarote - Casa Museo del Campesino

Vína na Lanzarote

Při výletech po ostrově si určitě všimnete, že všude pěstují révu. Typicky je každá rostlina révy v samostatné ohrádce z kamenů, které ji chrání před větrem. Zároveň mají půdu přikrytou drobným sopečným kamením, které drží vláhu (a přitom je lehké). Víno si můžete koupit pak i běžně v supermarketu - láhev bílého El Grifo stojí 11€ (případně můžete zkusit jiné značky - vždycky je na nich napsané, že jsou z Lanzarote). Pokud budete mít čas, tak můžete navštívit muzeum vinařství Museo el Grifo (mají i variantu prohlídky s ochutnávkou).

Lanzarote - Vinná réva

Montaña Blanca (hike)

Montaña Blanca je hora se super výhledem, ale podle mě to je takový otloukánek, protože se jmenuje stejně jako druhá Montaña Blanca, která má uprostřed kráter, takže je mnohem populárnější. Ale tenhle hike jsme šli na tu první, protože cestou na tu druhou jsme narazili na uzavřené silnice kvůli triatlonu. Mrkněte na záznam trasy na wikiloc. Jeli jsme tam v sobotu, takže jsme ve vesnici Montaña Blanca zaparkovali na prázdném parkovišti u školy. A následoval trošku náročnější hike na horu. Výhoda je, že to lze jít jako okruh a není potřeba se vracet po stejné trase.

Lanzarote - Montaña Blanca

Caldera de Montaña Blanca (hike)

Výlet ke kráteru Caldera de Montaña Blanca je delší, tak si nezapomeňte vzít dost vody a svačinu. Záznam trasy jsem opět dal na wikiloc. Parkovali jsme zbytečně daleko ve vesnici, můžete buď zaparkovat na kraji té hlavní silnice kousek před odbočkou na prašnou cestu nebo ještě kus popojet po té prašné cestě a zaparkovat tam (označeno na mapě). Pak už se vydáte po svých sopečnou krajinou.

Lanzarote - Caldera de Montaña Blanca

Je super, že to je oficiální trasa, takže jsou podél i informační tabule o sopkách apod. Nejdříve dojdete k menšímu kráteru, do kterého se dá vejít z boku (Caldera de Montaña Caldereta). Zajímavé je, že tam dřív něco pěstovali a chovali kozy (jak je to uvnitř chráněné proti větru, tak se tam drží vlhkost). Teprve potom začnete stoupat na okraj velkého kráteru Caldera de Montaña Blanca. Ten je možné obejít dokola (cestou vylezete na samotný vrchol Montaña Blanca). Pozor, že tam, kde se pak potřebujete odpojit z okruhu po obvodu kráteru, ta odbočka není úplně zřejmá, ale je označená naskládanými kameny (občas koukněte do mapy). Po sestupu se napojíte na tu cestu, po které jste ke kráterům přišli.

Lanzarote - Caldera de Montaña Blanca

Pokud byste na Caldera de Montaña Blanca chtěli výlet s průvodcem, tak je v nabídce na OutdoorVisit.

Los Hervideros

Na západním pobřeží je několik míst, které stojí za zastávku. Los Hervideros je vyhlídka z útesů na mořský příboj (i v jeskyních). Název to má podle toho, že se tam jakoby vaří voda.

Lanzarote - Los Hervideros

El Golfo a pár dalších věcí na západním pobřeží

Pokud pojedete od Los Hervideros dále, tak narazíte na pláž Playa Montaña Bermeja, která také stojí za vidění. Nakonec dojedete do městečka El Golfo. Je tam spoustu rybích restaurací s výhledem na moře a na případný západ slunce. Až tam budete čekat, tak se určitě dojděte podívat na zelené jezírko El Lago Verde.

Lanzarote - Lago Verde

Vrak lodi

Kousek od Arrecife můžete zastavit na pláži, kterou zdobí vrak lodi. (Zaparkovat můžete o pár desítek metrů dál, kde je před budovou dost místa.) Vrak tam je od roku 1981, kdy ta loď plula okolo Lanzarote a zjistili, že jim teče dovnitř. Arrecife jim nedovolilo jet do přístavu, protože kdyby se potopili uprostřed přístavu, tak by ho zablokovali. Místo toho je nasměrovali na mělčinu v písčité zátoce, kde je dodnes. Už delší dobu plánují, že vrak odstraní, ale zatím (říjen 2018) tam pořád je. Když jsme tam byli, tak z něj někdo dokonce skákal do vody.

Lanzarote - Shipwreck Arrecife

Punta Mujeres

Punta Mujeres je městečko, kde naleznete přírodní "bazény" - ohraničený kus moře, kde se dá příjemně koupat.

Pastelería San Antonio

Sladká tečka na závěr. Pastelería San Antonio je pekárna/kavárna ve vesnici Tías. Stavovali jsme se tam dvakrát cestou z nějakého výletu na kávu a něco sladkého nebo slaného k jídlu.

Závěr

Byli jsme na Lanzarote jen dva týdny, ale viděli jsme toho hrozně moc. Neumím si představit, že bychom na celý ostrov měli méně času. Opět se osvědčilo půjčené auto, i když večerní parkování v přeplněném Arrecife bylo náročnější.

Pokud se budete chystat na Lanzarote a budete mít více času, tak doporučuji alespoň týden z toho strávit na Fuerteventuře, tam je toho taky spoustu k vidění.

A pokud se chystáte do Las Palmas na Gran Canarii, tak mrkněte na moje tipy na výlety.

OutdoorVisit outdoor tours

Pokud chcete zkusit něco netradičního, tak doporučuji mrknout na outdoorové zážitky a výlety na Lanzarote.

]]>
<![CDATA[Jaké novinky přinese PHP 7.3]]> 2018-11-28T00:00:00+00:00 https://blog.martinhujer.cz/jake-novinky-prinese-php-7-3/ Vydání PHP 7.3 je plánováno na 6. prosince 2018. Přináší několik nových funkcí, vylepšení a různá pročištění jazyka. Oproti jiným vydáním mu sice chybí nějaký trhák, ale na druhou stranu nepřibyly ani žádné zásadní nekompatibilní změny, takže upgrade bude snadný.

Článek vyšel na serveru Zdroják.cz

]]>
<![CDATA[Best PhpStorm plugins for Symfony development]]> 2018-11-26T00:00:00+00:00 https://blog.martinhujer.cz/best-phpstorm-plugins-for-symfony-development/ I've been using PhpStorm for quite a while and I'm still surprised now and then when it suggests an auto-completion for something I thought that's not possible.

But there are still many things - usually framework- or library-specific - that PhpStorm cannot do on its own. But there are plugins that can step in place and do the magic for specific framework or library.

PHP Annotations

PHP Annotations plugin analyses the classes which can be used as annotations and provides code-completing when writing annotations - e.g. Doctrine ORM mappings.

PHP Annotations plugin

PHP Toolbox

PHP Toolbox plugin was extracted from Symfony plugin and provides better auto-completion for several libraries (PHPUnit, Behat, Doctrine, Twig etc.)

Symfony Plugin

Both PHP Annotations and PHP Toolbox are best used together with the Symfony Plugin. This plugin provides auto-completion for anything in Symfony you can imagine. It analyses the DI container code, so it can suggest the services when you call $container->get(). It provides various auto-completions in the YAML config files. Apart from that, it can handle lots of Form, Twig and Routing auto-completions. You can click through from controller to template, from the name of the route to the controller where it is defined. It analyses translation files and provides the completion for the translations when calling the translate function or using trans filter in Twig.

How to use custom template directory with the Symfony plugin?

If you have templates in a custom namespace and directory - e.g. configured in config/packages/twig.yaml, the auto-completion in controllers or other templates won't work for those, because the Symfony plugin can't detect them.

twig:
    paths:
        '%kernel.project_dir%/src/App/Resources/templates': App
        '%kernel.project_dir%/src/Admin/Resources/templates': Admin

You can fix it by manually adding them in PhpStorm Settings (PHP -> Symfony -> Twig/Template). But each of the developers must do it himself. Unless you put in into ide-twig.json in a project root:

{
    "namespaces": [
        {
            "namespace": "App",
            "path": "src/App/Resources/templates"
        },
        {
            "namespace": "Admin",
            "path": "src/Admin/Resources/templates"
        }
    ]
}

This file is loaded by Symfony plugin and the namespaces and paths will be configured automatically (you can check it in the Settings).

Enable translation keys auto-completion for custom translation methods

When you create a custom method that accepts translation key, the PhpStorm won't do the auto-completion for it, because it does not know that the parameter is a translation key. Luckily, the Symfony plugin provides an easy way to let it know of the type of the parameter. Have a look at the following example:

<?php
class TitleManager
{
    /**
     * @param string $label #TranslationKey
     */
    public function addItem(string $label): void
    {
        // ...
    }
}

$titleManager = new TitleManager();
$titleManager->addItem('app.products.name'); // the translation key auto-completion will work here 

You can see that I added #TranslationKey to the method parameter PHPDoc. It is something they call Hash Tags in Symfony plugin. It allows you to define the type of the parameter, so the plugin can provide the auto-completion. Apart from TranslationKey, you can also use Entity, Service, FormType, Template, Route, Class, TranslationDomain, FormOption or Interface (don't forget to prefix them with #).

PHPUnit Enhancement

PHPUnit Enhancement plugin provides smart autocomplete for mock creation. It also handles refactoring - if you rename a method which is mocked, it is correctly renamed in the string in tests.

PHPUnit Enhancement plugin

PHP composer.json support

PHP composer.json support plugin adds composer.json auto-complete and validation. It also displays which version of each packages is installed (from the data in composer.lock)

Php Inspections (EA Extended)

Php Inspections (EA Extended) is a plugin that adds a lot of inspections for statically analyzing the PHP code you are writing and suggesting fixes and improvements.

Twig Support

Twig Support is an official plugin from Jetbrains bundled with PhpStorm, so just enable it in the settings and you are done.

.env files support

Symfony 4 uses .env files for configuration parameters (instead of parameters.yml) and .env files support plugin provides syntax highlighting for the .env file.

.ignore

.ignore plugin provides syntax highlighting and path auto-completion for .gitignore (and other ignore files). It also automatically changes the color of the ignored files in the Project File Tree to gray.

Conclusion

I can't imagine using PhpStorm for Symfony development without those plugins. They save me time and prevent mistakes by providing the magic auto-completion.

Do you use some other useful plugins? Please let me know in the comments.

Update: If you are interested in plugins not directly related to Symfony, have a look at the Essential PhpStorm plugins article by localheinz.

]]>
<![CDATA[Fuerteventura - kam na výlety? Co navštívit?]]> 2018-11-18T00:00:00+00:00 https://blog.martinhujer.cz/fuerteventura-kam-na-vylety/ V říjnu 2018 jsme byli skoro tři týdny na Fuerteventuře, takže mám spoustu tipů na zajímavá místa a obecně k Fuerteventuře.

Fuerteventura - Puerto del Rosario

Cesta tam - letenky, autobus

Na Fuerteventuru se sice dá letět přímo z Prahy, ale jednosměrná letenka stojí cca 7 tisíc, takže jsme nakonec letěli s Ryanair z Berlína. Jedna letenka ze Schönefeldu stála asi 30€. Dá se tam v pohodě dopravit Flixbusem nebo Regiojetem (autobusem). A taky vlakem ČD (ranní jízdenky myslím v 6:30 z Prahy jsou docela levné).

Připomínám tip, který už jsem někde psal - na letišti se po security typicky dá docela levně koupit voda v láhvi v automatu na pití - na Fuerteventuře třeba 0.5l za 1€. Na Schönefeldu si zas můžete skrz security vzít prázdnou láhev a naplnit si ji z vodovodu.

Doprava - autobusy

Autobusy na Fuerteventuře provozuje společnost Tiadhe. Jízdní řády mají na webu - pozor, jsou tam jen odjezdy z výchozí stanice, ne průjezdy jednotlivými zastávkami. Jízdenky se kupují u řidiče v hotovosti.

Doprava - trajekty

Po dvou týdnech na Fuerteventuře jsme se na dva týdny přesouvali na Lanzarote a pak zase zpět. Z města Corralejo tam jezdí tři společnosti. Armas, Fred Olsen a Lineas Romero. Fred Olsen je nejrychlejší, ale taky nejdražší. My jsme obě cesty jeli s Lineas Romero (15€ za osobu a cestu), kteří jsou spíš taková výletní loď a neberou auta.

Doprava - auto

Vzhledem k tomu, že jsme během dne potřebovali kromě výletů také pracovat, tak jsme si půjčili auto na celých 14 dnů, co jsme byli na Fuerteventuře. Ukázalo se, že nejdražší je půjčení na jeden den (jako jsme si ho třeba půjčovali v Las Palmas) a pak to hodně klesne. Půjčení na celých 14 dnů stálo 220 € (+ nafta).

Půjčovali jsme rovnou na letišti od Cicar (i pak na Lanzarote) - mají pojištění bez spoluúčasti a stačí normální karta, není potřeba kreditka. Auto jde dopředu zarezervovat na webu, abyste měli jistotu, že ho budou mít k dispozici. Zároveň si tím ušetříte opisování údajů při přebírání, protože to všechno už jde vyplnit přes web. Při přebírání si můžete zadarmo dopsat i druhého řidiče, což je fajn. Auto jsme vraceli v Corraleju v přístavu (tzn. není problém vrátit jinde, než jste si ho půjčili). Palivo by při vrácení mělo být na stejné úrovni jako předtím.

Pozor, s auty z půjčoven by se mělo jezdit jen po asfaltových cestách, jinde většinou neplatí pojištění (mrkněte do smlouvy).

Faro del Tostón - Opel Astra

Počasí

Typicky bylo na koupání - teploty kolem 24°C a když svítilo slunce tak vedro. V noci teploty lehce pod 20°C.

Jídlo

Pro Fuerteventuru jsou typické kozí sýry - queso majorero (viz níže).

Voda z vodovodu je odsolovaná, takže není vhodná na pití a nezbývá, než nosit barely s vodou ze supermarketu. Vypozoroval jsem, že 8l barely mají typicky lepší držadlo než 5l, takže i když jsou těžší, tak se lépe nosí.

Ve větších obchodech běžně mají pult s čerstvými rybami a mořskými plody. My kupujeme předvařené krevety (langostino cocido, 9€ za kilo), nebo plátek z tuňáka, který vám ukrojí (rodaja de atún, 12€ za kilo). Letos jsme rozšířili repertoár i o chobotnici (pulpo cocido). Dá se koupit předvařené zavakuované chapadlo nebo už přímo kousky. Stačí na chvíli hodit na pánev a pak posypat mletou paprikou (pulpo a la gallega)

Pulpo a la Gallega

Bankomaty

Za výběr z některých bankomatů si kromě vaší banky účtuje poplatek ještě ta banka, které ten bankomat patří. Ale při výběru z bankomatů Cajamar Caja Rural poplatek neúčtují (vyzkoušeno Revolut a Airbank kartou).

Města na Fuerteventuře

Fuerteventura je velký ostrov - druhý největší z Kanárských ostrovů - a přitom tam žije jen 100 tisíc lidí, takže je hodně prázdný. Nechtěli jsme trávit tolik času v autě, tak jsme první týden bydleli na severu a projeli jsme ta místa na severu a druhý týden na jihu a prozkoumali to tam. Města na Fuerteventuře se hodně liší, v některých bydlí hlavně místní a jiná jsou letoviskovitá letoviska.

El Cotillo

El Cotillo je malé městečko na severu, kde jsme strávili první týden. Není přeplněné turisty, takže pokud bychom na Fuerteventuru jeli někdy na měsíc, tak asi do Cotilla. Je zajímavé tím, že má velkou surfařskou pláž. A plážové laguny.

  • Laguny jsou část pláže, která je chráněná přírodním vlnolamem a při odlivu tam je dost mělko - ideální pro děti.
  • Castillo del Tostón - místní minipevnost s fajn výhledem. Vstup 3€, platba pouze kartou.
  • El Goloso de Cotillo - kavárna, kde jsme byli asi 5×
  • Kalima - tapas bar

El Cotillo - lagunky

Corralejo

Corralejo je letovisko oblíbené britskými turisty. Pláž nic moc. Oproti El Cotillo dražší.

Puerto del Rosario

Puerto del Rosario je hlavní město Fuerteventury, málo turistů. Strávili jsme tam posledních 5 dnů. V přístavu průběžně kotví různé výletní lodě. Pokud neznáte, tak doporučuji MarineTraffic.com - obdoba FlightRadaru pro lodě. Hezká pláž s bílým pískem.

  • Oficina de Turismo de Puerto del Rosario - turistické informační centrum. Doporučuji navštívit hned po příletu, získáte spoustu tipů (možná i něco, co tu nebudu mít napsané)
  • Café Atlántico - cafeteria s výhledem na moře. Mají dobré obložené bagety za 3€.
  • Cafetería Del 15 - cafeteria, kam jsme náhodně zapadli po příletu, když jsme měli hlad. Velmi local - chodí tam na oběd místní v montérkách.
  • parkoviště kousek od centra, zdarma. Pozor, abyste nezadali do navigace druhé podobné, které je mnohem dál (nám se to první den povedlo).
  • Panadería Pastelería Pulido Alonso - příjemná kavárna, mají několik poboček na ostrově.

Další města

  • Calleta de Fuste - letoviskovité letovistko

  • Gran Tarajal - městečko zajímavé zejména tím, že má pláž s tmavým pískem a spoustu jednosměrek.

  • Costa Calma - letovisko, s obrovskou pláží, kde jsme strávili náš druhý týden na Fuerteventuře. Tady je to pro změnu oblíbené zejména německými turisty. Bydleli jsme v apartmánu kousek dál z centra, takže to bylo fajn. A v místním Sparu mají v sortimentu i kávu Dallmayr.

  • Morro Jable - další letoviskovité letovisko na jihu ostrova. Hodně pěkná pláž.

Výlety

Výletů jsme podnikli spoustu. Ta místa, která jsou přímo v nějakém městě jsem napsal přímo k nim. Všechno jsme objezdili autem, takže nevím, které z nich jsou nedosažitelné autobusem.

El Faro del Tostón

El Faro del Tostón je maják několik kilometrů od El Cotillo. Je tam muzeum tradičního rybářství, ale dorazili jsme tam až po zavíračce. Původně jsme tam chtěli jít pěšky z El Cotillo, ale naštěstí jsme jeli autem, je to po silnici, takže by to nebyla zábavná procházka.

El Faro del Tostón

Lajares

Na Lajares našla Ivča v Lonely Planet doporučení, že tam jsou fajn kavárny. Ty tam jsou (mimochodem pobočka našeho oblíbeného El Goloso, které jsme znali z Cotilla). Akorát, že ono tam už nic dalšího zajímavého není.

La Oliva

La Oliva je malá vesnice s docela hezkým kostelem a galerií. Ale co je zajímavé jsou větrné mlýny Molinos De Villaverde kousek odtamtud. Pozor, silnice nevede až k nim a pak se nečekaně mění na hliněnou a není se kde otočit. Takže radši auto nechte u hlavní silnice a dojděte to pěšky.

Molinos De Villaverde

Museo del Queso Majorero

I když je na první pohled Fuerteventura suchá a pustá, tak tam chovají kozy majorero a z jejich mléka vyrábějí sýr (pod různými značkami). O historii a současnosti výroby sýra se dozvíte v muzeu sýra Museo del Queso Majorero. Za mě hodně zábavné a dobře zpracované. Součástí je i větrný mlýn a kaktusová zahrada, takže si na to nechte více času. Na ty kozy můžete narazit po celém ostrově i u silnice nebo na silnici, tak pozor.

Museo del Queso Majorero

Antigua a Pulido Alonso

Kavárnu Pulido Alonso už jsem předtím zmiňoval, ale ta v Antigua je pro nás speciální. Protože když jsme po druhém týdnu na Fuerteventuře jeli do Corraleja na trajekt na Lanzarote, tak jsme cestou zjistili, že máme zbytečně moc času a že bychom se cestou mohli stavit někde na kávu. A při cestě byla Antigua, kde jsme podle Google Map vybrali právě kavárnu Pulido Alonso.

Betancuria

Betancuria byla kdysi hlavním městem Fuerteventury. A kromě jiného tam je kostel s počátky už v 15. století. Zajímavostí je, že to tam funguje na podobném principu jako Karlštejn - po 17h tam je všecko zavřené. Kousek od Betancurie jsou na kopci sochy nějakých králů a fajn výhled do kraje.

Sochy nedaleko Betancuria

Vyhlídka u soch

Parque Natural Dune De Corralejo

Písečné duny nedaleko Corraleja. Zaparkovat se dá dobře na tomhle parkovišti. Pokud jste nikdy na písečných dunách nebyli, tak určitě doporučuji - je to super zážitek (další jsou třeba v Maspalomas na Gran Canarii). A směrem ke Corrajelu je několik hezkých pláží. Nakonec jsme se tam nekoupali, protože když jsme přijeli, tak byla žlutá vlajka a než jsme vyndali věci z auta, tak ji plavčík vyměnil za červenou.

Duny Corrajelo

Jenomže to bychom nebyli my, kdybychom jenom zevlili na dunách. Místo toho jsme měli naplánovaný výstup na nedaleký kopec Montaña Roja. Záznam trasy jsem nahrál na Wikiloc. Když se na to podíváte, tak je vidět, že jsme zastavili až moc daleko - ale z auta to vypadalo, že je tam všude hrozně vysoký rantl a nechtěli jsme to auto zničit. Když jsme tam pak šli pěšky, tak na dvou místech to bylo na parkování OK, tak jsou v té mapě označené. Shora byl pak super výhled.

Montaña Roja

Salinas del Carmen

Sůl se získává buď v solných dolech nebo se taky dá usušit mořská voda, jako to třeba dělali a dělají v muzeu výroby soli Salinas del Carmen. Vnitřní expozice je pěkně zpracovaná, ale hlavně je součástí i venkovní část, kde si prohlédnete, jak to celé funguje.

Salinas del Carmen

Pájara a vyhlídka na FV-605

Co jsme občas dělali bylo, že pokud jsme měli čas, tak jsme místo nějaké hlavní silnice (FV-1, FV-2) vzali nějakou scénickou trasou přes kopce a vesnice (typu FV-605). Takhle jsme se stavili ve vesnici Pájara. Ta je zajímavá tím, že tam mají kostel ze 17. století, řeku, kde by se vám prášilo za kánoí a uprostřed kruháče místo fontánky sochu pána dojícího kozu.

Pájara - řeka

Pájara - socha dojiče

Pokud pojedete z Pájary na jih přes kopce po FV-605, tak cestou můžete zastavit na vyhlídce se super výhledem

Vyhlídka FV-605

Pozo Negro

Rybářská vesnice na konci silnice. Pláž s černým pískem a oblázky a dvě kavárny.

Faro de la Entallada

Faro de la Entallada je maják na útesu se super výhledem. Poslední úsek silnice je opravdu úzký a se svodidly tam docela šetřili, tak opatrně.

Faro de la Entallada

Mirador del Salmo

Vyhlídka Mirador del Salmo stojí za zastávku, pokud bude mít cestu okolo. Je to hned u silnice.

Pico de la Zarza

Pico de la Zarza (někdy také nazývaná Pico de Jandía) je nejvyšší hora Fuerteventury. Sice má jen 807 m. n. m., ale zas na ní stoupáte od nuly. Záznam trasy (15 km) najdete na Wikiloc. Na výstup jsme vyráželi v 9h ráno a naštěstí bylo chvílemi pod mrakem. Určitě si vezměte hodně vody a něco na hlavu, protože cestou je přesně nula míst, kde se dá schovat před sluncem. Auto jsme nechali zbytečně daleko, dalo by se docela dobře zaparkovat až tam, kde jsme se odpojili od silnice. Z vrcholu jsou super výhledy i na severní stranu ostrova.

Pico de La Zarza

Cofete

Cofete je hezká pláž na severní straně ostrova. Kvůli silným proudům se tam nedá koupat. Jde tam buď dojet autem (pozor, je prašná cesta) nebo speciálním autobusem s pohonem 4x4 z Morro Jable. Vyjíždí z Estación de Guaguas (=autobusák). Je to linka L111 a pozor, bere jen 18 lidí, takže tam buďte dřív.

Cofete bus

Zpátky můžete jet buď tím stejným autobusem nebo se jako my můžete projít přes kopec (12 km). Trasu jsem opět dal na Wikiloc.

Cofete - cesta přes kopec

Islote de Lobos

Islote de Lobos je malý ostrůvek kousek od Corrajela, dá se tam dojet výletní lodí. Tohle je jediná věc z celého článku, kterou jsme si nechali na někdy příště, ale uvádím ji tu pro úplnost.

Závěr

Na to, že jsme tam nebyli tak dlouho, jsme toho stihli hrozně moc. Hodně k tomu pomohlo to půjčené auto, protože jsme mohli jen i na krátký výlet později odpoledne, což by autobusem bylo mnohem komplikovanější. A těch 14 dnů bylo tak akorát, jinak by to bylo moc hektické.

Pokud se budete chystat na Fuerteventuru a budete mít více času, tak doporučuji alespoň týden z toho strávit na Lanzarote, tam je toho taky spoustu k vidění.

A pokud se chystáte do Las Palmas na Gran Canarii, tak mrkněte na moje tipy na výlety.

OutdoorVisit outdoor tours

Pokud chcete zkusit něco netradičního, tak doporučuji mrknout na outdoorové zážitky a výlety na Fuerteventuře.

]]>
<![CDATA[Use different Google Analytics ID by domain in Google Tag Manager]]> 2018-08-26T00:00:00+00:00 https://blog.martinhujer.cz/use-different-google-analytics-id-by-domain-in-tag-manager/ When setting up Google Analytics (or Facebook Pixel) in the Google Tag Manager the typical approach is to put the UA-code or the Pixel ID into the Constant Variable. And that ID is then used in the GA/Facebook Tag.

But soon after launch the people from Marketing will start complaining that some strange orders and conversions are appearing in the Google Analytics.

What happened? Apart from real orders, also the orders made in testing and dev environments are sent there.

There is a better way. You can easily use different UA codes in production and in testing environments. In the rest of the article I will guide you through setting it up.

Analysis

It is clear that we want to use testing UA code in dev/test environments, but apart from that we also want to use it when testing the Google Tag Manager configuration itself with Preview feature (even on production website).

The decision process for the UA code goes like this:

  • Are we running in Debug mode?
    • YES: use test ID
    • NO:
    • Are we on production domain?
      • YES: use real ID
      • NO: use test ID

Preparation

  1. Go to Google Tag Manager and create two Constant Variables:

    • GA_ID_DEV with the testing ID
    • GA_ID_PROD with the production ID
  2. In the Variables section in Built-In Variables enable Debug Mode and Page Hostname variables.

Setting up the hostname detection

  1. Create a Variable of type Lookup Table and name it GA_ID_BY_HOSTNAME
  2. Input Variable is {{Page Hostname}}
  3. Click Add row
  4. Put your production domain into the Input field (just the domain without https:// and the trailing /)
  5. Put {{GA_ID_PROD}} into the Output field
  6. Check Set default value checkbox
  7. Put {{GA_ID_DEV}} to the Default value field

It should look like this: GA_ID_BY_HOSTNAME variable configuration

By defining only the production domain and using default value for anything else, we handle any testing or dev environment.

Setting up the Debug environment detection

If you look back into the Analysis chapter, we have covered the Are we on production domain? part. Now we will cover the Are we running in Debug mode?.

  1. Create a Variable of type Lookup Table and name it GA_ID
  2. Input Variable is {{Debug Mode}}
  3. Click Add row
  4. Put true into the Input field and {{GA_ID_DEV}} into the Output field
  5. Click Add row again
  6. Put false into the Input field and {{GA_ID_BY_HOSTNAME}} into the Output field

It should look like this: GA_ID variable configuration

You might have noticed that we have used the variable GA_ID_BY_HOSTNAME which we prepared in previous step.

Setting up the Google Analytics Tag

With all those variables prepared, you can set up the Google Analytics tag as usual. But when creating the Google Analytics Settings, put {{GA_ID}} into the Tracking ID field as in the following picture. It will be resolved to correct UA code depending on the environment.

Google Analytics Settings variable

That's it!

Conclusion

Apart from Google Analytics ID, you can use this guide to set up Facebook Pixel ID or any other system where you can easily create different IDs for different environments.

Are you using similar approach? Or did you find a better way? Let me know in the comments!

]]>
<![CDATA[Consistence brings consistency to the PHP]]> 2018-02-06T00:00:00+00:00 https://blog.martinhujer.cz/consistence-brings-consistency-to-the-php/ In the article I describe the Consistence library that aims to bring consistency to PHP applications.

There is no argument, that PHP can sometimes be a bit inconsistent about naming stuff and maintaining order of parameters for related functions. Also, in some cases it is not strict and allows you to use the language and the functions in a wrong way. Sometimes you get false as a return value where an exception would be appropriate.

I really like the idea of code being strict because it prevents errors in the application. E.g. strpos usually returns int, but it returns false when the $needle was not found. It would be much better to throw SubstringNotFoundException in that case.

Consistence provides opinionated strict wrappers with better error handling and consistent naming and consistent parameters order.

Disclaimer: I haven't created the library, but I find it useful and I hope you will as well. It is one of the packages I use on every project.

Let's dive into it.

Use Enums for better type safety

It's a good practice to use constants instead of passing magic numbers (or magic strings) around. But you still pass them as a string, so there is nothing that prevents you from passing any other arbitrary string:

<?php
class BodyType
{
    const SUV = 'suv';
    const COMBI = 'combi';
    const HATCHBACK = 'hatchback';
    const CABRIO = 'cabrio';
    // ... 
}

function createCar(string $bodyType) {
    // do something with $bodyType
}

$car = createCar(BodyType::CABRIO);
$car = createCar('doubledecker'); // unexpected things can happen

Consistence provides an enum implementation. When you extend the class from Enum, all constants are automatically treated as possible enum values:

<?php
class BodyType extends \Consistence\Enum\Enum
{
    const SUV = 'suv';
    const COMBI = 'combi';
    const HATCHBACK = 'hatchback';
    const CABRIO = 'cabrio';
    // ...
}

function createCar(BodyType $bodyType) {
    echo $bodyType->getValue(); // you can use `getValue()` method to access the internal enum value
}

// use get() to get an instance of enum
$cabrioBodyType = BodyType::get(BodyType::CABRIO);

// It is a regular class instance
var_dump($cabrioBodyType instanceof BodyType); // bool(true)

// You always get the same instance, so you can compare them
var_dump(BodyType::get(BodyType::CABRIO) === BodyType::get(BodyType::CABRIO)); // bool(true)

// Type-hint checks work as expected
$car = createCar($cabrioBodyType); 

// Argument 1 passed to createCar() must be an instance of BodyType, string given
$car = createCar('doubledecker'); 

Enums also make it easier to write an actual code. Compare the following examples. When you want to instantiate the class from the first one, you have to dig into the documentation to check what are the allowed values:

<?php
class Car
{
    public function __construct(
        string $bodyType,
        string $transmissionType,
        string $engineType,
        string $fuelType
    )
    {}
}

In the second one, you just start typing BodyType::get(BodyType:: and then choose from the suggested values:

<?php
class Car
{
    public function __construct(
        BodyType $bodyType,
        TransmissionType $transmissionType,
        EngineType $engineType,
        FuelType $fuelType
    )
    {}
}

There are Doctrine and Doctrine + Symfony integrations which allow you to use Enums in Doctrine entities:

<?php
use Consistence\Doctrine\Enum\EnumAnnotation as Enum;
use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity()
 */
class Car
{
    /**
     * @Enum(class=BodyType::class)
     * @ORM\Column(type="string_enum")
     * @var BodyType
     */
    private $bodyType;

    public function __construct(BodyType $bodyType)
    {
        $this->bodyType = $bodyType;
    }

    public function getBodyType(): BodyType
    {
        return $this->bodyType;
    }
}

If you need to represent multiple values, have a look at the MultiEnums.

If the Consistence only provided the Enums, it would be enough reason for me to use it.

Use ObjectPrototype to disable magic methods

In PHP you can write to undefined object properties. If the property is not defined and you assign a value to it, it is created in runtime.

I think it is a bad idea because it can hide subtle bugs and typos. Consider the following example, where I made a several mistakes in the code, but PHP almost did not complain.

<?php
class MyClass
{
    public $foo;
}

$a = new MyClass();
$a->boo = 'bb'; // I made a typo, but PHP is fine with that

var_dump($a->foo);  // NULL
var_dump($a->boo);  // string(2) "bb"
var_dump($a->otherProperty);  // Notice:  Undefined property: MyClass::$otherProperty

If you want a more real-world example, consider this:

<?php
$finalPrice = $product->price * $customer->distountRate;

There is a typo in a property name, so the $finalPrice would be 0, because undefined property has null value which is converted to 0 and used in multiplication.

Consistence provides a straightforward way to mitigate this type of bugs. There is an ObjectPrototype class which you can extend your classes from. If you try to assign or read something from an undefined property, an exception is thrown. Calling undefined methods throws an exception too. Those exceptions are not meant to be caught, but they should be fixed directly in your code.

<?php
class MyClass extends \Consistence\ObjectPrototype
{
    public $foo;
}

$a = new MyClass();
$a->boo = 'bb'; // throws Consistence\UndefinedPropertyException

var_dump($a->foo); // NULL, but that does not matter, an exception would be thrown before
var_dump($a->boo); // throws Consistence\UndefinedPropertyException
var_dump($a->otherProperty); // throws Consistence\UndefinedPropertyException

$a->foo(); // throws Consistence\UndefinedMethodException

You're probably thinking, that using a base class for all classes is an awful code-smell!

I agree in general, but this case is different. If you consider the Consistence library to be an extension or augmentation of the standard PHP library, ObjectPrototype class is more like Object base class in Java. And nobody complains about it there.

The unseen advantage of this is that when you extend ObjectPrototype, you can't extend anything else, which is a good thing. You should be using composition as a code reuse mechanism anyway. In cases when the inheritance makes sense, you can use ObjectMixinTrait which enables the strict behaviour. Good example are the exceptions (they are objects too!):

<?php
class MyCustomException extends \Exception
{
    use \Consistence\Type\ObjectMixinTrait;
}

$exception = new MyCustomException();
$exception->foo = 'a'; // throws Consistence\UndefinedPropertyException

Speaking of exceptions, there is a PhpException which can be used as their base class. It has a shorter constructor without the mostly useless $code argument.

Strict type checking

PHP type-hints are powerful, but there are still a lot of things they can't check. You can put the detailed type info into the PHPDoc, but it is ignored at runtime. It only helps other developers and the IDE to better understand the code.

In the following example, IDE understands that the array contains int values, but PHP only checks that it is an array:

<?php
/**
 * @param int[] $data
 */
function foo(array $data)
{
    var_dump($data);
}

foo([0, 1, 2]); // OK,
foo(['0', '1', '2']); // OK
foo(1); // not OK: Argument 1 passed to foo() must be of the type array, integer given

You can use Type class to manually check that the variable contains expected type:

<?php
use Consistence\Type\Type;

/**
 * @param int[] $data
 */
function foo(array $data)
{
    Type::checkType($data, 'int[]');

    var_dump($data);
}

foo([0, 1, 2]); // OK 
foo(['0', '1', '2']); // throws Consistence\InvalidArgumentTypeException: int[] expected,  [array] given

Type::checkType() throws an exception when the type-check fails. If you want to throw the exception yourself, you can use Type::hasType($data, 'int[]') which returns boolean value.

Here are some examples what else you can use as an expected type:

  • object: useful in < PHP 7.2
  • Union types: int|string or int[]|string[]
  • Collection of objects: Product::class . '[]'
  • Array keys type: int:string[] (array of string values indexed by int keys)

Consistent array manipulation functions

Standard PHP functions for array manipulation aren't very consistent or strict:

  • most of them are not using strict comparison - they do automatic type conversion
  • most of them do not accept callbacks to create more complicated logic
  • some accept the source array as first parameter, some as a second parameter

Consistence provides several array manipulation functions in the ArrayType namespace. Let's have a look at the examples.

In the first example you can see how the implicit type conversion in in_array function can lead to unexpected results:

<?php
use Consistence\Type\ArrayType\ArrayType;

$data = ['1', '2'];

// automatic type conversion
in_array('1', $data); // bool(true)
in_array(1, $data); // bool(true) <- unexpected result!
in_array(true, $data); // bool(true) <- unexpected result!

// strict flag set to true
in_array('1', $data, true); // bool(true)
in_array(1, $data, true); // bool(false) <- works as expected
in_array(true, $data, true); // bool(false) <- works as expected

// ArrayType::containsValue() works as expected by default
ArrayType::containsValue($data, '1'); // bool(true)
ArrayType::containsValue($data, 1);  // bool(false)
ArrayType::containsValue($data, true);  // bool(false)

In this case you can get away with just making sure to always add true as a third parameter.

The code gets more complicated when you need more complex logic, e.g. you want to check if the array contains a value larger than 3. You can iterate through the array and determine if some value matches the condition:

<?php
$data = [1, 2, 3, 4];

$result = false;
foreach ($data as $value) {
    if ($value > 3) {
        $result = true;
        break;
    }
}
var_dump($result); // bool(true)

Consistence provides more succinct way of doing it with containsValueByValueCallback(), where you only need to write the actual business logic and not the repetitive boilerplate code:

<?php
use Consistence\Type\ArrayType\ArrayType;

$data = [1, 2, 3, 4];

$result = ArrayType::containsValueByValueCallback($data, function (int $value) {
    return $value > 3;
});

var_dump($result); // bool(true);

I often use array filtering by callback:

<?php
use Consistence\Type\ArrayType\ArrayType;

$data = [1, 2, 3, 4];

$result = ArrayType::filterValuesByCallback($data, function (int $value): bool {
    return $value > 2;
});
var_dump($result); // [3, 4]

And mapping values by callback:

<?php
use Consistence\Type\ArrayType\ArrayType;

$data = [1, 2, 3, 4];

// map values using callback
$result = ArrayType::mapValuesByCallback($data, function (int $value) {
    return $value * 2;
});
var_dump($result); // [2, 4, 6, 8]

Sometimes it may be convenient to use filterByCallback() and mapByCallback() that pass both key and value to the callback function (they use the KeyValuePair value object internally).

Did you know, that array_unique() is always comparing loosely? Therefore, I prefer to use strict ArrayType::uniqueValues():

<?php
use Consistence\Type\ArrayType\ArrayType;

$data = [1, '1', true];

var_dump(array_unique($data)); // ['1']
var_dump(ArrayType::uniqueValues($data)); // [1, '1', true]

Last thing I want to show you regarding the arrays is the find/get convention. If the method name starts with find (e.g. findValue()), it can either return the value or null. But if the method name starts with get (e.g. getValue()), it either returns the value or throws an exception.

<?php
use Consistence\Type\ArrayType\ArrayType;

$data = [1, 2, 3, 4];

// we want to get a value at key

ArrayType::findValue($data, 3); // int(4)
ArrayType::findValue($data, 5); // null

ArrayType::getValue($data, 3); // int(4)
ArrayType::getValue($data, 5); // throws ElementDoesNotExistException

And there is more, have a look at the available methods for yourself.

Regex

This chapter is going to be a short one. Consistence provides a preg_match wrapper with more sensible API and exceptions error handling:

<?php
use Consistence\RegExp\RegExp;

// you can either check if the string matches the pattern
RegExp::matches('abc', '/bc+/'); // bool(true)

// or get the matches back
$matches = RegExp::match('abcde', '/[b-d]+/');
var_dump($matches); // ['bcd']

PHPStan integration

There is a static analysis tool called PHPStan (you can read more about it in Ondřej's blogpost.

I have created PHPStan rules for the Consistence library. There is one which checks that the class extends ObjectPrototype or uses ObjectMixinTrait. And second which checks that you are using safer Consistence array manipulation functions instead of the plain native PHP ones.

Conclusion

In the article I've described the most interesting parts of the Consistence library. My favourite are enums and strict types everywhere.

If you are not using the Consistence library yet, give it a try!

]]>
<![CDATA[Málaga - co vidět a kam na výlety? Podruhé.]]> 2018-01-27T00:00:00+00:00 https://blog.martinhujer.cz/malaga-podruhe/ Letos v lednu (12. - 26.1.) jsem znovu vyrazil do Málagy za teplem. Našel jsem spoustu dalších zajímavých věcí, které stojí za to navštívit. Navazuji na předchozí článek o Málaze, takže si určitě pročtěte i ten.

Noční Málaga

Doprava

  • Uber v Málaze nefunguje, ale můžete místo něj použít Cabify.

  • Ve městě jezdí spoustu autobusů, spoje jdou vyhledávat v Google Maps. Nejpohodlnější je koupit si kartu na autobus (€1.7) a dobít si 10 jízdami za €8.30. Kartu jsem kupoval v prodejně v centru.

  • Teoreticky by na tu kartu na autobus mělo jít za €5 aktivovat možnost půjčování kol Malagabici. Nedá se to vyřešit v té prodejně v centru (kde jsem kupoval kartu), ale je potřeba dojít do kanceláře na Estación de María Zambrano. Jo a prý tam jsou asi jen do 15 h (nemám vyzkoušeno).

  • Z letiště i zpátky na letiště jsem jel vlakem, lístek stojí 1.8€. Zpátky jsem letěl v 7:00 ráno s Ryanairem a v pohodě stačilo jet vlakem v 5:20. Pokud byste chtěli větší rezervu, tak bych doporučoval to Cabify.

Co navštívit

Enflish Cemetery

  • Museo de Málaga - parádní muzeum. V prvním patře umění (vynechal jsem), v druhém patře archeologie (super). Vstup zdarma, zavřeno v pondělí.

  • Parque de Málaga - park v centru, víceméně je to botanická zahrada s fontánkami.

  • Parque del Oeste - obrovský park v Huelinu, je v něm obrovské jezírko s fontánou a želvami, palmy, papoušci, pštrosi a tak.

Parque del Oeste

  • Plaza de toros de La Malagueta - býčí aréna, myslím že se tam něco děje jen v srpnu. Zvenku to moc zábavné není. Ale je na ní super výhled shora. Viz další tip.

Malagueta

  • Mirador de Gibralfaro - na tuhle vyhlídku narazíte cestou na Castillo de Gibralfaro. Je z ní super výhled na město, moře i arénu. Zajímavost je, že většina lidí, co tam dorazí, se nejdříve otočí zády a fotí selfie místo toho, aby se koukali. Z vyhlídky kromě přímé cesty na hrad vede i trošku okružní turistická, odkud je ještě lepší výhled na Malaguetu než z té vyhlídky. A cestu na hrad to prodlouží jen o pár set metrů. Tady místo Google Maps doporučuji offline Mapy.cz, kde je zanesená i tahle turistická trasa.

  • Mirador de Alcazaba - vyhlídka před Alcazabou. Jde se tam po schodech za vlevo za vstupem do Teatro Romano. Zadarmo.

  • Teatro Romano - římský amfiteátr. Má docela zajímavou historii, objevili ho až někdy v půlce 20. století, když dělali terénní práce u dostavěného Casa de Cultura. Ten nakonec zbourali (v roce 1995), protože zjistili, že kus toho amfiteátru je pod ním. A Teatro Romano otevřeli k prohlídkám až v roce 2011.

  • Alcazaba - arabská pevnost, hezky zachovalá. Vstupné myslím 2.5€.

  • Mercado de Huelin - trh s ovocem, zeleninou, masem, rybami a mořskými plody. Typicky tam chodí jen místní.

  • La Taberna del Pintxo - tapas bar, kde hlavní roli hrají "Pintxos" (čti pinčos). Jsou to vlastně obložené chlebíčky, ale hodně vymazlené. A mají "párátko". Funguje to tak, že si sami chodíte na bar a vybíráte si z nabídky chlazených. A zároveň nosí z kuchyně tácy s teplými pintxos, prochází mezi stoly a pokud chcete, tak si nějaké vezmete. A při placení vám spočítají, kolik máte "párátek". Jo a mají tam na výběr i minidortíky.

  • Santa Canela Café-Crepería - výborná hipster kavárna ve centru. Kromě standardních espressových káv umí i různé filtrované (Chemex, V60, aeropress). A mají v nabídce i různé druhy kávy (zrnek).

Kavárna Santa Canela

  • El Último Mono Juice & Coffee - dobrá káva v centru. Nabízejí i smoothie apod.

  • La Esperanza de los Ascurra - jedna z mnoha restaurací. Tuhle doporučila Airbnb hostitelka z bytu, kde bydlela ségra s partou, když přijeli na víkend do Málagy. Mají fajn nabídku mořských plodů (třeba chobotnici - pulpo). Takže pokud stejně jako já máte problém si vybrat kam jít, tak můžete třeba sem.

  • Café Club Carambuco - fajn kavárna v Huelinu. Mají dobrou kávu, zapečené bagety a taky různé dortíky, byl jsem tam několikrát.

Café Club Carumbuco

  • Desembocadura del Guadalhorce - epická přírodní rezervace s mokřady. Mají tam dokonce pozorovatelny na sledování ptáků. Za mě jedna z top věcí v Málaze. Akorát to je trochu daleko a cestou si trochu zajdete, protože tam kde by se to hodilo, není most. Opět doporučuju Mapy.cz, kde jsou vyznačené i jednotlivé pozorovatelny. Nejlepší byla Observatorio Laguna Grande.

Výhled na lagunu v Desembocadura del Guadalhorce

  • Monte San Antón - baví mě najít nějaký kopec a vylézt na něj. Tady jsem našel jeden, na který se dá docela hezky dojít, je to jen 500 výškových metrů. Dojel jsem autobusem dole pod kopec a vyšlápnul si to nahoru. Část cesty je skrz hodně pěknou vilovou čtvrť. Nahoru a dolů mi to zabralo 3 h včetně půlhodinové svačiny a rozhlížení se nahoře. Cestou se jde skrz hezkou vilovou čtvrť. Prý je to top místo, kde se dá v Málaze bydlet, domy stojí od milionu eur výš. Záznam trasy na Wikiloc. (na fotce je výhled na Málagu)

Výhled na Málagu ze San Antón

  • Restaurante Hermanos Muñoz - když jsem sešel dolů z kopce, tak jsem dostal chuť dát si něco dobrého. Vybral jsem tuhle restauraci a bylo to super. Měl jsem rosadu, což je nějaká ryba. A hlavně jsem zkusil espeto de sardinas, což jsou sardinky pečené na ohni napíchnuté na tyčce. Jí se tak, že oloupete maso z obou stran páteře (jí se i ta opečená kůže) a necháte hlavu, ocas a páteř.

Sardinky - before

Sardinky - after

  • Chiringuito je obecný název pro restauraci/stánek s jídly z ryb a mořských plodů u pláže. Ty sardinky typicky mají ve všech.

  • Merendero Casa Jose - chiringuito, kolem kterého jsem šel nekolikrát, takže jsem si tam poslední den zašel na oběd. Měl jsem grilované krevety a pak ještě sardinky a bylo to moc dobré. A domluvíte se tam i anglicky (já tedy mluvil španelsky, ale pak přišli nějací turisti a jeden číšník si to anglicky dával dost dobře).

Krevety v Merendero Casa Jose

  • Primark - naschvál jsem si sebou vezl méně triček a radši jsem si koupil čtyři jednobarevná bavlněná v Primarku po 2€ za kus.

  • Decathlon - stejně tak jsem si sebou nebral tepláky na doma a koupil jsem si je tady v Decathlonu. Plánoval jsem si totiž stejně pořídit nové a takhle je povezu jen jednu cestu. Jo a funguje tu Decathlon kartička z českého Decathlonu (díky Portmonka).

  • Informační centrum v centru - doporučuji si dojít pro mapu, kde jsou vyznačené různé památky, případně si nechat něco doporučit. Ale s Google Maps si klidně vystačíte.

Zajímavosti

  • od 22 h do 8 h se nesmí prodávat alkohol jinde než v restauracích a barech. Takže by vám večerce neměli prodat láhev tvrdého. Neměli by.

  • Pokud budete v Málaze poprvé, tak můžete vyzkoušet nějakou free guided tour. Obecně to funguje tak, že si nějakou najdete, zúčastníte se a pak jim něco zaplatíte podle toho, jak jste byli spokojení. (nemám vyzkoušeno)

  • Jedno odpoledne se ze slunečného dne během chvíle udělala hustá mlha. Hledal jsem a říká se tomu mlha Taró.

  • Výběry z většiny bankomatů stojí kolem 2€ navíc se zahraniční kartou (i s Revolut kartou). Ale kupodivu Unicaja je má (zatím) zdarma, takže hledejte tu.

]]>
<![CDATA[Keep your YAML files sorted with YAML sort checker]]> 2018-01-17T00:00:00+00:00 https://blog.martinhujer.cz/yaml-sort-checker/ Last year I've created a PHP tool YAML file sort checker that checks that YAML files in project are sorted alphabetically.

Why should you sort everything alphabetically?

You can prevent unnecessary merge conflicts if you keep everything sorted. You should sort not only YAML files, but also composer.json (require, require-dev and scripts sections), use in PHP classes and any PHP array where order is not significant.

Typical situation is when two developers register a new service in services.yml. If they both add it to the end, it will inevitably lead to a merge conflict. However, when the services are alphabetically sorted, the probability of merge conflict is much lower, because the services will be probably added to different places and therefore won't clash.

(This specific example got better with new DI improvements in recent Symfony versions, where you don't need to register that many services manually)

Tip: You can use AlphabeticallySortedUses sniff from Slevomat Coding Standard to check that use in PHP class are sorted.

Installation

YAML file sort checker is installed through Composer:

composer require --dev mhujer/yaml-sort-checker

Configuration

You have to create a configuration file yaml-sort-checker.yml in the project root directory. Then list all files that should be checked in it.

The initial config may look like this:

files:
    app/config/services.yml:
        depth: 2

    yaml-sort-checker.yml:

It checks services.yml and itself. The services.yml will be validated only two levels deep.

Sometimes you may want to exclude some keys from validation. It can be accomplished by using excludedKeys option. You can see how the exclusion works in the example bellow:

files:
    app/config/config_prod.yml:
        excludedKeys:
            monolog:
                handlers:
                    main:
                        - type
                    nested:
                        - type

    app/config/config_test.yml:
        excludedKeys:
            0: imports

Run the checker

After you have created a configuration file, you can run the checker:

vendor/bin/yaml-sort-checker

PHPStorm integration

It is possible to integrate YAML sort checker with PHPStorm using File Watchers. It is described in the project README on github so I won't duplicated it here.

Conclusion

It is a good practice to keep most of the things sorted alphabetically to prevent merge conflicts. However, it can be a tedious task to do manually. Luckilly the YAML files can be automatically checked with YAML file sort checker.

]]>
<![CDATA[Have you tried Composer Scripts? You may not need Phing.]]> 2018-01-14T00:00:00+00:00 https://blog.martinhujer.cz/have-you-tried-composer-scripts/ Phing is a great tool (I'm using it as well), but in this article, I want to show you that some projects may not need it. Composer contains a powerful feature called "Scripts", which can be used to create a simple build script.

If you haven't read it yet, I suggest that you read my article 17 Tips for Using Composer Efficiently before reading this one.

Creating a build script for launching PHP_CodeSniffer

Let's say that you have installed PHP_CodeSniffer and you run it with this command:

vendor/bin/phpcs --standard=PSR2 src

You probably want your colleagues and CI server to run it with the same parameters. To do so, you need to store it somewhere. You can either create a build.xml for Phing or put it in a bash script (and batch file to cover Windows). Or you can leverage the power of Composer scripts.

Put the command to the composer.json file with all its parameters:

  "scripts": {
      "phpcs": "phpcs --standard=PSR2 src"
  }

And run it this way:

# either explicitly:
composer run-script phpcs

# or via shortcut:
composer phpcs

Tip: Use alias for running Composer

If you are launching Composer by typing composer (or even php composer.phar) every time, you may want to save time by creating an alias for it.

On Windows, you need to create a .cmd file in a directory which is in the system PATH. I've created c:\dev\php\x.cmd with this content (%* passes through all the parameters):

php c:\devweb\php\composer.phar %*

On Linux, you can add an alias to ~/.bashrc:

alias x="composer"

Now you can run Composer just by typing x and a command (e.g. x phpcs).

Tip: Don't type whole Composer command name

Because Composer CLI is powered by Symfony Console, you can save some characters on unambiguous commands. Instead of writing composer update, it is enough to write composer up (or only x up if you also applied the previous tip)

Creating more complex build script

Let's start with an example:

  "scripts": {
      "ci": [
          "@phpcs",
          "@test"
      ],
      "phpcs": "phpcs --standard=PSR2 src",
      "test": "phpunit"
  }

I've added a new script called test which just launches PHPUnit with default configuration.

The ci script is more interesting. It is not an actual script, but a meta-script that references several other scripts. The referenced scripts are prefixed by @. This way, you can create more complex scripts without duplication.

Launching Composer or PHP from scripts

You can use the @composer and @php commands to launch the same Composer or PHP executable that is running the script.

For example you may want to validate the composer.json file during CI build:

  "scripts": {
      "ci": [
          "@composer validate --no-check-all --strict",
          ...
      ]
  }

Or you want to use YAML validation that is available as a Symfony Console command:

"scripts": {
    "yamllint": "@php bin/console lint:yaml app"
}

Don't forget to document the custom scripts

You can use the scripts-descriptions section to document what custom scripts do:

"scripts-descriptions": {
    "phpcs": "Checks that the application code conforms to coding standard",
    "test": "Launches the preconfigured PHPUnit"
}

Configure timeout for long-running scripts

If you have some long-running scripts, you should configure the process timeout. It defaults to 300 which means that Composer will terminate the script after 300s. You can either set a specific time limit in seconds, or 0 for unlimited.

Timeout can be configured in the ENV variable COMPOSER_PROCESS_TIMEOUT:

export COMPOSER_PROCESS_TIMEOUT=600

Or by adding --timeout=0 argument when running the script:

composer phpunit --timeout=3600

Or in config section of composer.json:

"config": {
    "process-timeout": 0
}

Tips for the Scripts:

  1. You can use composer run-script --list to list custom scripts.

  2. Be careful not to create a script with a name conflicting with the existing Composer command. Composer throws a warning on every run when such a script is present in composer.json.

  3. You don't have to update composer.lock when adding or changing the scripts, because they are not included in composer.lock at all.

  4. You can even call PHP callbacks from scripts (Static methods in classes autoloadable by Composer). But I don't recommend using them for build scripts because potential migration to other build system would be hard.

When should I switch to Phing?

Composer Scripts are great for simple build scripts. But it is important to recognize the moment when the build script is so complex, that a dedicated build tool would do better.

As a rule of thumb, you shouldn't do any files / directories manipulation in Composer scripts (as it would be hard to do it Linux/Windows compatible) and switch to Phing instead.

Conclusion

Composer scripts are a lightweight tool to create build scripts. However, it is important to know when to switch to a dedicated tool such as Phing.

Do you like them?

]]>
<![CDATA[17 Tips for Using Composer Efficiently]]> 2018-01-05T00:00:00+00:00 https://blog.martinhujer.cz/17-tips-for-using-composer-efficiently/ Although most PHP developers know how to use Composer, not all of them are using it efficiently or in a best possible way. So I decided to summarize things which are important for my everyday workflow.

The philosophy of most of the tips is "Play it safe", which means that if there are more ways how to handle something, I would use the approach which is least error-prone.

Tip #1: Read the documentation

I really mean it. The documentation is great and a few hours of reading it will save you more time in the long run. You would be surprised how many things Composer can do.

Tip #2: Be aware of differences between a "project" and a "library"

It's important to know, whether you are creating a "project" or a "library". Each of them requires separate set of practices.

A library is a reusable package, that you would add as a dependency - such as symfony/symfony, doctrine/orm or elasticsearch/elasticsearch.

A project is typically an application, that depends on several libraries. It is usually not reusable (no other projects would require it as a dependency). Typical example is an ecommerce website, customer support system etc.

I will distinguish between library and a project in the tips bellow.

Tip #3: Use specific dependencies' versions for applications

If you are creating an application, you should use the most specific version to define the dependency. If you need to parse YAML files, you should specify the dependency like this "symfony/yaml": "4.0.2".

Even if the library follows Semantic Versioning, there may be backwards-compatibility breaks in the minor and patch versions. For example, if you are using "symfony/symfony": "^3.1", there may be something deprecated in 3.2 which may break your application tests. Or there may be a bug fixed in PHP_CodeSniffer and it would detect new formatting issues in your code, which again may lead to a broken build.

The update of dependencies should be deliberate, not accidental. One of the tips bellow discusses it in greater detail.

It may sound as an overkill, but it will prevent your co-workers from accidentally updating all dependencies when adding a new library to project (which you may miss during Code Review).

Tip #4: Use version ranges for libraries dependencies

If you are creating a library, you should define the broadest version range possible. If you create a library that uses symfony/yaml library for YAML parsing, you should require it like this:

"symfony/yaml": "^3.0 || ^4.0"

It means that your library can utilize symfony/yaml from any Symfony 3.x or 4.x versions. It is important, because this constraint is passed to the application that uses your library.

In case there are two libraries with conflicting requirements, e.g. one requires ~3.1.0 and other requires ~3.2.0, the installation would fail.

Tip #5: You should commit composer.lock to git in applications

If you are creating a project, you definitely want to commit composer.lock to git. This ensures that everyone - you, your co-workers, your CI server and your production server - is running the application with the same dependencies versions.

At first glance, it may sound superfluous - you are already using a specific version in the constraint, as mentioned in the tip #3. But no, there are also the dependencies of your dependencies which are not bound by these constraints (e.g. symfony/console depends on symfony/polyfill-mbstring). So without committing the composer.lock, you won't get the exact same set of dependencies.

Tip #6: Put composer.lock into .gitignore in libraries

If you are creating a library (let's call it acme/my-library), you should not commit a composer.lock file. It does not have any effect on the projects that are using your library.

Imagine that the acme/my-library uses monolog/monolog as a dependency. If you have committed a composer.lock, everyone who is developing the acme/my-library would be using an older version of Monolog. But when the library is finished, and you use it in a real project, a newer version of Monolog may be installed, and it may not be compatible with the library. But you didn't notice it before, because of the composer.lock!

It is best to put composer.lock into your .gitignore so you won't commit it accidentally.

If you want to make sure that the library is compatible with different versions of its dependencies, read the next tip!

Tip #7: Run Travis CI builds with different versions of dependencies

This tip applies only to libraries (because you use specific versions for applications).

If you are building an open-source library, you are probably using Travis CI for running its builds.

By default, Composer installs the latest possible versions of dependencies which are allowed by the constraints in composer.json. It means that for the dependency constraint ^3.0 || ^4.0, the build would always use the latest version of the v4 release. As the 3.0 is never tested, the library may not be compatible with it and that would make your users sad.

Luckily, Composer provides a switch to install the lowest possible versions of dependencies --prefer-lowest (should be used with --prefer-stable to prevent installation of non-stable versions).

Updated .travis.yml configuration may look like this:

language: php

php:
  - 7.1
  - 7.2

env:
  matrix:
    - PREFER_LOWEST="--prefer-lowest --prefer-stable"
    - PREFER_LOWEST=""

before_script:
  - composer update $PREFER_LOWEST

script:
  - composer ci

See it live in my mhujer/fio-api-php library and the build matrix on Travis CI

Even though this solution would catch most of the incompatibilities, remember that there are many combinations of dependencies between lowest and latest versions. And they may be incompatible together.

Tip #8: Sort packages in require and require-dev by name

It is a good practice to keep packages in require and require-dev sorted by name. It can prevent unnecessary merge conflicts when rebasing a branch. Because if you have added a package to the end of the list in two branches, there would be a merge conflict every time.

It is a tedious task to do manually, so it is best to configure it in composer.json:

{
...
    "config": {
        "sort-packages": true
    },
…
}

Next time, you require a new package, it will be added to a proper place (and not to the end).

Tip #9: Do not attempt to merge composer.lock when rebasing or merging

If you add a new dependency to composer.json (and composer.lock) and before your branch is merged, there is another dependency added in master, you need to rebase your branch. And you will get a merge-conflict in composer.lock.

You should never try to resolve this conflict manually, because the composer.lock file contains a hash of dependencies defined in composer.json. So even if you resolve the conflict, the resulting lock file would be incorrect.

Best thing to do is to create .gitattributes in the project root with the following line, which means that the git won't even attempt to merge the composer.lock:

/composer.lock -merge

You can remedy this issue by using short-lived feature branches as suggested in Trunk Based Development (you should be doing this anyway). When you have a short-lived branch, which is merged promptly, the risk of merge conflict in composer.lock is minimal. You may even create a branch just for adding a dependency and merge it right away.

But what to do, if you encounter a merge conflict in composer.lock when rebasing? Resolve it with the version from master, so you will have changes only in composer.json (the newly added package). And then run composer update --lock, which will to update the composer.lock file with changes from composer.json. Now you can stage the updated composer.lock and continue with the rebase.

Tip #10: Know the difference between require and require-dev

It is important to be aware of the difference between require and require-dev blocks.

Packages which are required to run the application or library should be defined in require (e.g. Symfony, Doctrine, Twig, Guzzle, …). If you are creating a library, be careful about what you put to require. Because each dependency from this section is also a dependency of the application, which uses the library.

Packages necessary for developing the application (or library) should be defined in require-dev (e.g. PHPUnit, PHP_CodeSniffer, PHPStan).

Tip #11: Update dependencies safely

I guess we can agree on the fact that dependencies should be updated regularly. What I want to discuss here is that dependencies updating should be explicit and deliberate, not done just by-the-way with some other work. If you refactor something and at the same time update some library, you can't easily tell if the app was broken by the refactoring or by the update.

You can use composer outdated command to see what dependencies can be updated. It is a good idea to include --direct (or -D) switch to list only dependencies specified in composer.json. There is also a -m switch to list only minor version updates.

For each outdated dependency follow these steps:

  1. Create a new branch
  2. Update the dependency version in composer.json to the latest one
  3. Run composer update phpunit/phpunit --with-dependencies (replace phpunit/phpunit with the library you are updating)
  4. Check the CHANGELOG in the library repository on Github to see if there are any breaking changes. If so, update the application
  5. Test the application locally (If you are using Symfony, you can find deprecation warnings in the Debug Bar)
  6. Commit the changes (composer.json, composer.lock and anything else what was necessary for new version to work)
  7. Wait for the CI build to finish
  8. Merge and deploy

Sometimes it makes sense to update more dependencies at once, e.g. when you are updating Doctrine or Symfony. In this case you can list them all in update command:

composer update symfony/symfony symfony/monolog-bundle --with-dependencies

Or you can use a wildcard to update all dependencies from a specific namespace:

composer update symfony/* --with-dependencies

I know that this all sounds tedious, but you will probably update dependencies just occasionally, so it is worth the extra safety.

One shortcut which is acceptable to make is to update all require-dev dependencies at once (if they do not require changes in the code, otherwise I would suggest using separate branches for easier code review).

Tip #12: You can define other types of dependencies in composer.json

Apart from defining libraries as dependencies, you can also define other things there.

You can define, which PHP versions your application/library supports:

"require": {
    "php": "7.1.* || 7.2.*",
},

You can also define which extensions are required for the application/library. It is super-useful when you are trying to dockerize your application or your new colleague is setting-up the application for the first time.

"require": {
    "ext-mbstring": "*",
    "ext-pdo_mysql": "*",
},

(You should use * for the extensions version as they may be a bit inconsistent).

Tip #13: Validate the composer.json during the CI build

composer.json and composer.lock should be always kept in sync. Therefore, it is a good idea to have an automatic check for it. Just add this as a part of you build script and it will ensure that composer.lock is in sync with composer.json:

composer validate --no-check-all --strict

Tip #14: Use a Composer plugin in PHPStorm

There is a composer.json plugin for PHPStorm. It adds autocompletion and some validations when changing composer.json manually.

If you are using other IDE (or just a code editor), you can setup validation against its JSON schema.

Tip #15: Specify the production PHP version in composer.json

If you are like me and you are sometimes running pre-released PHP versions locally, you are in risk of updating the dependencies to a version that won't work in production. Right now, I'm using PHP 7.2.0 which means, that I can install libraries, that would not work on 7.1. As the production is running 7.1, the installation would fail there.

But no need to worry, there is an easy way out. Just specify the production PHP version in config section of composer.json:

"config": {
    "platform": {
        "php": "7.1"
    }
}

Don't confuse it with require section, which behaves differently. Your application may be able to run on 7.1 or 7.2 and at the same time specify 7.1 as a platform (which means that the dependencies will be always updated to a version compatible with 7.1):

"require": {
    "php": "7.1.* || 7.2.*"
},
"config": {
    "platform": {
        "php": "7.1"
    }
},

Tip #16: Using private packages from self-hosted Gitlab

It is recommended to use vcs as a repository type and the Composer should determine the proper way of fetching the packages. For example, if you are adding a fork from Github, it would use its API to download the .zip file instead of cloning the whole repository.

But it is more complicated for a private Gitlab installation. If you use vcs as a repository type, Composer will detect that it is a Gitlab installation would try to download the package using the API (which requires an API key. I didn't want to set it up, so I settled for this setup (which uses SSH for cloning):

First specify the repository with the type git:

"repositories": [
    {
        "type": "git",
        "url": "git@gitlab.mycompany.cz:package-namespace/package-name.git"
    }
]

Then use the package as you would have normally:

"require": {
    "package-namespace/package-name": "1.0.0"
}

Tip #17: How to temporarily use a branch with bugfix from fork

If you find a bug in some public library and you fix it in your fork on Github, you need to install the library from this repository instead of the official one (until the bugfix is merged and fixed version is released).

It can be done easily with inline aliasing:

{
    "repositories": [
        {
            "type": "vcs",
            "url": "https://github.com/you/monolog"
        }
    ],
    "require": {
        "symfony/monolog-bundle": "2.0",
        "monolog/monolog": "dev-bugfix as 1.0.x-dev"
    }
}

You can test the bugfix locally before pushing it by using path as a repository type.

Update 2018-01-08:

After publishing the article, I got suggestions for several more tips. So here they are:

Tip #18: Install prestissimo to speed up package installation

There is a Composer plugin hirak/prestissimo which speeds up dependencies installation by downloading them in parallel.

And the best thing? You only need to install it once, globally and it will work automatically for all projects:

composer global require hirak/prestissimo

Tip #19: Test your version constraints if you are not sure

Writing correct version constraints may sometimes be tricky even after reading the documentation.

Luckily, there is a Packagist Semver Checker where you can check which versions match the specified constraint. Instead of only analysing the version constraint, it downloads the data from Packagist to display the actual released versions.

See the result for symfony/symfony:^3.1.

Tip #20: Use authoritative class map in production

You should generate authoritative class map in production. It will speed-up class loading by including everything in class-map and skipping any filesystem checks.

You can do it by running this as a part of your production build:

composer dump-autoload --classmap-authoritative

Tip #21: Configure autoload-dev for tests

You don't want to include test files in production class map (because of the file size and memory). It can be done by configuring the autoload-dev (similarly to autoload):

"autoload": {
    "psr-4": {
        "Acme\\": "src/"
    }
},
"autoload-dev": {
    "psr-4": {
        "Acme\\": "tests/"
    }
},

Tip #22: Try Composer scripts

Composer scripts are a lightweight tool to create build scripts. I have written a separate article about them.

Conclusion

If you disagree with some of the tips, I would be happy if you can describe why in the comments (don't forget to put the tip number there).

]]>