DFBG Złoty półmaraton 2024

Złoty Półmaraton na DFBG miejsce 106 open na 967 startujących. Start 11:00. Czas 2:14:29 waga 77,9 kg. Dystans 20,4 km 872 m up.

Przygotowanie – 2 tygodnie przed Grecja i 2x Skopos, tydzień przed 33× Mała Sobótka poniedziałek crossfit, wtorek luźne bieganie z 1km @4:0, czwartek lekkie krótkie bieganie w upale.

Fizycznie – na zbiegu z Borówkowej gdy przyspieszyłem do około 4:30 to po 2 km zacząłem czuć lekkie skórcze w łydkach płaszczkowatych przyśrodkowych obyło się bez zatrzymania jak na Jaworniku. Nie wiem czy przez to zwolniłem. Na zbiegu czasy 4:30-5:05 wolniejsze niż na zbiegu z Jawornika ale jednak teren też trudniejszy był. Pod koniec czułem też lekkie przeciążenie w okolicach prawego achillesa.

Dzień, dwa po biegu czuję wyjątkowo duże zmęczenie w dolnej części łydki w okolicach achillesa.

Żywienie – bardzo dobrze, wieczorem miska makaronu jako dodatek do standardowego jadła. Rano prawie całą miska makaronu + 4 kanapki chleba, pobótka 7:15. W aucie jeszcze ciut makaronu, przed biegiem 1 daktyl, kilka łyków kawy i żel na 15 min przed startem. W trakcie biegu planowo żel po Trojaku na podbiegu pod Karpiak oraz na podejściu pod Borówkową. Żele długo mielone. Zmuszałem się do picia trochę więcej niż w Jaworniku.

Warunki – bardzo ciepło ale nie czułem tego negatywnie. Za żywieniowym na Przełęczy Lądeckiej zdjąłem koszulkę. Słońce głównie za chmurami, czasem się przebijało.

Trasa – było trochę wąskich ścieżynek – zbieg z Karpniaka oraz cała bardzo wąska ścieżka graniczna. Zbieg z Borówkowej 2 pasmową drogą, chwilę asfalt, ogólnie prosty ale trudniejszy niż z Jawornika.

Sprzęt – wziąłem stare Brooks Catamount 1 i spisały się super.

Przebieg – PacePro i RMT rozpisałem na 2:15 co wyceniło na 506 punktów RMT. Trojak zrobiłem przed czasem bo planowałem mocny start żeby zostawić za sobą większość mocno rekreacyjnej stawki. Na Karpniak głównie bieg, na zbiegu z Karpniaka był chyba jedyny moment gdzie troszeczkę blokowała mnie babeczka ale to niewielka strata. Na Borówkową już głównie szedłem, z przełęczy Lądeckiej miałem 270m up – chyba powinienem się tam bardziej przemóc i więcej biec co dobitnie sugeruje najniższy GAP kilometrowy 6:05 i 6:16 ale jakoś nie mogłem się przemóc. Miałem też wyliczone, że na zbiegu zyskam 6 min w stosunku do PacePro i zakończę z zakładanym czasem. Tak też się stało. Tutaj mimo wolniejszego zbiegu niż z Jawornika udało się odrobić z nawiązką, w Jaworniku nie.

Średnie tempo 6:36 /km, średni GAP 5:30 /km nie urywa w porównaniu z Jawornikiem ale 270m up robi swoje.

W RMT na punkcie #2 z rozpiski przewaga 5 minut, zarówno pod Trojak jak Karpniak głównie biegłem, na Borówkowej podobnie i straciłęm przewagę na zbiegu o założyłem w RTM zbyt optymistyczny czas. W PacePro odwrotnie, tam traciłem na podbiegach bo tam algorytm nadaje zbyt duże tempo.

Wniosek: na RMT szacować wolniejsze zbiegi.

Wniosek: w momencie gdy podciągnąłem podbieg to ciężko mi już chojraczyć na zbiegach bo trafiam już do grupy mocnych ludzi również na zbiegu. Ciężko mi oszacować ilu prześcignąłem na zbiegu bo półmaraton łączył się z innymi dystansami, ale kilka na pewno tak, mnie przegoniła tylko 1 osoba. Muszę dalej ćwiczyć podbiegi żeby miniej na nich tracić, szacuję że w lepszych podbiegach mogę zyskać więcej niż w lepszych zbiegach.

Ocena – 8/10 Nie znam jeszcze wyceny RMT wyścigu, RMT aktywności wyniosło 565 ale w grupie 505 więc mam nadzieję załapać się powyżej 500. Na liście startowej byłem na 158 pozycji zakończyłem na 106 ale wiadomo, że nie wiadomo ile z listy osób biegło. Warunki były akceptowalne jak na lato. Szacunki RMT pobite dość mocno.

Wyniki DFBG 21km
aktywność w RMT
aktywność Strava

Bieg na Jawornik 2024

Bieg na Jawornik miejsce 26 open na 108 startujących. Start 11:00. Czas 1:52:07 waga 79,2 kg. Dystans 20,5 km 610 m up.

Przygotowanie – tydzień przed mocny BNP pod górkę, poniedziałek crossfit, wtorek średnie bieganie, czwartek lekkie krótkie bieganie w upale.

Fizycznie – na 14/15km po szybkim zbiegu i hopce 50m up złapał mnie skurcz w prawej łydce mięsień płaszczkowaty przyśrodkowa głowa. Musiałem na chwilę się zatrzymać i 2 sec rozciągnąć nogę. Wydaje mi się, że to przez supinację spowodowaną wciąż otwartą lewą stroną miednicy, w dalszym zbiegu starałem się bardziej pronować prawą stopę i problem nie już powrócił. Ciężko powiedzieć czy ta asekuracja wpłynęła na tempo biegu, pewnie nieznacznie tak, może ~1 min.

Kilka godzin po biegu czuję w lewej nodze ciągnące przyczepy brzuchatego.

Żywienie – dobrze, plan przedbiegowy zrealizowany, standardowo żel na 15 min przed startem a później po około 40 minut biegu na stromszym podejściu gdzie i tak przeszedłem w chód. Picie z uwagi, że organizator zapewniał kubki – łyknąłem po pół kubka na 2 punktach i raz pociągnąłem z flaska. Byłem dobrze nawodniony przed biegiem i nie czułem potrzeby pić więcej… ale, z uwagi na słońce i kosmiczne 26 stopni, może powinienem się bardziej zmusić.

Wniosek: jednak więcej pić

Jedzenie przed biegiem – dzień wcześniej po kolacji dodatkowa miska makaronu, pobudka o 7:20, standardowe 2,5 kromki kiełbasa i ser oraz miska makaronu. Na miejscu kilka daktyli, kawa, 40 min przed biegiem 2 łyżki makaronu. Zawsze obawiam się, że za mało jem i zwykle jem za dużo, tutaj chyba udało się uniknąć przeżarcia. Na początku biegu ciut chlupało w żołądku ale nie przeszkadzało.

Warunki – mega upał, o 11:00 na starcie 26 stopni i pełne słońce. Co prawda trasa w większości zacieniona ale było tez sporo odsłoniętych fragmentów i tam parzyło niemiłosiernie. Strzelam, że około 15-20% odsłoniętego było. Na około 3 km zdjąłem koszulkę co chwilowo dało ulgę.

Trasa – trasa mega prosta, w 100% szeroka dwutorówka, zero problemów z wyprzedzaniem. Ziemia, szuter, proste kamienie, może 2 km trochę zarośnięte i wyższa trawa ale nie przeszkadzało specjalnie.

Sprzęt – buty Brooks Catamount po raz kolejny (po maratonie 3xKopa) pokazały, że są do dupy. Na 9 km podbiegu zacząłem czuć lekkie boleści stóp jakby mimo sporej warstwy amortyzacji 19-25 mm mało tłumiły kamienie myślę, że przy dłuższym dystansie miałbym podobne bóle co na Kopie. Co dziwne czułem to tylko na podbiegu, na zbiegu nie. Poza tym dziwnie robią mi punkt podparcia na zewnętrznej krawędzi środka stopy, prawa obrywa bardziej. Jest to zdecydowanie do wyjaśnienia i chyba zakup innych butów. Co dziwne Brooks Catamount 1 spisywał się w obu elementach bez zarzutu, nawet teraz po kilometrażu prawie 1800 km. Reszta sprzętu gicior.

Przebieg – PacePro i RMT rozpisałem na 1:47:00 co wyceniało bieg na 501. Gdzieś do 5 km utrzymywałem zakładane tempo a nawet zrobiłem chwilowo -1 minutę. Pierwsze chwilowe przejście w chód na 5 km na dużym gradiencie, ale dosłownie kilka kroczków. Następnie kilka kilometrów bieg na 0 i 9,10,11 i pół 12 na gradiencie 10-14% zamuła i sporo chodu. Tempo 7:20 – 8:15 zaowocowało stratą ponad 6 min do docelowego czasu. Według garmina miałem 4:46 min czasu chodu.

Tego nie dało się już odrobić mimo iż PacePro na zbiegu nie zakładało kosmosu a jedynie około 4:40. Przed biegiem zakładałem, że jestem w stanie odrobić 4 minuty. Niestety na zbiegu były jeszcze 2 małe hopki oraz opisana wyżej przygoda z brzuchatym i odrobiłem tylko 1 minutę. Tempa 4:01 – 4:40 poza większą hopką gdzie wyszło 6:10. Na ostatnich 4,5 km tętno powyżej 170, miejscami 177 więc nie było z czego przyspieszyć.

Wniosek: gdy jest 80-100m przewyższeń na 1 km to nie daję radę w 100% biec.

Ocena – 8/10. Nie znam jeszcze wyceny RMT wyścigu, RMT aktywności wyniosło rekordowe 624 ale wyścigowe raczej będzie poniżej 500. Na liście startowej byłem na 42 pozycji więc niby progres ale nie wiadomo ilu biegaczy z listy ostatecznie wystartowało. Warunki pogotowie bardzo trudne więc to podnosi ocenę, gdyby było 6 stopni to pewnie dałbym ciut mniej. Szacunki RMT niektóre pobite inne nie, forma ogólna prawie idealnie weszła. Jak jak mówię, wycena raczej nie uwzględniałą takiego upału. Zobaczymy na RTM official wyścigowy.

Mimo iż nie zacząłem wolno i wcale nie byłem ustawiony na tyle to w zasadzie tylko wyprzedzałem, na ostatnim km ktoś mnie wyprzedził ale nie mam pewności czy sam go wcześniej nie łyknąłęm. Cały bieg miałem w miarę równy GAP 4:32 – 5:36 to mnie bardzo cieszy – widać, że nawet trudniejsze kmy pod górkę nie poskutkowały większym zamuleniem. Fakt, że przewyższenia nie były za wielkie ale zawsze coś.

BNJ_Polmaraton_2024 – wyniki
aktywność w RTM
aktywność Strava

30 Bieg na Ślężę 2024

Bieg na Ślężę miejsce 89 na 204 startujących, czas 41:50, waga 80,4kg. Pierwszy w karierze vertical gdzie biegnie się tylko pod górę z metą na szczycie. Bieg króciutki acz intensywny 5,10km i 530m up.

Fizycznie – dobrze, w trakcie biegu nie odczuwałem żadnych negatywnych fizycznych dolegliwości. Przed biegiem pracowałem nad spiętym brzuchatym (wewnętrzna głowa) w lewej łydce dwójką lewej nogi. Coś tam rozluźniłem ale po powrocie czuję więc do wyprostowania u fizjo.

Gdy na końcówce cisnąłem już na maksa to wydawało mi się, że blokerem nie były nogi, które jakoś nie czułem a kardio i oddech.

Żywienie – dobrze, wiele tego nie było. Standardowa kanapka o 8:00 humus + warzywa oraz miska makaronu i 1 morela. Po przyjeździe 2 figi a po rozgrzewce, 15 min przed biegiem standardowo 1 żel. Na trasę wziąłem softflask z 100ml ale nie skorzystałem, głównie pod cel uzupełnienia po biegu.

Warunki – ciepełko 19 stopni i pełnie słońce. 95% trasy w cieniu a ciepła nie odczuwałem więc raczej bez negatywnego wpływu. Na ostatnim km śliskie stały ale ogólnie warun bardzo dobry.

Przebieg – PacePro rozpisałem na 40 minut, pierwsze 1,5km do podbiegu pod Wieżyce -1:30, które planowo straciłem na podejściu, po Wieżycy gdzie nie było dużej stromizny gdzieś do 3km w okolicach 0:00, może lekki minus – to odpuszczenie widać na wykresie tętna. 3-4km gdzie gradient skoczył do 15-20% przejście w szybki chód w efekcie zjazd na +1:30. Ostatni km od skrzyżowania ze ścieżką pod skałami głownie ponownie bieg ale i tak ciut wolniej niż zakładane. Końcówkę cisnąłem już na maksa, pewnie za późno zacząłem. Ostatecznie koniec na +1:50.

Wniosek: po Wieżycy, 3km trzeba cisnąć mocniej żeby zrobić zapas na 4km, ew. wiadomo 4km biec a nie iść.

Ocena – 8/10. Podbiegi to nie jest moja mocna strona, dlatego trzeba nad nimi pracować. Ocena indywidualna RMT=608 co jest historycznie najwyższym moim osiągnięciem. Krośnice 2023=605 a najlepszy górski bieg Lhoste=551. Na pewno mogłem wcześniej przycisnąć bardziej bo dopiero w ostatnim km tętno skoczyło powyżej 170 ale się nie zmobilizowałem. Szacunki RMT trochę pobite więc wstydu nie ma. Więcej pod górkę chyba ciężko mi aktualnie wyciągnąć.

W biegu raczej wyprzedzałem niż byłem wyprzedzany, na wolnym 4 km być może słabe otoczenie biegowe być może nie mobilizowało do ekstremalnego wysiłku, a może po prostu też byłem słaby. Zmobilizowałem się na maksa dopiero od krzyżówki ze ścieżką pod skałami co było zakładane.

Maraton Opawski na Festiwalu 3xKopa 2024

Maraton Opawski OPEN 34 miejsce na 94 zawodników. Widowiskowo – świetnie trasa z pięknymi prawdziwie górskimi ścieżkami i widokami. Biegowo – dla mnie zajazd, 2.2k up to bardzo dużo jak na 41 km, trasa w wielu miejscach mocno stroma zarówno na podejściu jak i na zbiegu. W drugiej pętli mocno doskwierał upał 20+ stopni i pełne słońce. Patrząc na czasy nie tylko dla mnie drugie kółko było zabójcze. Drugie kółko ma tylko 2 km więcej i tyle samo przewyższeń co pierwsze a czas okrążenia spadł mi z 2:37h na 3:53h. Mimo takiej masakry czasowej o dziwo w generalce spadłem tylko o 4 pozycje z 30 na 34. To pokazuje, że inni też lekko nie mieli.

Fizycznie – pierwsze kółko super, drugie bardzo ciężko – sporo skurczów (przywodziciele, dwójki, brzuchate) bywało, że nawet na zbiegu musiałem się na chwilę zatrzymać. Z bólów jedynie po raz pierwszy zbite stopy i to mocno – to pewnie przez rzadkie bieganie górskie w ostatnich miesiącach. Do poprawy więcej biegania po Ślęży na początku sezonu. Mimo iż zaliczyłem już biegowo m.in 72 km i 2.6k up na Sudeckiej Żylecie to jeszcze nigdy tak się nie zniszczyłem fizycznie i emocjonalnie. Na mecie nie mogłem powstrzymać łez, że ta katorga w końcu się skończyła. Być może miałem zbyt wygórowane plany i oczekiwania. Track w zegarku miałem ustawiony na optymistyczne 5:45h ostatecznie skończyłem na 6:30. RMT szacował na 6:06h-6:11h. Moje 5:45h dało by kosmiczne 15 miejsce więc widać, że było nierealne.

Żywienie – zagadka ale raczej słabo, 2 dni przed zawodami po raz pierwszy testowałem “ładowanie węgli” czy zadziałało na plus czy na minus ciężko powiedzieć. Zaraz przed biegiem wszedł baton a na trasie tylko 3 żele, dużo izo i coli. Żeli na pewno za mało mało, na dużo krótszych dystansach wcinałem po 4-5 a teraz przez wcześniejsze łądowanie wungli chyba miałem dosyć słodkiego. Po wciągnięciu żela w ogóle nie czułem mocy. Poszło też 5 salt sticków ale na skurcze nie pomogły. Być może za mało piłem bo nie mogłem użyć planowanego bukłaka 2l gdyż zapomniałęm wziąć zamknięcia. Lecialem więc na 0,5l flasku i choć nie czułem specjalnie doskwierającego pragnienia, to podświadomie, pomiędzy punktami żywieniowymi (były 4) na pewno za bardzo oszczędzałem wodę. Do poprawy.

Warunki – pierwsza pętla fajne – 8-12 stopni, druga 20+ i pełne słońce. Na końcowym podejściu pod Biskupią Kopę w zacienionych miejscach obok trasy leżał śnieg. Najchętniej bym się w nim wytarzał, ostatecznie musiałem poprzestać na wsadzaniu go sobie na głowę, kark, pod koszulkę. Trasa w 99% sucha, w 1% na szlaku strumyk, woda i błoto praktycznie nie do ominięcia. Dużo wąskich górskich ścieżek.

Organizacja – super, punkty żywieniowe dobrze zaopatrzone i pięknie dopingujące. Na minus drobne nieporozumienie z przedwcześnie zamkniętym parkingiem i biuro zawodów daleko od startu (przepak i jedzonko).

Ocena – ciężko jednoznacznie ocenić, miejsce w 45% w 36% stawki nie urywa, dawno tak daleko w biegu się nie uplasowałem. Przechodzenie z dystansu biegu z 20-30 km na maraton zwiększa trudność nie tylko w dystansie ale też w poziomie rywali bo tu zapisują się już głównie osoby zaprawione w bojach. Ale być może to tylko wymówka ;-)

Sam festiwal jak i maraton godny polecenia. Z zastrzeżeniem, że 2 kółko daje popalić. Podobno 3 kółko jest proste i mocno biegowe.

#3xkopa #3xkopa_2024 #maraton #bieganie #bieg #run #running #pokrzywna #góryopawskie

Główne wnioski:
* na razie odpuścić ładowanie węgli
* minimum 1 żel na 1h
* więcej biegania na Ślęży, szczególnie na początku sezonu
* maraton i więcej niż 2k up to na razie bardzo dużo dla mnie

Wzorzec projektowy Decorator – elastyczne dodawanie funkcjonalności

Wzorzec dekoratora jest przydatny w wielu sytuacjach, w których chcemy elastycznie dodawać funkcjonalność do istniejących obiektów. Oto kilka przykładów problemów, do których można użyć wzorca dekoratora:

  1. Dopasowywanie funkcjonalności na etapie uruchamiania: Możemy użyć dekoratora, aby dodać lub zmienić zachowanie obiektu w zależności od określonych warunków, takich jak konfiguracja aplikacji czy uprawnienia użytkownika.
  2. Logowanie i analiza: Dekorator może zostać zastosowany do rejestrowania działań obiektu, dodając logowanie przed lub po wykonaniu konkretnej metody. Na przykład, dekorator może logować czas wykonania metody lub przekazywane argumenty.
  3. Kształtowanie danych wyjściowych: W przypadku danych wyjściowych, takich jak formatowanie danych do wyświetlenia w różnych kontekstach (np. HTML, XML, JSON), dekorator może dostosowywać wyjście w zależności od wymagań.
  4. Cacheowanie: Dekorator może być użyty do dodania mechanizmu buforowania (cache) dla wyników wywołań metod, co pozwala na uniknięcie ponownego obliczania tych samych wyników dla tych samych argumentów.
  5. Autoryzacja: Dekorator może być wykorzystany do dodania mechanizmu autoryzacji przed wykonaniem danej metody. Na przykład, dekorator może sprawdzać uprawnienia użytkownika przed wykonaniem operacji.
  6. Śledzenie stanu obiektu: Dekorator może być użyty do monitorowania i rejestrowania zmian stanu obiektu. Na przykład, możemy zaimplementować dekoratory, które rejestrują historię zmian obiektu lub powiadamiają inne komponenty o aktualizacjach stanu.
  7. Kompresja danych: Dekorator może być użyty do dynamicznego kompresowania danych wyjściowych w celu zmniejszenia rozmiaru przesyłanych danych w zależności od preferencji użytkownika lub ustawień aplikacji.

Wzorzec dekoratora jest niezwykle elastyczny i pozwala na dynamiczne dostosowywanie funkcjonalności obiektów w czasie działania programu, co jest szczególnie przydatne w sytuacjach, gdy zachowanie obiektów może się zmieniać w zależności od różnych czynników.

// Interfejs komponentu
interface Component {
    public function operation(): string;
}

// Konkretny komponent
class ConcreteComponent implements Component {
    public function operation(): string {
        return "ConcreteComponent operation";
    }
}

// Dekorator bazowy
abstract class Decorator implements Component {
    protected $component;

    public function __construct(Component $component) {
        $this->component = $component;
    }

    public function operation(): string {
        return $this->component->operation();
    }
}

// Konkretny dekorator
class ConcreteDecorator extends Decorator {
    public function operation(): string {
        return parent::operation() . " with added behavior in ConcreteDecorator";
    }
}

// Użycie
$component = new ConcreteComponent();
$decoratedComponent = new ConcreteDecorator($component);
echo $decoratedComponent->operation(); // Wyświetli: ConcreteComponent operation with added behavior in ConcreteDecorator

Wykorzystanie wzorca dekoratora w frameworku Symfony

Symfony jest jednym z najpopularniejszych frameworków PHP, który zapewnia solidną strukturę i wiele gotowych rozwiązań do tworzenia aplikacji webowych.

Wśród wielu wzorców projektowych, które można zastosować w Symfony, wzorzec dekoratora odgrywa ważną rolę, umożliwiając elastyczne dostosowywanie funkcjonalności aplikacji w czasie jej działania. Poniżej przyjrzymy się, jak można wykorzystać wzorzec dekoratora w Symfony na podstawie konkretnych przykładów.

Dekorowanie usług Symfony

W Symfony usługi są kluczowym elementem, który umożliwia organizację kodu i zarządzanie zależnościami. Za pomocą wzorca dekoratora możemy łatwo modyfikować zachowanie usług bez ingerencji w ich kod. Przykładowo, załóżmy, że mamy usługę do kompresji danych, ale chcielibyśmy dodać dodatkową funkcjonalność, taką jak logowanie każdego żądania kompresji. Możemy to osiągnąć poprzez utworzenie dekoratora dla tej usługi:

use Symfony\Component\DependencyInjection\Argument\WrappedIterator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;

// Dekorator logujący kompresję danych
class CompressionLoggingDecorator implements DataCompressionInterface
{
    private $compressionService;
    private $logger;

    public function __construct(DataCompressionInterface $compressionService, LoggerInterface $logger)
    {
        $this->compressionService = $compressionService;
        $this->logger = $logger;
    }

    public function compress($data)
    {
        $compressedData = $this->compressionService->compress($data);
        $this->logger->info('Data compressed successfully');
        return $compressedData;
    }
}

// Konfiguracja kontenera usług Symfony
$containerBuilder = new ContainerBuilder();
$containerBuilder->register('compression_service', DataCompressionService::class);
$containerBuilder->register('compression_service_with_logging', CompressionLoggingDecorator::class)
    ->setDecoratedService('compression_service')
    ->addArgument(new Reference('compression_service'))
    ->addArgument(new Reference('logger'));

W powyższym przykładzie mamy usługę DataCompressionService, którą dekorujemy za pomocą CompressionLoggingDecorator, dodając logowanie do każdego wywołania kompresji danych.

Dekorowanie formularzy Symfony

Formularze w Symfony są wygodnym sposobem na obsługę danych wejściowych od użytkownika. Za pomocą wzorca dekoratora możemy modyfikować zachowanie formularzy w zależności od różnych warunków. Na przykład, możemy dodać walidację dodatkowych pól lub zmienić sposób wyświetlania formularza w zależności od uprawnień użytkownika. Poniżej znajduje się przykład dekorowania formularza:

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

// Dekorator formularza dodający pole "Uwagi"
class CommentFieldDecorator extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('comment', TextType::class, [
            'label' => 'Uwagi',
            'required' => false,
        ]);
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'data_class' => 'App\Entity\Comment',
        ]);
    }
}

// Klasa bazowa formularza
class CommentFormType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        // Budowanie formularza
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'data_class' => 'App\Entity\Comment',
        ]);
    }
}

// Użycie dekoratora do zmiany formularza
$commentForm = $this->createForm(CommentFieldDecorator::class, $comment);

W tym przykładzie dekorujemy formularz CommentFormType za pomocą CommentFieldDecorator, dodając pole „Uwagi” do istniejącego formularza.

Podsumowanie

Wzorzec dekoratora jest potężnym narzędziem, które można zastosować w Symfony do elastycznego dostosowywania funkcjonalności aplikacji bez konieczności modyfikowania oryginalnego kodu.

Dzięki zastosowaniu dekoratorów możemy łatwo rozszerzać zachowanie usług, formularzy i innych komponentów Symfony, co przyczynia się do zwiększenia modularności i elastyczności naszej aplikacji.

Wzorzec projektowy Adapter – klucz do dostosowania interfejsu do Twoich potrzeb

Wzorzec projektowy Adapter w PHP – jak go zastosować w swoim projekcie?

Zobacz jak wzorzec projektowy Adapter może Ci pomóc dostosować interfejs do potrzeb Twojego projektu w PHP. Przeczytaj nasz przewodnik i poznaj przykłady jego zastosowania w praktyce.

Adapter to wzorzec projektowy, który pozwala na dostosowanie interfejsu jednej klasy do interfejsu innej klasy. Jest to użyteczne, gdy chcesz użyć już istniejącej klasy, ale jej interfejs nie pasuje do Twoich potrzeb. Wzorzec Adapter pozwala na ukrycie różnic między interfejsami, dzięki czemu można je łatwo połączyć i użyć razem.

Jakie zastosowania ma wzorzec Adapter?

Wzorzec Adapter jest często stosowany w następujących sytuacjach:

  • Integracja z istniejącymi klasami: Adapter może być użyty do integracji z już istniejącymi klasami, których interfejs jest niezgodny z twoimi potrzebami.
  • Zmiana interfejsu: Adapter pozwala na zmianę interfejsu klasy bez ingerencji w jej kod źródłowy.
  • Rozszerzanie funkcjonalności: Adapter może być użyty do rozszerzenia funkcjonalności istniejącej klasy poprzez dodanie dodatkowych funkcji.
  • Łączenie różnych systemów: Adapter może być użyty do łączenia różnych systemów i ukrywania różnic między nimi.
  • Współpraca z różnymi bibliotekami: Adapter może być użyty do współpracy z różnymi bibliotekami i frameworkami, które mają różne interfejsy.

Wzorzec projektowy Adapter – przykład implementacji

interface Target {
    public function request();
}
 
class Adaptee {
    public function specificRequest() {
        return "Specific request";
    }
}
 
class Adapter implements Target {
    private $adaptee;
 
    public function __construct(Adaptee $adaptee) {
        $this->adaptee = $adaptee;
    }
 
    public function request() {
        return "Adapter: (TRANSLATED) " . $this->adaptee->specificRequest();
    }
}
 
$adaptee = new Adaptee();
$adapter = new Adapter($adaptee);
 
echo $adapter->request();

W powyższym kodzie mamy interfejs Target, który zawiera sygnaturę metody request(), którą chcemy użyć. Klasa Adaptee jest klasą, która posiada funkcjonalność, ale interfejs jest niezgodny z naszymi wymaganiami. Klasa Adapter jest naszym adapterem i jest on implementacją interfejsu Target. Wewnątrz klasy Adapter używamy obiektu Adaptee, aby wykonać żądane zadanie.

Wzorzec projektowy Adapter w Laravel

Wzorzec projektowy Adapter jest często używany w frameworku Laravel. Laravel posiada wiele mechanizmów, które pozwalają na łatwe dostosowanie interfejsu i implementacji do potrzeb projektu.

Na przykład, można dostosować dostarczone przez framework adaptery bazy danych, aby użyć innej niż domyślna biblioteki do komunikacji z bazą danych. W ten sposób wzorzec Adapter jest wykorzystywany w Laravel do dostosowywania interfejsu do potrzeb projektu.

Rozbicie routes na kilka plików w Laravel

Gdy aplikacja robi się coraz większa dla czytelności można chcieć podzielić plik routes/web.php na kilka mniejszych.

Aby to zrealizować moją pierwszą myślą było po prostu include wydzielonych plików z trasami:

// routes/web.php

require_once 'web/redirects.php';
require_once 'web/website.php';
require_once 'web/admin.php';

Mimo iż to jest złe podejście to po tej zmianie aplikacja działała całkowicie poprawnie.

Problemy zaczęły się gdy wykonałem testy PHPUnit

    public function test_home()
    {
        $response = $this->get('/');

        $response->assertStatus(200);
    }

    public function test_posts()
    {
        $response = $this->get('/posts');

        $response->assertStatus(200);
    }

Pierwszy test zawsze przechodził jednak następne (bez względu czy w tym samym czy innym pliku) zwracały błąd:

Route [home] not defined.

Okazuje się, że mechanika testująca Laravela wczytuje jedynie plik routes/web.php

Aby poprawnie rozbić routes na kilka plików zamiast includów w samym pliku trzeba dostarczyć ścieżki w Provoderze.

Poprawne rozbicie routes na wiele plików

// App\Providers\RouteServiceProvider.php;

Route::middleware('web')
    ->namespace($this->namespace)
    ->group(
        [
            base_path('routes/web.php'),
            base_path('routes/web/redirects.php'),
            base_path('routes/web/website.php'),
            base_path('routes/web/admin.php'),
        ]
    );

Wzorzec projektowy Strategy. Elastyczność i niezależność w twoim kodzie.

Wzorzec projektowy Strategy przydaje się do definiowania rodziny zachowań, algorytmów lub strategii, które mogą być wymieniane przez aplikację. Umożliwia to programowanie do interfejsu, a nie konkretnej implementacji.

Do konkretnych zastosowań wzorca Strategy należą:

  • Abstrakcja algorytmów: Strategy pozwala na oddzielenie logiki algorytmu od klienta, co pozwala na łatwą zmianę implementacji algorytmu bez konieczności modyfikacji kodu klienta.
  • Elastyczność: Aplikacja może zmienić strategię w trakcie działania, co pozwala na dostosowanie działania aplikacji do różnych potrzeb czy sytuacji.
  • Łatwe testowanie: oddzielenie algorytmów od reszty aplikacji pozwala na łatwe testowanie poszczególnych implementacji algorytmów.
  • Skalowalność: rozdzielenie algorytmów

Wzorzec projektowy Strategy – przykład implementacji

Poniżej przedstawiam przykład implementacji wzorca projektowego Strategy w PHP:

interface SortStrategy {
    public function sort(array $data): array;
}

class BubbleSort implements SortStrategy {
    public function sort(array $data): array {
        // implementacja sortowania bąbelkowego
        return $data;
    }
}

class quickSort implements SortStrategy {
    public function sort(array $data): array {
        // implementacja sortowania szybkiego
        return $data;
    }
}

class Sorter {
    protected $sortStrategy;

    public function __construct(SortStrategy $sortStrategy) {
        $this->sortStrategy = $sortStrategy;
    }

    public function setSortStrategy(SortStrategy $sortStrategy) {
        $this->sortStrategy = $sortStrategy;
    }

    public function sort(array $data): array {
        return $this->sortStrategy->sort($data);
    }
}

Kod powyżej zawiera interfejs SortStrategy, który zawiera metodę sort(array $data): array. Klasy bubbleSort i quickSort implementują ten interfejs i zwracają posortowane dane.

Klasa Sorter jest klasą klienta, która przyjmuje obiekt implementujący interfejs SortStrategy w konstruktorze, a następnie używa tego obiektu do wywołania metody sort(array $data) .

$data = [5, 1, 3, 8, 2, 9];

$sorter = new Sorter(new bubbleSort());
$sorter->sort($data);

$sorter->setSortStrategy(new quickSort());
$sorter->sort($data);

W powyższym przykładzie tworzymy instancję klasy Sorter z podaną implementacją sortowania, która jest przypisana do pola sortStrategy. W kolejnym kroku dzięki metodzie setSortStrategy zmieniamy implementację sortowania na inną.

Wzorzec strategy pozwala nam na dynamiczne zmienienie implementacji algorytmu, pozwala na oddzielenie logiki algorytmu od klienta oraz umożliwia tworzenie nowych implementacji bez konieczności modyfikacji kodu klienta.

Wzorzec projektowy Strategy w Laravel

W Laravelu wzorzec Strategy jest używany w kilku miejscach, w tym:

Obsługa różnych formatów danych – Laravel używa strategii do obsługi różnych formatów danych, takich jak json, xml czy też csv. Dzięki temu możemy łatwo dostosować format danych który jest zwracany przez API.

Obsługa różnych metod płatności – Laravel używa strategii do obsługi różnych metod płatności, takich jak PayPal czy też Stripe. Dzięki temu możemy łatwo dostosować system płatności do potrzeb naszej aplikacji.

Obsługa różnych metod wysyłki – Laravel używa strategii do obsługi różnych metod wysyłki, takich jak Poczta Polska czy też DHL. Dzięki temu możemy łatwo dostosować system wysyłki do potrzeb naszej aplikacji.

Widać więc, że wzorzec strategy jest ważnym elementem w Laravelu, ponieważ pozwala na dynamiczne dostosowywanie działania aplikacji do różnych potrzeb i sytuacji, co wpływa na elastyczność i skalowalność aplikacji. Dzięki temu, logika działania jest oddzielona od reszty aplikacji, co pozwala na łatwe testowanie oraz rozwijanie poszczególnych modułów.

Wzorzec projektowy Fabryka. Twoja szansa na zwiększenie czytelności i testowalności kodu.

Wzorzec projektowy Fabryka to Twoja przepustka do projektowania modularnego i skalowalnego kodu.

Wzorzec projektowy Fabryka jest przydatny do tworzenia obiektów. Głównym celem tego wzorca jest oddzielenie logiki tworzenia obiektów od reszty aplikacji oraz umożliwienie łatwego tworzenie różnych typów obiektów.

Do konkretnych zastosowań wzorca Fabryka należą:

  • Abstrakcja tworzenia obiektów – fabryka jest odpowiedzialna za tworzenie obiektów, a nie klient, dlatego logika tworzenia obiektów jest oddzielona od reszty aplikacji.
  • Tworzenie różnych typów obiektów – fabryka może tworzyć różne typy obiektów, które implementują tę samą klasę bazową lub interfejs. To pozwala na łatwe rozszerzanie aplikacji o nowe funkcjonalności.
  • Tworzenie obiektów z danymi testowymi – fabryki często są używane do tworzenia obiektów z danymi testowymi, co jest przydatne przy tworzeniu testów jednostkowych.
  • Elastyczność – Wzorzec fabryka umożliwia na dynamiczne tworzenie różnych implementacji tej samej klasy bazowej czy interfejsu.

Wzorzec projektowy Fabryka – przykład implementacji

Poniżej przedstawiam przykład implementacji wzorca projektowego Fabryka w PHP:

interface Vehicle {
    public function getType(): string;
}

class Car implements Vehicle {
    public function getType(): string {
        return "Car";
    }
}

class Bike implements Vehicle {
    public function getType(): string {
        return "Bike";
    }
}

class VehicleFactory {
    public static function createVehicle(string $type): Vehicle {
        switch ($type) {
            case "car":
                return new Car();
            case "bike":
                return new Bike();
            default:
                throw new Exception("Invalid vehicle type");
        }
    }
}

Kod powyżej zawiera interfejs Vehicle, który zawiera metodę getType(). Klasy Car i Bike implementują ten interfejs i zwracają odpowiedni typ pojazdu. Klasa VehicleFactory jest fabryką, która posiada statyczną metodę createVehicle(), która jest odpowiedzialna za tworzenie obiektów klas Car i Bike. Metoda ta przyjmuje jako argument typ pojazdu, a następnie w zależności od tego jaki typ jest podany zwraca odpowiedni obiekt.

$car = VehicleFactory::createVehicle("car");
echo $car->getType(); // "Car"

$bike = VehicleFactory::createVehicle("bike");
echo $bike->getType(); // "Bike"

W powyższym przykładie używamy metody createVehicle z klasy VehicleFactory by utworzyć instancję klasy Car lub Bike.

Warto zauważyć, że zwiększa to abstrakcję i oddziela logikę tworzenia obiektów od reszty aplikacji. Dzięki temu w razie potrzeby, możemy łatwo zmienić sposób tworzenia obiektów bez wpływu na pozostałą część aplikacji.

Warto wspomnieć że wzorzec Fabryka jest często używany w połączeniu z innymi wzorcami projektowymi takimi jak np. Wzorzec projektowy Strategia czy też Wzorzec projektowy Builder. Dzięki temu połączeniu, tworzą one skomplikowany system, który jest bardziej elastyczny i łatwy w utrzymaniu.

Wzorzec projektowy Fabryka w Laravel

W Laravelu wzorzec fabryka jest używany w kilku miejscach, w tym:

Tworzenie obiektów modeli – Laravel używa fabryk do tworzenia obiektów modeli, które reprezentują rekordy z bazy danych. Fabryki pozwalają na łatwe utworzenie obiektów z danymi testowymi, co jest bardzo przydatne przy tworzeniu testów jednostkowych.

Tworzenie migracji – Laravel używa fabryk do generowania danych testowych do migracji, które pozwalają na przetestowanie aplikacji przed uruchomieniem jej na produkcji.

Tworzenie przykładowych danych – Laravel udostępnia także API do tworzenia przykładowych danych, które są generowane przez fabryki.

Tworzenie modeli w kontrolerach – Fabryki Laravel pozwalają także na proste tworzenie modeli bezpośrednio w kontrolerach, w związku z tym użycie konstruktora nie jest konieczne.

Widać więc, że fabryki są istotnym elementem w Laravelu, ponieważ pozwalają na generowanie danych testowych, tworzenie modeli i migracji, co wpływa na poprawienie przetestowalności aplikacji. Dzięki fabrykom kod jest bardziej czytelny, ponieważ logika tworzenia obiektów jest oddzielona od reszty aplikacji.

Wzorzec projektowy Fabryka w Symfony

W Symfony możemy również użyć fabryki do tworzenia instancji usług zależnie od określonych warunków lub konfiguracji.

Na przykład, możemy stworzyć fabrykę, która na podstawie parametru konfiguracyjnego utworzy odpowiednią instancję usługi do obsługi operacji na plikach.

class FileServiceFactory {
    public static function create(string $storageType): FileServiceInterface {
        switch ($storageType) {
            case 'local':
                return new LocalFileService();
            case 'cloud':
                return new CloudFileService();
            default:
                throw new \InvalidArgumentException('Invalid storage type');
        }
    }
}

// Użycie fabryki
$fileService = FileServiceFactory::create('cloud');
$fileService->uploadFile($file);