<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="de_DE"><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://www.kevinpapst.de/feed/index.xml" rel="self" type="application/atom+xml" /><link href="https://www.kevinpapst.de/" rel="alternate" type="text/html" hreflang="de_DE" /><updated>2026-03-22T08:44:44+00:00</updated><id>https://www.kevinpapst.de/feed/index.xml</id><title type="html">Kevin Papst</title><subtitle>Kevin Papst, Open-Source-Entwickler aus Wien und Entwickler der Zeiterfassung Kimai.</subtitle><author><name>kevinpapst</name></author><entry><title type="html">Trial-Bike rockt … als Zuschauer</title><link href="https://www.kevinpapst.de/blog/das-grosse-trial-bike-abc.html" rel="alternate" type="text/html" title="Trial-Bike rockt … als Zuschauer" /><published>2024-05-13T08:00:00+00:00</published><updated>2024-05-13T08:00:00+00:00</updated><id>https://www.kevinpapst.de/blog/das-grosse-trial-bike-abc</id><content type="html" xml:base="https://www.kevinpapst.de/blog/das-grosse-trial-bike-abc.html"><![CDATA[<p>Dieser Artikel ist die Quintessenz einer jahrelangen Leidenschaft und Zusammenfassung aller 
Artikel übers Trialbiken, die in der Vergangenheit auf einem eigenen Blog veröffentlicht waren.</p>

<h2>Ist Trialbiken etwas für alle?</h2>

<p>Ist Trialbike für alle geeignet? Ja und Nein, man braucht neben körperlicher Fitness und guter Körperkoordination auch noch eine gehörige Portion Mut.</p>

<p>Für wen ist Trialbike geeignet? Gute Frage. Leicht zu beantworten. Grundsätzlich können Frauen, Männer, Jugendliche und Kinder das Trialbiken erlernen.
Gerade bei den Kids ist das Trialbike weit verbreitet und es gibt auch Meisterschaften für die werdenden Trickfahrer.
Trotz allem ist es aber immer noch eine Männerdomäne. Frauen sind in der repräsentativen Unterzahl, aber was nicht ist kann ja noch werden.
Witzig ist es, immer wieder bei den Anbietern von Trialbike Lehrgängen zu lesen, dass es spezielle Frauenkurse gibt.
Soviel zum Zeitalter der Emanzipation. Frauen gehören da eben noch zu den Exoten.</p>

<p>Wichtig für diesen Sport ist es, zu wissen, dass man nicht mal eben wie Danny MacAskill
sein Bike aus der Garage holen kann, um dann einfach so aufs Gute Wohl loszuradeln.
Denn was der Stunt-Meister aus Schottland da so brillant und leicht vorführt, hat auch bei ihm immerhin 12 Jahre intensives Training und zahlreiche Ableger erfordert.
Daher klein anfangen und groß aufsteigen - so lautet die Devise.</p>

<div class="image fit">

<div class="js-reframe" style="position: relative; width: 100%; margin: 0 0 1.33333em;">
	<iframe src="https://player.vimeo.com/video/9970489" frameborder="0" allowfullscreen=""></iframe>
</div>

</div>

<blockquote>
  <p>Mitten in der Stadt - abgesperrte Straßen, gute Sprüngem, Treppen - ein Hund im Weg und das alles gefilmt mit der Action-Cam am Helm … WOW, was für ein Downhill Video!</p>
</blockquote>

<p>Wer einen Hang zu Abenteuern hat und das Fahrrad generell nicht nur aus Kindertagen mit Stützrädern kennt, der kann sich im Trialbike versuchen.
Anfänger sollten jedoch erst einmal mit einem Mountainbike starten und das Gelände erkunden,
um ein Gefühl für das Rad und ihren Körper zu bekommen. Krafttraining und Konzentrationsübungen sind ebenfalls angeraten.
Denn wer einmal versucht, das Vorderrad seines BMX Rades einfach so anzuheben, aus dem Stand wohlgemerkt,
der wird schnell merken, dass es dafür mehr bedarf, als der Wille allein.</p>

<p>Ausdauertraining sollte ebenfalls nicht vernachlässigt werden. Die Kräfte sind schnell verzehrt und die Selbstüberschätzung bisweilen vielleicht zu groß.
Schutzkleidung und Helm sind ein Must have. Denn Stürze bleiben nicht aus und Übung macht den Meister.
Natürlich muss keiner wie ein Alien aus dem Weltall verpackt sein. Kopf, Arme und Beine sollten aber gut gepolstert sein.</p>

<p>Schnupperkurse sind prinzipiell nicht verkehrt, davon wird man aber nicht zu einem Künstler auf zwei Rädern.
Hierfür gibt es Teams und Einrichtungen, die eine langfristige Ausbildung anbieten, mit allem, was dazu gehört.</p>

<p>Beratung vor dem Kauf eines speziellen Trial Bikes ist unbedingt angesagt.
Es gibt soviel zu beachten und Einsteiger fahren besser, wenn Sie es auch beim Rad erst einmal eine Nummer kleiner angehen lassen.</p>

<h2>Fahrtechniken</h2>

<p>Die richtigen Fahrtechniken auf dem Trialbike lernen: Bremsen, Kurventechniken, Balance - Tips und Tricks für die Fahrt auf dem Trialbike</p>

<p>Auch beim Trialbiken heißt es: Erst einmal die grundlegenden Dinge zu beherrschen, bevor es an die Feintunes geht. Feintunes sind in diesem Zusammenhang die Tricks und Fertigkeiten die schon Stunt-Potential besitzen.</p>

<p>Auch wenn es sich schon fast lästig anhört, aber bevor es losgeht, sollte die richtige Schutzkleidung angezogen werden, der Helm ist Pflicht.</p>

<div class="gallery">
	
	<div class="gallery_images">
        
<figure class="caption">
	<img src="/images/trialbike/IMG_0399.jpg" alt="Bild zur Verfügung gestellt von M. Wibmer / Alle Rechte liegen bei www.ota.at" />
    <figcaption class="caption-text">Bild zur Verfügung gestellt von M. Wibmer / Alle Rechte liegen bei www.ota.at</figcaption>
</figure>

		
	</div>
</div>

<p>Rad checken und zwar regelmäßig. Denn das Bike ist eine größere Gefahrenquelle, als man glaubt. Risse, desolate Lenker und weitere Kleinigkeiten können schnell lebensgefährlich werden. Vor jedem Wagnis, sollte der Fahrer kurz inne halten und sich vergewissern, dass er auch weiß, was er jetzt vorhat und welche Konsequenzen und Gefahren dies so mit sich bringt.</p>

<p>Wenn das alles erledigt ist, geht es ab zum Üben. Balance ist hier das A und O. Wer das nicht beherrscht, der wird auf seinen zwei Rädern kein Künstler werden. Dazu wird ein ruhiges und ebenes Gelände ausgesucht. Am Anfang kann ein Widerstand, zum Beispiel eine Mauer oder ein Baumstamm, als Stütze genommen werden. Die Bremsen werden angezogen und der Lenker leicht eingeschlagen. Wichtig: nach vorne schauen. Später kann dann auf schmalen Brettern geübt werden.</p>

<p>Bremsen lernen! Wer nicht einen unschönen Abgang über den Lenker riskieren will, der sollte sich intensiv mit seinen Bremsen beschäftigen. Hier ist die richtige Dosierung zwischen Vorder- und Hinterbremse angesagt, entsprechend den jeweiligen Bodenverhältnissen.</p>

<p>Vor Kurven immer rechtzeitig abbremsen. Bergauf- und Bergabfahren sind ebenfalls zu trainieren. Hierbei spielt Gewichtsverlagerung und Konzentration nach vorne die ausschlaggebende Rolle.</p>

<p>Die Gangschaltung kann bei den Modellen variieren. Hier sind Begriffe, wie Übersetzung, Ritzel und Kettenblätter wichtige Infos, die der Biker kennen muss.</p>

<p>Wenn diese Dinge nun alle sitzen, dann kann mit den Spezialitäten begonnen werden.</p>

<p>Der „Bunny Hop“ ist Voraussetzung, um über Hindernisse zu springen, das heißt, das Bike muss nach oben kommen. Das Hüpfen auf dem Hinterrad wird „Back Wheel Hop“ genannt. In beiden Fällen sind das Arbeiten mit den Bremsen und die Gewichtsverlagerung wieder entscheidend. Um mit dem Hinterrad nach vorne zu springen ist der Pedal Kick zu trainieren. Das erfordert allerdings schon eine intensive Übung, da hier der Körpereinsatz sehr groß ist. Während man auf dem Hinterrad hüpft, lässt man sich nach vorne fallen und geht mit dem Gleichgewicht hinterher. Die Hüften müssen dabei blitzschnell Richtung Lenker bewegt werden. Gleichzeitig wird die Hinterradbremse gelöst und kräftig in die Pedale gekickt. Das hört sich nach besonderer Koordination an und bei dieser Übung lernt der Fahrer sehr gut, worauf es ankommt.</p>

<p>Natürlich kann jeder Interessierte alleine üben. Besser ist es jedoch, sich von Profis beraten zu lassen, um essentielle Fehler zu vermeiden.</p>

<div class="gallery">
	
	<div class="gallery_images">
        
<figure class="caption">
	<img src="/images/trialbike/IMG_0504.jpg" alt="Bild zur Verfügung gestellt von M. Wibmer / Alle Rechte liegen bei www.ota.at" />
    <figcaption class="caption-text">Bild zur Verfügung gestellt von M. Wibmer / Alle Rechte liegen bei www.ota.at</figcaption>
</figure>

		
	</div>
</div>

<h2>Stil-Richtungen im Trialbike-Sport</h2>

<p>Wir erklären euch die verschiedenen Stil-Richtungen im Trialbike-Sport. Denn Trialbiking ist vielseitig und mehr als das reine Überqueren von Hindernissen!</p>

<p>Trialbiking ist sehr vielseitig und beschränkt sich nicht auf das reine Überqueren von Hindernissen oder spektakuläre Sprünge.</p>

<h3>Show Trial</h3>

<p>Viele Menschen, aufgebaute Parcours, atemberaubende Tricks und Stunts – das ist der Show Trial mit dem passenden Bike.
Ob auf Messen, in Freizeitparks oder auch Hallen, die Möglichkeiten sind sehr groß. Sprünge über Hindernisse, wie gestapelte Paletten,
Reifen oder auch das Balancieren zwischen liegenden Menschen hindurch werden immer wieder gerne vom Publikum gesehen.
Show Trial wird von Einzeltrailern, aber auch von Gruppen angeboten. Es dient in erster Linie der Unterhaltung und soll in Staunen versetzen.
Dabei fiebert der Zuschauer immer mit, dass auch nichts schief geht.</p>

<h3>Stunt Trial</h3>

<p>Stunt Trial ist die hohe Kunst des Trials, mit dem Rad außergewöhnliche Sprünge und Loopings durchzuführen.
Dabei gibt es eine Reihe von Tricks und Stunts, die der Biker lernen kann. Trackstand, Bunny Hop, Wheelie, Backflip,
Franzose oder Freiheitsstatue sind nur einige von diesen Tricks. Damit können dann Hindernisse geschickt überwunden werden.
Das A und O, als Voraussetzung für Stunt Trial, sind die Balance und die Kontrolle über den Körper und das Rad.</p>

<h3>Street Trial</h3>

<p>Danny McAskill gehört zu den Stars unter den Street Trialern.
Er schnappt sich sein Bike und jagt durch die Gegend.
Treppengeländer, Treppenstufen, Brückenpfeiler werden mit dem Bike gekonnt überwunden, ebenso, wie alle anderen Hindernisse,
die Stadt und Land zu bieten haben.
Auch Sprünge, beispielsweise über Mauern, gehören dazu.
Street Trial bietet jede Menge Herausforderungen.</p>

<h3>Einrad-Trial</h3>

<p>Nur auf einem Rad Hindernisse überwinden oder waghalsige Sprünge durchführen, das kennzeichnet den Einrad-Trial.
Der Trialsport stellt an ein Einrad größere Anforderungen, als an ein normales Trialbike. Die Konstruktion ist noch stabiler,
Kurbeln und Pedale sind robuster gebaut. Auch die Körperbeherrschung muss optimiert werden.</p>

<p>Kris Holm ist das Aushängeschild dieser Disziplin.</p>

<h3>Mountain Unicycling</h3>

<p>Berg-Einrad oder auch Offroad-Einrad ist das Trialbiking mit dem Einrad in bergigem Gelände.
Bei dieser Sportart geht es Berge hinab, Wurzeln und Steine gilt es zu überqueren.
Unebenes Gelände, Felsen, Sand, Schnee, Eis, Matsch sind die gängigen Untergründe für diese Art des Bikens.
Schwierige Abfahrten bestimmen die Strecke. Dazu muss auch das Rad entsprechend konstruiert sein.
26 Zoll Stollenreifen mit grobem Profil werden hier gerne genommen.
Ein absoluter Könner dieser Disziplin ist Kris Holm.</p>

<h3>Wettbewerbs-Trial</h3>

<p>Sich in Leistung messen – das geht bei den Wettbewerben für Trialfahrer.
In Teams oder alleine absolvieren sie, je nach Art, schwierige Parcours in Hallen oder Sektionen, draußen im freien Gelände.
Outdoor werden diese Wettbewerbe meistens in unwegsamen Waldregionen durchgeführt, mit zahlreichen natürlichen Hindernissen.
Die Fahrer kennen die Strecke vorher nicht. Es gelten strenge Regeln und es kommt auf die Fehlerfreiheit an.
Die Wettbewerbe werden üblicherweise in die Rad-Kategorien 20 oder 26 Zoll eingeteilt.
Es gibt regionale, Europa- und Weltmeisterschaften im Fahrrad-Trial.</p>

<h2>Trial – Historie und Entwicklung</h2>

<p>Wie ist Trialbike entstanden und wohin wird es sich in der Zukunft entwickeln? Ein Rück- und Ausblick auf den Trialbike Sport.</p>

<p>Trial entwickelte sich in den 1970er Jahren in der Motorradszene. Das Wort Trial ist von „try“ abgeleitet und heißt: versuchen.
Damals versuchten Motorradfahrer unwegsames Gelände mit ihren Maschinen zu durchqueren. Aus diesen anfänglichen Versuchen
entwickelten sich sehr schnell durchdachte Möglichkeiten, um die Fahrzeuge den schwierigen Gegebenheiten anzupassen
und mit dem Einsatz des Körpers zu dirigieren.
Daraus entwickelten sich auch die Trial Wettkämpfe,
bei denen genau abgesteckte Sektionen (Bereiche), die mit Hindernissen aller Art gespickt sind, durchfahren werden müssen,
ohne mit den Füßen auf den Boden zu kommen. Genauso wenig ist das Abstützen mit der Hand erlaubt.</p>

<p>Trial beschränkt sich nicht nur auf Motorräder, obwohl sie den Begriff geprägt haben.</p>

<p>Trials werden mit Autos, LKWs, Fahrrädern (den speziellen Trial-Bikes) oder auch mit Einrädern gefahren.
Trial hat sich ständig weiterentwickelt und mittlerweile ist der Fahrradtrial
zu einem neuen Funsport gewachsen. Auch hier werden Wettbewerbe indoor (in einer Halle) oder outdoor gefahren.</p>

<p>Neben dieser Leistungsmessung gibt es allerdings auch noch Urban und Street Trialbike.
Das Urban Biking mit BMX oder Trialfahrrädern ist sehr vielfältig und fordert vom Fahrer eine permanente Konzentration und Einstellung auf neue Gegebenheiten.
Er muss sein Bike unter Kontrolle haben und es ständig an die Situation anpassen.
Grenzen sind hier keine gesetzt.
Ausgefuchste Profibiker bereisen die Welt und suchen sich immer neue Herausforderungen, wie Klippen, Felswände, Wüstenstrände, Wasserfälle und dergleichen.</p>

<p>Beim Street- oder Citytrial werden alle Hindernisse, die man in der Stadt oder auf der Straße findet, genommen. Treppen,
Schilder, Absperrungen, Begrenzungen, Brückenpfeiler oder Steinmauern sind beliebte Hürden. Dabei führen die Biker, die diese Trials wählen,
schon richtige Kunststücke auf ihren Bikes aus. Balancieren, Springen, Hüpfen, ja manchmal tanzen sie sogar auf zwei Rädern.</p>

<p>Auch das Showfahren hat seinen Stellenwert ausgebaut. Installierte Parcours mit eindrucksvollen Hindernissen,
zu denen auch liegende Menschen gehören, sind ebenso dabei, wie hoch gestapelte Kisten oder Autos.</p>

<p>In Deutschland ist die Szene noch sehr klein. Wenn man aber über den Kontinent winkt, sieht das schon etwas anders aus.
Stunt- und Trickfahrer, wie Danny MacAskill, der mit seinen Youtube Videos Millionen Menschen aufmerksam gemacht hat,
tragen zur Popularität dieser Kunst bei.</p>

<div class="gallery">
	
	<div class="gallery_images">
        
<figure class="caption">
	<img src="/images/trialbike/IMG_0388.jpg" alt="Bild zur Verfügung gestellt von M. Wibmer / Alle Rechte liegen bei www.ota.at" />
    <figcaption class="caption-text">Bild zur Verfügung gestellt von M. Wibmer / Alle Rechte liegen bei www.ota.at</figcaption>
</figure>

		
	</div>
</div>

<p>Was ursprünglich mit Mountainbikes und BMX Rädern im Fahrradtrial begonnen hatte, erforderte mit der Zeit eine Optimierung der Fahrräder.
Überflüssiges wurde weglassen, die Konstruktion und die Funktionstüchtigkeit der Bikes den besonderen Verhältnissen angepasst.
Daher gibt es heute spezielle Trial Bikes auf dem Markt.</p>

<p>Viele Trialfahrer sind in so genannte „Teams“
eingebunden und fahren zum Teil auch für große Bike-Hersteller. Trial ist eine Herausforderung an sich selbst.
Denn was so leicht aussieht ist nicht für jeden etwas,
es erfordert eine totale Körperbeherrschung, Kraft und Ausdauer.
Immer mit dem Risiko einer Verletzung. Doch Spaß macht es auf jeden Fall und wenn es nur beim Zusehen ist.</p>

<h2>Bekannte Trialbike Fahrer</h2>

<h3>Danny MacAskill - Zauberer auf zwei Rädern</h3>

<p>Danny MacAskill - der wahrscheinlich bekannteste Trialfahrer der Welt und Star mehrerer extrem erfolgreicher Trial-Videos bei YouTube.</p>

<p>Okay, wer in der Szene des Trial Bikens so richtig mitreden will, der sollte neben einem ordentlichen Bike,
einer Schutzzausrüstung und dem Talent zum Einstecken, vor allen Dingen auch die heiligen drei Könige des Metiers kennen.
Das Trio Infernale der weltbesten Trial Riders heißt Danny MacAskill, Steve Peat
und Hans Rey. Das ist die chronologische Reihenfolge des Alters (Youngster bis Hipster).</p>

<p>Danny MacAskill ist das beste Beispiel dafür, wie man über Nacht durch Youtube weltberühmt werden kann.
Video einstellen und über 14 Millionen Mal angeklickt werden.</p>

<p>Im April 2009 veröffentlicht Danny MacAskill das wohl berühmteste Trialbike Video der Welt, in dem er selbst die Hauptrolle übernimmt.
Über 23 Millionen Aufrufe bisher und kein Ende in Sicht … einfach geniessen!</p>

<div class="image fit">

<div class="js-reframe" style="position: relative; width: 100%; margin: 0 0 1.33333em;">
	<iframe src="https://www.youtube-nocookie.com/embed/Z19zFlPah-o?feature=oembed" frameborder="0" allowfullscreen=""></iframe>
</div>

</div>

<p>Dazu ist Youtube ja da. Im April 2009 löste das Video „Inspired Bicycles“
mit den Stunts des Schotten eine wahre Hysterie unter Bike Fans und vermutlich auch Frauen aus.
Denn auch Frauen finden solche Typen ultracool :)</p>

<p>Danny fährt für den englischen Trialbike-Hersteller Inspired Bikes.</p>

<p>Da wird mit dem Bike wirklich alles aufgefahren, was man sich so denken kann, Treppen, Geländer, Pfeiler, Zäune.
Entfernungen werden auf zwei Rädern überwunden, sensationelle Sprünge und Balanceakte gibt’s obendrauf.
Aber das soll man sich ansehen, beschreiben ist da fehl am Platz. Da fragt man sich mehr als einmal:
Wie hält der Hintern das bloß aus? Ohne Körperbeherrschung geht da gar nix.
Aber vielleicht hat Danny the Askill seinen Namen ja mit Absicht so in die Wiege gelegt bekommen.</p>

<p>Okay her mit den Eckfacts, damit das Gespräch mit dem Kumpel oder der Kumpeline auch nicht zur Blamage wird:</p>

<p>Geboren wurde Danny 1985 in Schottland, Isle of Skye, genau einen Tag vor Heiligabend.</p>

<p>Über sein Leben, bis zu seinem Erfolg 2009 ist bekannt, dass er als Fahrradmechaniker in Edinburgh tätig war.
Immerhin hatte er so schon sein Hobby in gewisser Weise zum Beruf gemacht.
Er gründete 2009 die Stunt Gruppe „The Clan“ und wollte sich von da an nur noch mit dem Trial Biken beschäftigen.
Dass er aber schon zwölf Jahre lang geübt hatte, das darf nicht vorenthalten werden,
denn sonst denken alle wohl möglich noch, er könnte wirklich zaubern.</p>

<p>Zauberhaft war allerdings die Idee, sein Bike, aus dem Youtube Video, bei Ebay zu versteigern und den satten Erlös
von ca. 3400 Euro dem Hilfsprojekt Kinder in Not (Children in Need) zukommen zu lassen.
Er hat es auch verdient, dass sich plötzlich alle um ihn gerissen haben: Zeitungsleute, Sponsoren, TV, usw.
Denn es stecken schon jede Menge Training, Geduld und viele Schmerzen hinter solch einer Leistung.</p>

<p>Danny soll trotz des Rummels und Rubels um ihn aber immer noch ein ganz normaler Mensch sein, der sich freut,
dass er jetzt machen kann, was er will und wann er will.</p>

<p>Besonderer Beliebtheit erfreuen sich seine Shows bei der Bike Expo in München, bei denen Danny seinen eigenen Parcours
hat und natürlich tausende von Zuschauern. Aber Shows fährt er eigentlich nicht, das macht der dann nur an der Expo.
Er gehört zu den Teamfahrern des englischen Bike Herstellers „Inspired Bikes“.
Auch Werbespots, die ihm manche übel nehmen, z.B. für bestimmte Automarken, kommen vor.
Aber Danny ist ja frei und eigentlich kann er uns ja wieder mit einem Überraschungsvideo, dass die 15 Mille Grenze knackt, begeistern.</p>

<p>Ergänzung: Sein zweites Video “Way back home” wurde mittlerweile auch über 13 Millionen mal angeklickt, 
auch sein zweiter Geniestreich wurde zum vollen Erfolg!</p>

<h3>Kris Holm – Einradtrial vom Feinsten</h3>

<p>Kris Holm - der unangefochtene Meister des Einradtrial und Weltmeister im Unicycle Trial 2002.</p>

<p>Eine Besonderheit im Trial Biken ist das Einrad Trial. 
Unangefochtener Meister dieser Disziplin ist der Kanadier Kris Holm. 
Der Weltmeister im Unicycle Trial 2002 beherrscht sein Metier ausnahmslos und ist der Star des Mountain Unicycling, kurz „Muni“ genannt.</p>

<p>Schwindelig wird es dem Zuschauer bei seinen waghalsigen Rides an Felsabgründen oder superschmalen Brückenpfeilern. 
Stadientribünen springt er mühelos hoch und runter. 
Waldstrecken, die andere noch nicht einmal zu Fuß gehen könnten, bewältigt er mit seinem Einrad leicht und elegant. 
Und er steht auch mal zu einem Sturz, bei dem das Einrad hinüber ist. 
Symphatisch und extrem professionell - das sind die Schlagwörter, die zu Kris Holm passen.</p>

<p>Angefangen hat alles im Alter von elf Jahren. 
Tief beeindruckt von einem Straßenkünstler, der mit seinem Einrad Zauberstücke vollführte, war es um den jungen Kris geschehen. 
Mit zwölf bekam er sein eigenes Einrad und übte von da an fleißig. 
Ihm sind die ersten Einrad-Trial Wettkämpfe zu verdanken. 
Mit seinem Talent und der Einmaligkeit der Aktionen zog er die Aufmerksamkeit von Film und Fernsehen auf sich und verschaffte so dem Sport die gebührende Anerkennung. 
Mittlerweile sind zahlreiche Nachfolger in seine Fußstapfen getreten. 
Doch mit seinen spektakulären Abenteuer-Rides auf Vulkanen in Mexiko und Guatemala, zum Himalaja oder an der Chinesischen Mauer, bleibt er der unangefochtene Star der Szene.</p>

<p>Wie er selbst sagt, ist es für Chris das Schönste, seine Leidenschaften Reisen, Einradfahren und Bergsteigen, so oft es geht, miteinander zu verbinden. 
Aus dem Wettebewerbsbereich hat er sich zurückgezogen und seine eigene Firma für den Bau von Einrädern gegründet: „Kris Holm Unicycles“. 
Diese Einräder sind speziell auf die Anforderungen des Mountain Cyclings ausgerichtet. Talentierte Fahrer werden gesponsert und unterstützt. 
Zudem achtet der Naturfreak Kris auch auf den Umweltschutz bei der Herstellung der Räder und beteiligt Umweltschutzorganisationen am Umsatz. 
Vorbildlich kann man da nur sagen – in jeder Hinsicht. Also mal auf Youtube nach Kris Holm schauen und fesseln lassen.</p>

<h3>Hans Rey - Godfather of Trialbike</h3>

<p>Hans Rey - Pionier des Trialbiking und Star zahlreicher Dokumentation</p>

<p>Alles hat seinen Anfang und wenn man einen Pioneer braucht, in der Geschichte des Trial- und Urban Biking, dann ist Hans Rey eben genau so einer.</p>

<p>Er ist ein Jahrgang 1966 und ein guter dazu. Noch kein bisschen leise oder müde. Nee auf Youtube kann man ihn schon als Legende, in zahlreichen Dokumentationen, bewundern.</p>

<p>Multikulti ist er sowieso. Er wurde in Deutschland geboren, nahm die Schweizer Nationalität an und lebt heute in den USA. Hummeln im Popöchen haben ihn zum Trialbiken angetrieben. Mit den beiden Künstlerkollegen Danny MacAskill und Steve Peat lässt er sich auch mal auf einen flotten Dreier in den schottischen Highlands ein und sorgt damit für Furore.</p>

<p>Doch man wird nicht einfach so zu einem Kultfaktor. Dafür muss Leistung her. Und dass so etwas jahrzehntelanges Training erfordert ist klar. Als mehrfacher Weltmeister im Trial Biken und mit zahlreichen nationalen und internationalen Rängen, hat Hans Rey dem Trialbike-Sport alle Ehren erwiesen. Doch Hans wäre nicht Hans, wenn er sich auf solchen Erfolgen ausruhen würde. Und so sind Vulkantänze in Hawai, unter Wasser Bungee und ein spektakulärer Sprung über ein Auto, auf dem Freeway in Los Angeles, nur einige seiner zahlreichen Abenteuer.</p>

<p>1997 verabschiedete er sich vom Wettkampfsport und begann auf seinem Bike die Welt zu erkunden. Und da gibt es so gut wie nichts, was er nicht schon auf den zwei Rädern erforscht hat: Ägyptischer Wüstensand, Schluchten in Mexiko, Berge in Kenya und Brasilien oder Hügellandschaften in den Philippinen. Das ist nur ein Auszug aus der langen Liste. Fast immer dabei ist ein Team von Kameraleuten und Fotografen, die alles dokumentieren. Das „Hans Rey Adventure Team“ wurde gegründet, um Millionen von Zuschauern an diesen Abenteuern teilhaben zu lassen. Auch weitere, namhafte Biker nimmt Hans auf seine Touren gerne mit. Dann macht es noch mehr Spaß. Und so wird gedreht, was das Zeug hält, ganz im Sinne des stockenden Atems: Waghalsige Ausflüge zu den Wasserfällen in Jamaika, die Suche nach dem Inka Gold in Bolivien oder das Stelldichein mit den Raubkatzen im Dschungel.</p>

<p>Die Medienpräsenz ist Hans gewohnt, ob als Stuntman in Filmen, wie „Fire and Ice“ (Bogner) oder „White Magic“. Zahlreiche TV Shows hat er schon mit seiner Anwesenheit beglückt. 1996 zeigte er sein Können bei der Abschlussfeier der olympischen Spiele in Atlanta. Was will man mehr – die Aufnahme in die Mountainbike Hall of Frame - und da ist er auch schon drin!</p>

<h3>Steve Peat – ein bisschen crazy schadet nicht</h3>

<p>Steve Peat - englischer Trialbiker aus Leidenschaft - hält den Weltmeister Titel im Downhill-Biken 2009.</p>

<p>„Guten Tag Herr Doktor“, könnte man den Trial Profi Steve Peat ohne weiteres anreden. Denn immerhin wurde ihm von der Hallam Univeritsy in Sheffield im Jahr 2008 der Ehrendoktortitel verliehen. Zum einen für seine großartigen, sportlichen Leistungen und zum anderen für sein Engagement bei lokalen Wohltätigkeits-Aktionen.</p>

<p>Doch wenn man ihn so sieht, dann ist er mehr der durch geknallte Typ von nebenan, der eben super gut auf seinem Bike ist und dafür auch mehrfach ausgezeichnet wurde. Er erinnert, mit seinen 34 Jahren, an einen eher 19 jährigen Freak, Graffittiwände und eine Portion jungenhaftem Charme. 1974 erblickte er in Chapeltown, South Yorkshire (England) das Licht der Welt und freute sich auf die Dinge, welche da auf ihn zukommen sollten.</p>

<p>Bereits mit drei Jahren stieg er zum ersten Mal auf ein Rad, um damit zu beginnen, was er heute kann. Seine beiden älteren Brüder waren dabei für ihn die größten Vorbilder. Mit ihnen zusammen machte er die Gegenden unsicher und lernte viel. Er fuhr mit Mountainbikes und startete nach dem Abschluss der Highschool seine Teilnahme an Rennen. Einmal Blut geleckt, sollte das die Passion von „Peaty“ werden, der laut eigenen Angaben, 14 Steine wiegt und sich am liebsten von Fish and Chips sowie Stella Artois ernährt.</p>

<p>Mit 19 Jahren stieg er professionell in das Bike-Business ein. Mit verschiedenen Teams, denen Steve angehörte, führ er sagenhafte Erfolge. Den UCI Downhill-Weltcup gewann er dreimal. Neben 17 Weltcup-Siegen, etlichen Meister-Titeln und Silbermedaillen, ist sein größter Erfolg noch relativ frisch: 2009 konnte er den Weltmeister Titel im Downhill-Biken sein eigenen nennen. Downhill bezeichnet eine Disziplin, bei der ausschließlich bergab gefahren wird und das möglichst schnell. Dabei ist das alles andere alles einfach, denn das Gelände ist rutschig, uneben und noch dazu mit vielen, gemeinen Hindernissen gespickt, so dass hier enorme Konzentration gefragt ist. Doch darin ist Steve Spitze und es kann ihm keiner so schnell das Wasser reichen. Ein so aktiver Kerl, ruht sich natürlich nicht aus. Er arbeitet an seiner eigenen Akademie für Jugendliche, die das Biken lernen wollen und engagiert sich vorbildlich für kranke Kinder.</p>

<p>Und wer Steve mal besuchen will, der klopft ganz einfach an die knallrote Holztür in Sheffield und sagt mal Hallo. Vielleicht sind dann auch gerade seine Frau und die beiden Söhne da.</p>

<h3>Thomas Öhler – Trialbiker Made in Austria</h3>

<p>Thomas Öhler, österreichisches Trialtalent, Weltrekordhalter im Fahrradhochsprung und Weltmeister 2008 im Trial Bike.</p>

<p>Der Eintrag für Tom Oehler bei Wikipedia wäre mal dringend angesagt.
Denn das österreichische Trialtalent ist eine der wenigen Jungs weltweit, die ihre hohe Kunst verstehen.</p>

<p>Im Wettbewerbs-Trial ist Tom hierbei ebenso fit, wie beim Street Trial.
Da wird auf Mauern und Steinen getanzt oder Menschen werden übersprungen, mit nur einem Spalt breit Luft dazwischen, wo der Trialprofi reinpassen muss.
Sprungbalancen von Baumstamm zu Baumstamm, in unterschiedlichen Höhenordnungen, sind ebenso sein Ding. Ja der Junge hat was drauf.
Als Weltrekordhalter im Fahrradhochsprung und Weltmeister 2008 im Trial Bike International Union ist sein Können schon bewiesen.
Seit 2008 fährt er keine Wettbewerbe mehr, sondern widmet sich dem Show- und Stunt Trial. Dabei ist Street Trial seine favorisierte Disziplin.</p>

<p>Anfangen hat es bei ihm eigentlich so, wie bei all seinen bekannten Kollegen. Schon als Kind war die Begeisterung da,
stark geprägt durch seinen Vater, einem Rallyefahrer und leidenschaftlichem Biker.
Später zog er mit Freunden um die Häuser und übte auf Mountainbikes und BMX. Der gebürtige Österreicher, Jahrgang 1983,
wollte allerdings mehr und merkte schnell, dass für seine Trials ein herkömmliches BMX Rad nicht mehr reicht.
Ausgestattet mit einem Trialbike, ging es dann zu den ersten Wettbewerben. Da war Tom 15 und lief schon in der internationalen Bikerszene rum.
Fünfmal wurde er Meister im eigenen Lande und 2006 Europameister. Zuletzt heimste er dann auch noch den Weltmeistertitel ein.</p>

<p>Sein Vorbild ist Hans Rey und ihm tut er es auch gerne gleich.
Sein Faible für das Reisen um die Welt bringt ihn immer wieder gerne in die amerikanischen Gefilde oder nach Kuwait, wo er,
mit seinen Bike-Spaziergängen auf den Hausdächern, die Passanten zum Staunen bringt.</p>

<p>Ein wenig Glück gehört auch dazu, um bei Wettkämpfen zu siegen, sagt Tom Öhler. Da hat er wohl auch Recht.
Und wie andere einen Talisman haben für dies und das, verlässt sich Tom Öhler ganz auf seine Glückssocken.
Das ist doch mal ne Idee, vielleicht ne neue Marketingstrategie: Mit Glückssocken zum Erfolg.</p>

<p>Die Shows von Öhler sind gefragt und beliebt. Ist es da nicht schön, wenn wir auch in Europa auf Trialtalente schauen
können und uns nicht nur von Danny MacAskill und Co. ernähren müssen?</p>

<div class="image fit">

<div class="js-reframe" style="position: relative; width: 100%; margin: 0 0 1.33333em;">
	<iframe src="https://www.youtube-nocookie.com/embed/_3FfS5FTah4?feature=oembed" frameborder="0" allowfullscreen=""></iframe>
</div>

</div>

<p>Der Trialbike Weltmeister Thomas Oehler zeigt in diesem Urban Video
sein Können und begeistert u.a. an der Boston University mit weiten Sprüngen und Indoor Tricks.</p>

<h3>Andrew Dickey</h3>

<p>Anfang 2012: Der Trialbike Fahrer Andrew Dickey macht auf seinem schwarz gesprühten Trialbike Melbourne (Australien) unsicher. Der Hammer: reinschauen!</p>

<div class="image fit">

<div class="js-reframe" style="position: relative; width: 100%; margin: 0 0 1.33333em;">
	<iframe src="https://www.youtube-nocookie.com/embed/zJHayGJGc0E?feature=oembed" frameborder="0" allowfullscreen=""></iframe>
</div>

</div>

<h2>Trialbike Hersteller</h2>

<h3>Hoffmanbikes</h3>

<p>Der amerikanische Hersteller von BMX- und Trial-Rädern, Hoffman Bikes, wurde von Mat Hoffman, Jahrgang 1972, gegründet.</p>

<p>Der erfolgreiche BMX-Fahrer machte durch spektakuläre Aktionen in der Halfpipe von sich Reden und zeigt großes Können beim Street Trial.
Er hat an zahlreichen Wettbewerben teilgenommen und brach 1991 den Weltrekord im „Highest Air Vertical Ramp“ auf einer 6,4 Meter-Quarterpipe.
Diesen Erfolg konnte er 2001 mit einer 1 Meter höheren Rampe noch toppen. Aber das ist noch nicht alles. Der „Condor“, wie Mat auch genant wird,
brilliert durch Flugakrobatik mit dem Bike und hat mehr als 100 revolutionäre Tricks erfunden, darunter den „Flair“ (Backflip mit 180 Grad Wende).
Bereits mit 20 Jahren gründete er Hoffman Bikes. Daneben ist Mat Hoffman aber auch für große Stuntshows, Free BMX Events und das Sponsoring von Nachwuchstalenten verantwortlich.
Auch von gebrochenen Beinen lässt er sich nicht abhalten, er ist genauso crazy, wie seine Firma!</p>

<p><strong>Schrill &amp; schräg</strong></p>

<p>Hoffman Bikes ist wirklich schrill und bedient die junge Streetszene mit den eigenen Kompletträdern, Komponenten und ausgefallener Streetwear.
Das erinnert an Grafittikunst, Skaterleben, Aggro, Ninja und Freiheit. Die Serien der Kompletträder tragen passend dazu die klangvollen Namen:
Condor, Aggroman, Evil Ninja sowie Ontic. Die Räder sind mehr, als nur Bike-Spass, denn sie sind zum Teil auch noch mit aufwendigen Grafiken verziert.
Bei Hoffman Bikes gibt es die Bike-Kollektionen bis zurück in das Jahr 2009, dazu eine große Auswahl an Komponenten, wie Lager, Rahmen, Sattel und vieles mehr.</p>

<p>Im Internet findet sich eine kleine, aber feine Anzahl von Shops, über die Hoffman Bikes geordert werden können,
wie z.B. <a href="http://www.chainreactioncycles.com/" target="_blank">www.chainreactioncycles.com</a>.</p>

<p>Die Preise liegen für ein Hoffman Bike zwischen 400 und 800 Euro. Für alle Freerider, die auf abgefahrene Aktionen stehen und das Ausgefallene lieben,
ist <a href="https://hoffmanbikes.com" target="_blank">Hoffman Bikes</a> nicht nur eine Anlaufstelle für Bikes, sondern auch für einen besonderen Lifestyle.</p>

<h3>Inspired Bikes</h3>

<p>Danny McAskill ist das berühmteste Aushängeschild des englischen Bikeherstellers.</p>

<p>Als Teamfahrer von Inspired Bikes ist der Trialstar von den fahrbaren Untersätzen dieser Marke begeistert - kein Wunder,
denn seine Meinung war ausschlaggebend für einen neuen Rahmentyp, den Inspired Bikes auf den Markt gebracht hat.</p>

<p>Gegründet wurde das Unternehmen 2007 von Dave Cleaver, mit der Idee, einen speziellen Rahmen für Trialräder zu konstruieren,
der den hohen Anforderungen an den Street Trial stand hält und ebenso für BMX-Rider ideal ist. Ein „Allroundbike“ sollte damit möglich sein.
Der „Fourplay“ Rahmen, das erste Produkt von Inspired Bikes, war somit geboren. Weiter ging es mit Produkt-Komponenten,
mit denen das individuelle Trialrad für jeden Anspruch perfektioniert werden kann.</p>

<p>Mit dem berühmt-berüchtigten Youtube Video von Danny McAskill erhöhte sich die Nachfrage nach Trialrädern in sehr kurzer Zeit sehr stark.
Darauf reagierte Inspired Bikes und ging auch mit Komplett-Trialrädern (24 Zoll) an den Start.
Das Augenmerk lag dabei auf Kreativität und Styling, kombiniert mit erstklassiger Qualität.
So finden sich vier Varianten im Sortiment der Kompletträder: Hex-Bike und Element-Bike, speziell für Anfänger,
Fourplay Team und Fourplay Pro Bike für Fortgeschrittene und Profis. Natürlich sind auch einzelne Komponenten,
wie Rahmen, Sattel, Bremsen, Lager, in riesengroßer und top-designter Auswahl zu finden.
Die Preise bei den Bikes beginnen bei ca. 1200 Euro und können für ein Profirad auch auf knapp 2000 Euro steigen.
Dafür werden aber nur beste Materialien verbaut und das Design ist auffällig.</p>

<p>Wer mehr erfahren will, kann sich auf der Webseite <a href="http://www.inspiredbicycles.com/">www.inspiredbicycles.com</a> informieren.</p>

<p>Rahmen und Gabel sind aus Aluminium, denn ein leichtes Gewicht ist bei einem Trialrad sehr wichtig.
Mit Komponenten von Trial Tech und Hope Tech Trial (beides namhafte Hersteller für Zubehörteile) wartet beste Ausstattung auf die Trialfans.
Wendigkeit und Kontrolle sowie optimal zu dosierende Bremsen zeichnen die Inspired Bikes aus.
Das neue 2011er Element-Bike ist eine 26 Zoll Version, mit kürzerem Radstand, größerer Laufruhe und geringerem Rollwiderstand.</p>

<h3>Extreme Bike Sports</h3>

<p>Wenn Trialbike Profis sich zusammen tun, dann kommt im besten Fall Extrem Bike Sports dabei heraus.</p>

<p><em><strong>Zweimal Mrohs und einmal Pils bitte</strong></em></p>

<p>So haben es die drei deutschen Bikeprofis Thomas und Matthias Mrohs sowie Rafael Pils getan und mit
<a href="http://www.extreme-bike-sports.de">www.extreme-bike-sports.de </a>eine Plattform gegründet,
auf der sie ihre Erfahrungen und ihr Können, in Form von attraktiven Angeboten, sowohl für Unternehmen,
als auch für Privatleute, weitergeben wollen.</p>

<p>Spektakuläre Bike Shows haben die drei Champions in ihrem geschnürten Paket. Ein Mix aus Bike-Stunts und Unterhaltung.
Dabei wird über Hindernisse am Boden, über Menschen oder so hoch, wie möglich gesprungen. Interviews und Autogrammstunden gibt es obendrauf.
Für Messen und geschäftliche Veranstaltungen ist dies ein besonderer Anreiz, um sich attraktiv und modern zu präsentieren.</p>

<p>Für alle, die das Trial-Bike von der Pike auf lernen wollen, sind die Fahrtechnik-Lehrgänge und das Trial Coaching interessant.
Geschicklichkeit, Gleichgewicht und absolute Radbeherrschung sind das A und O und müssen zuerst gelernt und trainiert werden.
So kann man bei den drei Jungs von den einfachen Basics bis hin zu Wheelings und Sprüngen viel aus der Profiliga lernen.
Auch für bereits begeisterte Fahrer sind Verbesserungen immer von Vorteil. Mit 18 Jahren praktischer Erfahrung im Trialsport,
vielen nationalen und internationalen Titeln sowie Trainerlizenzen haben die Extrembiker jede Menge Qualifikationen vorzuweisen.</p>

<p>Gegründet wurde Extreme Bike Sports von Thomas Mrohs (geb. 1985), der seit 1992 in der Bikesportbranche mit von der Partie ist.
Bereits 2005 gründete er zusammen mit Hauptsponsor Lorenz Hoffmann von Hoffmanbikes das sehr erfolgreiche
Trial Team Hoffmann, das nicht nur in Deutschland für
seine klasse Fahrer bekannt ist. Seit 2009 widmet er sich dem eigenen Projekt.
Thomas möchte auf Entwicklungen im Bikesport eingehen und immer wieder Neues an den Start bringen.
Matthias, der jüngere Bruder von Thomas (geb. 1988) ist ebenfalls dem Trialbike verfallen und kann bereits beachtliche Erfolge,
unter anderem mit 2 Bronzemedaillen bei der MTB und Trail WM in Neuseeland, vorweisen.
Weiter ist er Fahrersprecher beim Bund Deutscher Radfahrer. Raphael Pils ist der Jüngste im Bunde (Jahrhang 1994).
Mit seinen 16 Jahren konnte er schon viele nationale und internationale Titel für sich verzeichnen, so zum Beispiel als Nachwuchsweltmeister in der Klasse U1.</p>

<p>Jetzt leben die Drei ihren Traum und bezeichnen Bike-Trial als Lifestyle - jung, dynamisch und flexibel.
Ihre Aktivitäten zeigen sie nach wie vor im Wettkampf, bei den Bike-Shows oder als Trainer.
Mehr von den Jungs und ihrer „Firma“ unter <a href="http://www.extreme-bike-sports.de">www.extreme-bike-sports.de</a>.</p>

<p>Und wer nach Trialbike Fotos sucht, der sollte sich unbedingt ihren <a href="http://www.flickr.com/photos/extremebikesports/show">Flickr Stream anschauen</a>!</p>

<h3>Onza Bikes</h3>

<p>Der Trialbike Hersteller Onza hat seinen Sitz in England und gehört zu den führenden Unternehmen auf diesem Markt.</p>

<p>Das Sortiment umfasst Bikes für Einsteiger, bis zu den professionellen Fahrern.</p>

<p>Angefangen hat alles Ende der 1980er Jahre in Kaliforniern. Zuerst wurden Lenker für Bikes konzipiert, es folgten weitere Teile für die Trialbikes. 
So entwickelte Onza perfektionierte Komponenten und konnte sich weltweit etablieren. 
Ende der 1990er Jahre wurde das Unternehmen von der Super Cycles Gruppe in Nottingham (England) übernommen, behielt allerdings seine eigenständige Markenbezeichnung.</p>

<p>Onza hat eine große Modellauswahl. Bird, Blade Rip, Zoot, Master und viele mehr. 
Besonders auffällig ist, neben den rein funktionellen Aspekten, auch das Design, welches direkt ins Auge sticht. 
Ziemlich hype und abgefahren, in einer großen Farbenvielfalt. 
Auch die Verarbeitung, unter Verwendung von leichtem Aluminium für Rahmen und Pedalteile sowie hochwertige Bremskonstruktionen zeichnen ein Onza Bike aus. 
Während die Rip-Modelle auf junge Einsteiger abzielen, sind die Bikes aus der Comp und Master Serie für professionelles Fahren gedacht. 
Je nach Bedarf, gibt es Onza Bikes mit oder ohne Sattel. Auch hier fällt wieder das interessante Design mit der Absetzung der Sattelfarbe auf. 
Onza Bikes sind also vom Stylefaktor her für alle, die auffallen wollen, unbedingt angesagt.</p>

<p>Aber auch die technischen Details, wie Hydraulikbremsen, Onza Doppelkäfig Pedale, Aluminiumkurbeln- und Lenker, ausgefräste Steuerrohre und der hochwertige Freilauf sprechen für die Qualität eines Onza Bikes. 
Bei den Reifenstests schneiden die Onza Bikes mit sehr guten Werten ab. Hier sollte sich der interessierte Fahrer von einem Händler beraten lassen, welches Bike für seine Bedürfnisse in Frage kommt. 
Preislich sind Onza Bikes, je nach Typ (Einsteiger- oder Fortgeschrittene), von 500 Euro aufwärts erhältlich. Damit liegen sie im Level der großen Herstellermarken. 
In England gehören die Onza Bikes zur ersten Wahl bei den Wettkampfbikern. Viele Onza Bike Modelle sind auch upgradefähig mit umfangreichem Zubehör und Ersatzteilen.</p>

<h3>Koxx Bikes</h3>

<p>Bikes des französischen Premium-Herstellers Koxx gehören zu den Spitzenrädern für den Trialsport und gehören definitiv
in die Premiumklasse der Trialbike Hersteller.</p>

<p>Wer sich ein Trialbike kaufen will, der sollte sich das große Sortiment von Koxx anschauen.
Neben BMX- und Trialfahrrädern, sind auch Einräder ein weiteres Gebiet von Koxx. Diese werden unter „Koxx One“ vertrieben.
Auch im Motorrad-Trial hat Koxx, mit den Enduros, Markenzeichen gesetzt.</p>

<p>Koxx verfügt über ein eigenes Fahrerteam. Viele Trialbiker, darunter auch der Deutsche Marco Hösler, gehören zu den Stammfahrern.
Koxx ist, wie viele der Bike-Hersteller, aus einem Familienunternehmen entstanden. So fährt der Sohn des Firmengründers Dominique Hermance ebenfalls für die Marke.</p>

<p>Die „Koxx Days“ zählen zu den renommierten Wettbewerben der Szene und werden großartig angenommen.
Ein weiteres Baby ist die „Koxx Academy 124“, die speziell für den Nachwuchs der Trial Szene gedacht ist und hier professionelle Ausbildung und Training bietet.
So hat Koxx an alle Trialer gedacht und kann beste Ausrüstung für jeden Wunsch liefern. Street oder Urbantrial,
Municycle oder Einradtrial – die Bikes sind auf die individuellen Verhältnisse abgestimmt und bieten hohen Komfort.</p>

<p>Koxx Bikes sind ideal für Wettkampffahrer und alle, die ein Leichtgewicht unter sich haben wollen.
Auch für die ganz kleinen Bikestars gibt es Laufräder, mit denen die ersten Schritte in ein erfolgreiches Biker Leben getan werden können.
Koxx gehören zu den erfolgreichsten Trialbike-Herstellern der Welt. Die Modelle unterschieden sich von Einsteiger bis Profi und
haben dementsprechend ihre Modellreihen, wie Aciddrop Foxx, Hydrox usw. Die Sky Serie, in verschiedenen Farben, bietet alles,
was das professionelle Bikerherz begehrt. Diese Teile sind superleicht, besitzen ein hohes Tretlager, Aluminiumrahmen und eine Top-Ausstattung.
Das Aushängeschild unter den Trialbikes ist das Koxx XTP, mit dem auch die Fahrer des Herstellers bestückt werden. Allerdings bekommt bei
Koxx jeder Fahrer sein, eigens auf ihn zugeschnittenes, Koxx Bike.</p>

<p>Koxx Räder sind begehrt und haben einen saftigen Preis. Die Anfänger Bikes für Kinder und Jugendliche liegen zwischen 100 und 500 Euro.
Für den professionellen Biker bewegen sich die Preise zwischen 1500 und über 2000 Euro, je nach Modell.</p>

<h3>Monty Bikes</h3>

<p>Der Name Monty ist allen Trialbikern ein Begriff und selbst Anfänger, die nach guten Trialbikes Ausschau halten, werden schnell mit dem Namen vertraut.</p>

<p>Der spanische Hersteller gilt als Pioneer in der Trialbike-Herstellung und ist ständig am Feilen, Forschen und Verbessern. 
Das große Unternehmen, mit dem einfachen aber wirkungsvollen rot-schwarzen Schriftzug, sitzt seit 25 Jahren in Barcelona. 
Das Familienunternehmen kann selbst einen Star vorweisen: den zwölffachen Trial Weltmeister Ot Pi, Sohn der Firmenchefin.</p>

<p>Die Freude am Sport und die herzliche Atmosphäre spiegeln sich auch in den unterschiedlichen Monty-Modellen wieder. 
Hauptmerkmale des Sortiments sind die Kamel- Bikes, die es in verschiedenen Ausführungen gibt. 
Auch das Laufrad für die kleinsten Trialer sowie das Unicycle Einrad sind erhältlich.</p>

<p>Bei Monty sind die Modellbezeichnungen gleich entsprechend den Altersgruppen, für die das Bike konzipiert ist. 
So steht Monty 202 für das Laufrad ab einem Alter von 2 Jahren. Es folgen das 205 und das 207. 
Dann gibt es einen Sprung zum 218er Bike, das zu den meistverkauften seiner Klasse gehört und mit dem sich auch schon Wettbewerbsdisziplinen bewältigen lassen. 
Richtig spannend wird es dann ab Modell 220. Mit diesem 20 Zoll Rad ist man bestens für den Wettbewerbstrial gerüstet.</p>

<p>Monty Räder sind leicht, was die Verarbeitung von Aluminium immer wieder beweist. 
Ständige Optimierung der Rahmen, um Stöße besser abzufedern und Verbesserungen an Bremsen und Lagern, gehören ebenfalls zu der Monty Motivation. 
Farblich kann man sich auch nicht beklagen, denn vom stylischen Rot über Edelschwarz bis hin zu Reinweiß ist alles dabei.</p>

<p>Bei Monty steigt mit dem Alter auch der Preis. 
Während das Kleinkind Laufrad noch für schlappe 140 Euro zu bekommen ist, kalkuliert man bei den Trialbikes für Wettbewerbe gleich schon mal über 1000 Euro ein. 
Nun ja Qualität hat ihren Preis. Und ehrlich gesagt: der Sport ist ganz und gar nicht ungefährlich und da ist eine Investition in Sicherheit und Fahrtauglichkeit das Beste, was ein Biker tun kann. 
Alleine schon seinem Leben zu liebe.</p>

<p>Natürlich hat Monty auch ein riesiges Zubehör- und Ersatzteil Arsenal und Bike Klamotten.</p>

<p>Wie zu jedem guten Hersteller gehören natürlich auch zu Monty Stammfahrer und Sponsoring. 
Bei Monty stammt das Aushängeschild deluxe noch aus der eigenen Familie – was will man mehr?</p>

<h2>Weitere Angebote der Trialbike-Szene</h2>

<h3>Hans Rey &amp; das Adventure Team</h3>

<p>Hans Rey, der Godfather of Trial Bike, ist ein Kultfaktor der Szene.
Er ist das, was Rainer Langhans und Uschi Obermaier für die Kommune 1 oder Mick Jagger in der Musik sind.
Diese Leute altern anscheinend nicht. Sie haben unverwechselbare Merkmale, sei es die Einstellung, die Mähne, die Schönheit oder aber,
wie bei Hans Rey, Baujahr 1966, das Talent, aus zwei Rädern alles rauszuholen, was nur geht.
Als weltweiter Trial Champion,
mit unzähligen Siegen und verewigt in der Mountain Bike Hall of Fame,
hat sich Hans „No Way Rey“ einen Traum erfüllt, von dem Millionen Biker träumen.
Sein Leben ist zum Abenteuer geworden und das beweist er mit dem Hans Rey Adventure Team.</p>

<p>Extrem-Sport an den schönsten und aufregendsten Fleckchen der Erde ist das Motto des
Hans Rey Adventure Teams, das einst von Hans ins Leben gerufen wurde,
um Sport, Abenteuer und die Erfahrung der eigenen Grenzen zu vereinen.
Aber auch der kulturelle Aspekt fehlt nicht. Denn wer schon quer um den Erdball reist, der nimmt viel mit von den
Einheimischen und den Naturwundern, die sich präsentieren. Hans Rey ist eigentlich das einzige ständige Mitglied des Teams,
das aus Athleten, Fotografen und Filmemachern besteht, die aber ständig wechseln. Mit ihnen gemeinsam nimmt er immer
wieder einzigartige und herausfordernde Ziele in Angriff, um Inseln und Länder mit dem Bike zu erkunden.</p>

<p>Ägypten, Mexiko, Nepal, Tansania, Kuba, Brasilien, Jamaika, Peru sind nur einige Stationen der vergangenen Abenteuer,
die Hans und sein Team erlebt haben. Die Vielfalt der Kulturen, die fulminanten Landschaften und die
Naturschauspiele werden mit den herausragenden Trial-Aktionen zu einer Einheit.
In Schrift, Bild, Wort und auf Film gebannt, wird alles für die interessierten Fans und Zuschauer dokumentiert. 
So sind im Laufe der Zeit wertvolle Beiträge entstanden, die mehr sind, 
als nur Extrem-Trial mit Sprüngen über Bergspalten oder High-Speed-Abfahrten, gespickt mit riskanten Hindernissen.</p>

<p>Wenn Hans mit den Einheimischen der Stammesvölker einen Plausch hält,
mit den wilden Tieren des Dschungels auf Du und Du ist oder wenn er sich in die tobenden Wasserfälle stürzt,
dann sind bekannte Sportler, auch aus der Bike-Szene, an seiner Seite. Steve Peat
oder Danny McAskill lieben es, mit Hans einen Trial-Trip zu wagen,
wie im Mai 2010, als sie gemeinsam auf großer Schottland Tour waren.
Und es gilt, noch viele, weitere Ziele zu erkunden, denn Hans ist noch lange nicht müde…</p>

<h3>Trial-Park Rottenburg</h3>

<p>Trialbike von der Pike auf lernen - Ex-Weltmeister Mesick bietet kostenlos Training im neuen Trial-Park in Rottenburg/Baden-Württemberg an.</p>

<p>Trial Bike wird jetzt in Rottenburg, im Sportpark 1861, ganz groß geschrieben. 
Kürzlich wurde der neue Trial-Park eröffnet.</p>

<p>Der Sportpark 1861 ist seit jeher ein Anziehungspunkt, für alle die sich bewegen wollen. 
Und auch den neuen Trends im Sport stehen die Verantwortlichen hier sehr positiv gegenüber. 
Unterstützung bekamen sie dabei von einem, der es wissen muss: 
Der ehemalige Trial Weltmeister Michael Mesick (UCI Mountainbikes WM &amp; Trials, 20 Zoll, 1997, Frankreich) gehört zu den Mitinitiatoren des neuen Trial Parcours und wird hier kostenlose Trainingsstunden geben. 
Das Gelände wurde von ihm mitkonzipiert und ist optimal ausgerichtet, um die jungen Radkünstler auch auf Meisterschaften vorzubereiten.</p>

<p>Der Sportpark 1861 gehört zum Turnverein Rottenburg, der mit großem Engagement bei der Sache ist. 
Norbert Vollmer, Geschäftsführer des TV Rottenburg freute sich, dass der Trial Park nun allen Interessierten die Möglichkeit bietet, diese Sportart zu lernen und zu trainieren. 
Jeden Samstag werden von 14-17 Uhr die kostenlosen Trainingszeiten, unter der fachkundigen Betreuung von Michael Mesick, stattfinden.</p>

<p>Bei der Einweihung ließ Mesick es sich nicht nehmen, dem zahlreich erschienenen und vor allen Dingen auch sehr jungen Publikum die Sportart Trial Biking vorzustellen.</p>

<p>Der Trial Park besteht überwiegend aus Betonblöcken und Betonröhren sowie Holzpaletten, die für kleines Geld von umliegenden Firmen erworben wurden. 
Anfänger, wie auch Weltklassefahrer können im neuen Trial Gelände ihr sportliches Talent unter Beweis stellen. 
Michael Mesick erklärte:„Wichtig war bei der Realisierung des Parcours, dass die Hindernisse pflegeleicht sind und lange erhalten bleiben, daher wurde überwiegend Beton ausgesucht. 
Die runden Formen reduzieren die Verletzungsgefahr“. Der gebürtige Tübinger wird den Trialpark mit seinen Erfahrungen betreuen.</p>

<p>Zeit, Fleiß und Geduld müssen die angehenden Trialer mitbringen. 
Für Neulinge geht es erst einmal mit Slaloms und engen Parcours los, später werden dann Stufen gefahren. 
Die Steigerung erfolgt kontinuierlich. 
Langfristiges Ziel wird es sein, dass Jugendliche den Park selbst verwalten.</p>

<p>Helm ist Pflicht. Sollte aber dennoch mal was passieren, so sind die Trialer über den Turnverein mitversichert. 
So können auch Nichtmitglieder jederzeit dem Sport nachgehen.</p>

<p>Der Trialpark kann das ganze Jahr über genutzt werden. Training findet samstags immer statt, außer bei Schnee und Hagel. 
So viel Extrem muss dann doch nicht sein. Und wer kein eigenes Trial Bike hat, der muss dennoch nicht auf Fun verzichten. 
Passende Trial Räder können beim Turnverein ausgeliehen werden. 
Auch mit dem Einrad ist der Parcours zu fahren.</p>

<h3>Trialbike in Deutschland</h3>

<p>England, Schottland oder Europa sind bedeutend, was den Trial Sport angeht.
In Deutschland ist diese Disziplin zwar etabliert, aber es könnte durchaus noch besser sein.</p>

<p>Einzelkämpfer sind u.a. Marco Hösler oder Dominik Raab, die Aufsehen erregen und unter den deutschen Fahrern zu finden sind.
Anders dagegen im Teamsport. Da sieht es auf deutscher Ebene schon gut aus.
Das Trial Team Hoffmann setzt hier neue Aspekte und ist besonders für den talentierten Nachwuchs ein bedeutendes Aushängeschild.
Hier kommen die besten Trialer Deutschlands zusammen. Neben Wettbewerben werden auch Shows gefahren.</p>

<p>Das Trial Team Hoffmann verfolgt das Ziel,
jugendliche Trialfahrer zu fördern und Ihnen die Möglichkeit zu geben, aus ihrem Hobby auch eine Passion zu machen.
Daher ist das Alter der Teammitglieder auch entsprechend jung angesetzt. Die Fahrer sind zwischen 10 und 23 Jahre alt.
Zudem ist die Firma Hoffmannbikes führend, was den Trialrahmenbau in Deutschland angeht und gehört mit zu den bedeutenden Herstellern der Welt.
Ideale Voraussetzungen also, um so ein Team aufzustellen.
Im Trialsport zählt das Team Hoffmann zu den besten in Deutschland und alle Fahrer sind ebenfalls in der Nationalmannschaft oder im Nationalkader vertreten.</p>

<p>Als Trainer der Trialnationalmannschaft fungiert Martin Engelhart.
Als einstiger Wettstreiter von Hans Rey weiß er,
worauf es ankommt und kennt sich bestens aus.
Zehnmal konnte das Team bisher den Deutschen Meistertitel holen.
Doch damit nicht genug. Auch die internationalen Erfolge lassen sich sehen.
Gold, Silber, Bronze - alle Medaillen sind in unterschiedlichen Klassifizierungen vertreten.</p>

<p>Der erfolgreichste Trialer im Team heißt Sebastian Hoffmann.
Der 24-Jährige ist seit 1996 im Trialsport aktiv und wurde 2008 Deutscher Meister der Elite 26´´.
Die Jungs sind auch weiter fleißig im Medaillen kassieren und setzen mit ihren Shows Höhepunkte für die berauschende Kunst auf zwei Rädern.</p>

<p>Workshops und Trainingsmodule werden vom Team ebenso angeboten.
Durch die qualifizierten Trainer wird hier, mit modernen Methoden, das eigene Fahrverhalten dokumentiert und analysiert.</p>

<p>Nicht jedes Land kann einen Danny MacAskill oder Steve Peat haben, aber es kann viel dafür getan werden.
Wichtig ist, dass der Sport aus seiner Randnische des Hobbys in Deutschland herauskommt.</p>

<h3>Trial Bike Park Adventure Camp Osttirol</h3>

<p>Der neue Trial-Bike-Park Osttirol wurde am 30.08.2015 im feierlichen Rahmen eröffnet und ist für alle Trial Biker, Street Trial’er sowie begeisterte Bikern dieser Sportart verfügbar.</p>

<div class="gallery">
	
	<div class="gallery_images">
        
<figure class="caption">
	<img src="/images/trialbike/IMG_0414.jpg" alt="Bild zur Verfügung gestellt von M. Wibmer / Alle Rechte liegen bei www.ota.at" />
    <figcaption class="caption-text">Bild zur Verfügung gestellt von M. Wibmer / Alle Rechte liegen bei www.ota.at</figcaption>
</figure>

		
	</div>
</div>

<blockquote>Wir möchten mit diesem Bikepark und der Eröffnung dieser einzigartigen Anlage, den Trial Bike und Street Trial Sport eine neue Dimension verpassen und freuen uns auf viele Besucher aus dem Inn und Ausland.
Nur wenn wir ein geschloßenes Bild des Bikesports und einen Mix aus Jung und alt erreichen,hat sich unser Einsatz gelohnt.Es folgen in den kommenden Jahren intern.Wettbewerbe, Bikeshows, Bikeausstellungen sowie Workshops, Trainingslager uvm.<br />
Der Bikepark bietet für Kinder mit Laufrädern bis hin zum perfekten Fahrer alles was das Herz begehrt.
Besonders freuen würden wir uns über Vereine, Clubs und sonstige Gruppen des Bikesports.<br />
Es besteht die Möglichkeit nach vorheriger Absprache und Anmeldung,dass sich Vereine und deren Fahrer vorstellen und Ihr Können einem breiten Publikum präsentieren zu können.</blockquote>

<div class="gallery">
	
	<div class="gallery_images">
        
<figure class="caption">
	<img src="/images/trialbike/IMG_0392.jpg" alt="Bild zur Verfügung gestellt von M. Wibmer / Alle Rechte liegen bei www.ota.at" />
    <figcaption class="caption-text">Bild zur Verfügung gestellt von M. Wibmer / Alle Rechte liegen bei www.ota.at</figcaption>
</figure>

		
	</div>
</div>

<p>Weitere Informationen gibt es auch unter <a href="http://www.ota.at">www.ota.at</a>.</p>]]></content><author><name>Kevin Papst</name><email>kevin@kevinpapst.de</email></author><category term="Persönliches" /><summary type="html"><![CDATA[Fahrradtrial: Trialbikes und Street/Trial Bikes - der Balanceakt mit dem Rad über Felsen und Baumstämme, auf Paletten und über Balken]]></summary></entry><entry><title type="html">Refreshing single template twig cache in production</title><link href="https://www.kevinpapst.de/blog/refresh-twig-template-cache.html" rel="alternate" type="text/html" title="Refreshing single template twig cache in production" /><published>2023-10-02T08:00:00+00:00</published><updated>2023-10-02T08:00:00+00:00</updated><id>https://www.kevinpapst.de/blog/refresh-twig-template-cache</id><content type="html" xml:base="https://www.kevinpapst.de/blog/refresh-twig-template-cache.html"><![CDATA[<p>If you have a PHP application that handles dynamic Twig templates, which can be changed by a user, you have most likely already stumbled upon the question:</p>

<blockquote>
  <p>How can I delete the template cache in production, without flushing my entire cache?</p>
</blockquote>

<p>I hope a search engine brought you here, because I have an answer, which I wasn’t able to find on Stackoverflow or anywhere else.</p>

<p>For some reason, Twig has no documentation about that issue and the ways to achieve it are rather hidden.</p>

<h2>Using Twig cache and environment</h2>

<p>Interacting with the cache directly and using the <code class="language-plaintext highlighter-rouge">@internal Environment::getTemplateClass()</code> method feels more than just a little hacky:</p>

<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$twigCache</span> <span class="o">=</span> <span class="nv">$twig</span><span class="o">-&gt;</span><span class="nf">getCache</span><span class="p">(</span><span class="kc">false</span><span class="p">);</span>

<span class="nv">$twigCache</span><span class="o">-&gt;</span><span class="nf">write</span><span class="p">(</span>
    <span class="nv">$twigCache</span><span class="o">-&gt;</span><span class="nf">generateKey</span><span class="p">(</span><span class="nv">$templateName</span><span class="p">,</span> <span class="nv">$twig</span><span class="o">-&gt;</span><span class="nf">getTemplateClass</span><span class="p">(</span><span class="nv">$templateName</span><span class="p">)),</span>
    <span class="nv">$twig</span><span class="o">-&gt;</span><span class="nf">compileSource</span><span class="p">(</span><span class="nv">$twig</span><span class="o">-&gt;</span><span class="nf">getLoader</span><span class="p">()</span><span class="o">-&gt;</span><span class="nf">getSourceContext</span><span class="p">(</span><span class="nv">$templateName</span><span class="p">))</span>
<span class="p">);</span>
</code></pre></div></div>

<p>And the big question is really:</p>

<blockquote>
  <p>Why isn’t there a simple <code class="language-plaintext highlighter-rouge">Environment::refreshCache(string $templateName)</code> method?</p>
</blockquote>

<p>Unfortunately I don’t have an answer. But I have another, even better solution …</p>

<h2>Auto reloading your Twig template</h2>

<p>After too much try &amp; error, I started reading the twig source-code to find out how it is using the cache internally and stumbled upon a method that looked promising: <code class="language-plaintext highlighter-rouge">Environment::enableAutoReload()</code>.</p>

<p>Obviously we don’t activate it blindly and cause a performance bottleneck in production, but we can utilize it to refresh our template. 
You know when your Twig template was changed and the cache needs to be reloaded, right? So at that moment you can do this:</p>
<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="nv">$twig</span><span class="o">-&gt;</span><span class="nf">enableAutoReload</span><span class="p">();</span>
    <span class="nv">$twig</span><span class="o">-&gt;</span><span class="nf">load</span><span class="p">(</span><span class="s1">'@bundle/'</span> <span class="mf">.</span> <span class="nb">basename</span><span class="p">(</span><span class="nv">$template</span><span class="o">-&gt;</span><span class="nf">getFilename</span><span class="p">()));</span>
    <span class="nv">$twig</span><span class="o">-&gt;</span><span class="nf">disableAutoReload</span><span class="p">();</span>
</code></pre></div></div>
<p>All you need to do is: pass in the correct filename (and possibly bundle identifier) used by your Twig loader.</p>

<p>Using this method of reloading the Twig template cache in production is working pretty well for me and I haven’t seen any side effects yet. 
But I haven’t used that approach on high traffic websites, so I can’t guarantee that there won’t be any race conditions.</p>]]></content><author><name>Kevin Papst</name><email>kevin@kevinpapst.de</email></author><category term="Programmierung" /><summary type="html"><![CDATA[Ever wondered how to reload a twig template in production, without pruning the entire cache? Here is how to do it.]]></summary></entry><entry><title type="html">Warum ich keinen Verhaltenskodex unterschreibe</title><link href="https://www.kevinpapst.de/blog/verhaltenskodex-unerwuenscht.html" rel="alternate" type="text/html" title="Warum ich keinen Verhaltenskodex unterschreibe" /><published>2021-06-24T14:00:00+00:00</published><updated>2021-06-24T14:00:00+00:00</updated><id>https://www.kevinpapst.de/blog/verhaltenskodex-unerwuenscht</id><content type="html" xml:base="https://www.kevinpapst.de/blog/verhaltenskodex-unerwuenscht.html"><![CDATA[<p>Es kommt immer wieder mal vor, das ein potenzieller Kunde schon vor dem ersten Gespräch unterzeichnete Dokumente von mir 
sehen möchte. Dokumente wie ein NDA (Non disclosure agreement – Vertraulichkeitserklärung) finde ich dabei völlig okay, 
auch wenn ich es vor dem ersten Gespräch für überzogen halte, aber das ist ein anderes Thema.</p>

<p>Dann wiederum gibt es ab und an Anfragen von Interessenten, die mir Ihren Verhaltenskodex zur Unterschrift zusenden.
Wer das nicht kennt: ein Verhaltenskodex umfasst freiwillige Erklärungen zum eigenen Geschäftsverhalten, 
wo Dinge angesprochen werden wie:</p>

<ul>
  <li>Geschäftsverhalten
    <ul>
      <li>Einhaltung von Gesetzen</li>
      <li>Verbot von Korruption und Bestechung</li>
      <li>Achtung von Wettbewerb und Eigentumsrechten</li>
    </ul>
  </li>
  <li>Umgang mit Mitarbeitern
    <ul>
      <li>Ächtung von Diskriminierung, Belästigung, Zwangsarbeit, Kinderarbeit</li>
      <li>Angemessene Entlohnung</li>
      <li>Arbeitssicherheit</li>
    </ul>
  </li>
  <li>Umweltschutz &amp; Nachhaltigkeit (Fucking Buzzword 2021)</li>
</ul>

<p>Nun spricht natürlich nichts gegen diese Punkte (oben ist nur eine Beispielliste) und ich halte das inhaltlich
auch für richtig, welcher gesunde Mensch würde einen der Punkte ablehnen (ich sag nur unbezahlte Praktika)?</p>

<p>Nein, mein Problem ist, dass es überhaupt nichts mit dem eigentlichen Auftragsthema zu tun hat.
Hier wird primär versucht, Einfluss auf das Verhalten von Geschäftspartnern auszuüben.</p>

<blockquote>
  <p>Der Dienstleister erklärt mit seiner Unterschrift, dass er den Verhaltenskodex für Dienstleister erhalten hat. 
Er verpflichtet sich, die vorstehenden Grundsätze und Regelungen anzuerkennen und einzuhalten.</p>
</blockquote>

<p>Kommen wir zum Kernpunkt meiner Ablehnung. Von den potenziellen Kunden wird vorausgesetzt, dass Ihr Verhaltenskodex angenommen wird.
Es liegt in der Autonomie meiner Kunden so einen Verhaltenskodex auszugeben, aber gleichzeitig wird durch einen (beinahe) Kontrahierungszwang 
meine Privat- bzw. Geschäftsautonomie in Frage gestellt. Denn der Zwang zur Unterschrift ist gleichzeitig der einzige Weg den Auftrag zu erlangen.
Und das, bevor überhaupt das erste Gespräch stattgefunden hat.</p>

<p>Auch wenn ich inhaltlich mit allen Punkte übereinstimme, ich unterschreibe sowas grundsätzlich nicht.
Ob es nun ein Code of Conduct von Open Source Communities ist, oder ein Verhaltenskodex eines Kunden – sofern da 
mehr als “Sei kein Arsch” drin steht, bekommt es von mir kein OK.</p>

<p>Nun bin ich in der luxuriösen Position viel mehr Anfragen zu haben, als Zeit diese umzusetzen und kann so auch mit ruhigem 
Gewissen einfach “Nein” sagen. Aber Dienstleister, die nicht über so eine (finanzielle) Freiheit verfügen? 
Pervertiert das vielleicht die gute Absicht?</p>

<blockquote>
  <p>Der Dienstleister erklärt und verpflichtet sich außerdem, die vorstehenden Grundsätze und Regelungen auch bei seinen 
Subunternehmern und Lieferanten / Dienstleistern einzufordern und deren Einhaltung zu gewährleisten.</p>
</blockquote>

<p>Es wird versucht, einen (vermeintlich) abhängigen Dienstleister den eigenen “Image-freundlichen Verhaltenskodex” aufzuoktroyieren. 
Ich unterstelle hier zwar erstmal eine gute Absicht, aber der Weg dahin gefällt mir überhaupt nicht. Wenn dann auch noch mit 
dieser <em>überlegenen Weltretter</em> Einstellung des Unternehmens geworben wird, dann ist für mich ganz schnell die Grenze des
Greenwashings überschritten. Vermeintliche moralische Überlegenheit.</p>

<p>Dabei ist der größte Witz, dass dieser Verhaltenskodex nur den “kleinen Geschäftspartnern” vorgelegt wird.
Reden wir über den Email- oder Cloudanbieter (Google, Apple, Microsoft), über den Anbieter den Telefon- und Internetzugangs,
über den Mobilfunkanbieter, über den Hersteller der Handys – reden wir über die Hersteller der Akkutechnologien in den genutzten Laptops oder
auch einfach nur über den Kaffeehändler. Werden Geschäfte mit diesen gemacht, ohne sie zu der Unterschrift zu zwingen?
Natürlich nutzt man deren Dienste. Und DAS ist Heuchelei. Denn es sind es doch gerade die großen, 
die überhaupt den Einfluß hätten, tatsächlich etwas zu bewirken.</p>

<p>Ich kann, aber ich will auch niemanden kontrollieren oder ihm Regeln aufzwingen. Liegt nicht in meiner Natur. 
Es gibt Anbieter, die würde sowas unterschreiben und den Inhalt einfach ignorieren, und es gibt Menschen die Ihren Teil zum 
positiven Wandel unserer Welt auf andere Weise beitragen. Die etwas Gutes bewirken, ganz ohne Kodex.
Und genauso wie man dem Kaffeehändler das “FairTrade” Label glaubt, so kann man auch erstmal mit mir reden, 
ohne mir so ein Dokument aufzuzwingen. Ich bin ein Freund mündlicher Absprachen, von Vertrauen und gegenseitigem Respekt.</p>

<p>Einem Interessenten der mir schrieb:</p>

<blockquote>
  <p>Es geht ja grade darum einerseits verantwortungsvolles Handeln zu unterstützen, und andererseits Firmen/Personen, 
die gegen so grundlegende Prinzipien verstossen, zu sanktionieren.</p>
</blockquote>

<p>habe ich geantwortet:</p>

<blockquote>
  <p>Tue ich aber nicht, ich verstoße nicht dagegen. 
Es ist grotesk, dass daran festzumachen, ob sich jemand durch Zwang zu einer Unterschrift drängen lässt. 
Kein gesunder Mensch kann etwas gegen die einzelnen Punkte im Dokument haben (bis ihm die richtige Summe geboten wird und 
die Bestechung selbstverständlich annimmt). 
Ich lasse mich nur nicht zu einer Unterschrift unter einem Dokument zwingen, das nichts mit dem eigentlichen Thema zu tun 
hat und dessen Abschlußsatz mir sowieso unmöglich ist einzuhalten.</p>
</blockquote>

<p>Wie erwartet, hat die Verweigerung der Unterschrift des Verhaltenskodex dazu geführt, 
dass die Kommunikation abgebrochen und kein Geschäftskontakt aufgebaut wurde. Und nein, das lag nicht am Ton 😃</p>

<p>Ich kann nur vermuten, dass diese Unternehmen auf ihren Prozess mehr Wert legen, als auf den Inhalt. 
Wenn ich inhaltlich in allem zustimme, aber nicht über die Marktmacht verfüge bestimmte Punkte zu beeinflussen und daher 
eine Verpflichtung nicht unterzeichnen will, dafür dann aber “sanktioniert” werde, dann sieht das für mich so aus, als ob 
der Kunde mir Lügen und eben jenes Verhalten unterstellt. Was auch für mich keine Grundlage für eine Geschäftsbeziehung darstellt.</p>

<h3>Abschlusswort</h3>

<p>Es ist zwar schade, das Sie mich unter diesen Umständen nicht als Dienstleister wollen, aber ich freue mich dennoch, 
wenn Sie meine kostenlose und vollständig freie Zeiterfassungs-Software Kimai nutzen. 
Und denken Sie dabei nochmal kurz an Ihren eigenen Verhaltenskodex und den Punkt “Angemessene Entlohnung” 👿</p>]]></content><author><name>Kevin Papst</name><email>kevin@kevinpapst.de</email></author><category term="Persönliches" /><summary type="html"><![CDATA[Es kommt immer wieder mal vor, das ein potenzieller Kunde schon vor dem ersten Gespräch unterzeichnete Dokumente von mir sehen möchte. Dokumente wie ein NDA (Non disclosure agreement – Vertraulichkeitserklärung) finde ich dabei völlig okay, auch wenn ich es vor dem ersten Gespräch für überzogen halte, aber das ist ein anderes Thema.]]></summary></entry><entry><title type="html">Letsencrypt - Expected cert.pem to be a symlink</title><link href="https://www.kevinpapst.de/blog/fix-letsencrypt-cert-pem-symlink.html" rel="alternate" type="text/html" title="Letsencrypt - Expected cert.pem to be a symlink" /><published>2021-01-26T08:00:00+00:00</published><updated>2021-01-26T08:00:00+00:00</updated><id>https://www.kevinpapst.de/blog/fix-letsencrypt-cert-pem-symlink</id><content type="html" xml:base="https://www.kevinpapst.de/blog/fix-letsencrypt-cert-pem-symlink.html"><![CDATA[<p>Ein kleiner Quickie für meine eigenen Tipps &amp; Tricks Box, falls mir das Problem nochmal passieren sollte.</p>

<p>Ich habe mal wieder einen Server migriert und dabei auch das Letsencrypt Verzeichnis aus <code class="language-plaintext highlighter-rouge">/etc/letsencrypt/</code> mitgenommen.
Irgendwo in dem Prozess scheint ein <code class="language-plaintext highlighter-rouge">cp -r</code> oder <code class="language-plaintext highlighter-rouge">rsync</code> vorhandene Symlinks aufgelöst und daraus Dateien gemacht zu haben.
Oder die alte Letsencrypt Version war veraltet … lässt sich leider nicht mehr verifizieren, da der vorherige Server nicht mehr verfügbar ist.</p>

<p>Beim Setup des Webservers ist nichts aufgefallen und auch <code class="language-plaintext highlighter-rouge">certbot</code> ließ sich ohne Murren installieren.
Auch ein Test des Befehls <code class="language-plaintext highlighter-rouge">test -x /usr/bin/certbot -a \! -d /run/systemd/system &amp;&amp; perl -e 'sleep int(rand(43200))' &amp;&amp; certbot -q renew</code> 
aus dem Cronjob <code class="language-plaintext highlighter-rouge">/etc/cron.d/certbot</code> hat keine Fehlermeldung zutage gebracht.</p>

<blockquote>
  <p>An der Stelle fällt dem geneigten Leser auf, wieso ich den gesamten Befehl kopiert habe: JA, ich habe das -q übersehen</p>
</blockquote>

<p>Ein paar Wochen nach dem Setup des Servers bekam ich vom <strong>Let’s Encrypt Expiry Bot</strong> eine typische Expiry-Email mit dem Titel <strong>Let’s Encrypt certificate expiration notice for domain “example.com”</strong>.<br />
Randnotiz: wieder mal hat sich bewiesen, dass es sich lohnt die Email Adresse bei der Ausstellung des Zertifikats anzugeben.</p>

<h2>Logfile und Fehler</h2>

<p>Die Email war ein Weckruf und nach einer kurzen Recherche auf dem Server kam das Logfile <code class="language-plaintext highlighter-rouge">/var/log/letsencrypt/letsencrypt.log</code> zu Tage und 
eine Kontrolle eben jenes die Fehlermeldung:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>DEBUG:certbot.main:certbot version: 0.40.0
DEBUG:certbot.main:Arguments: ['-q']
DEBUG:certbot.main:Discovered plugins: PluginsRegistry(PluginEntryPoint#manual,PluginEntryPoint#nginx,PluginEntryPoint#null,PluginEntryPoint#standalone,PluginEntryPoint#webroot)
DEBUG:certbot.log:Root logging level set at 30
INFO:certbot.log:Saving debug log to /var/log/letsencrypt/letsencrypt.log
WARNING:certbot.renewal:
Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/certbot/renewal.py", line 65, in _reconstitute
    renewal_candidate = storage.RenewableCert(full_path, config)
  File "/usr/lib/python3/dist-packages/certbot/storage.py", line 465, in __init__
    self._check_symlinks()
  File "/usr/lib/python3/dist-packages/certbot/storage.py", line 522, in _check_symlinks
    raise errors.CertStorageError(
certbot.errors.CertStorageError: expected /etc/letsencrypt/live/example.com/cert.pem to be a symlink
2021-01-24 11:24:27,110:WARNING:certbot.renewal:Renewal configuration file /etc/letsencrypt/renewal/example.com.conf is broken. Skipping.
2021-01-24 11:24:27,110:DEBUG:certbot.renewal:Traceback was:
Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/certbot/renewal.py", line 65, in _reconstitute
    renewal_candidate = storage.RenewableCert(full_path, config)
  File "/usr/lib/python3/dist-packages/certbot/storage.py", line 465, in __init__
    self._check_symlinks()
  File "/usr/lib/python3/dist-packages/certbot/storage.py", line 522, in _check_symlinks
    raise errors.CertStorageError(
certbot.errors.CertStorageError: expected /etc/letsencrypt/live/example.com/cert.pem to be a symlink

DEBUG:certbot.log:Exiting abnormally:
Traceback (most recent call last):
  File "/usr/bin/certbot", line 11, in &lt;module&gt;
    load_entry_point('certbot==0.40.0', 'console_scripts', 'certbot')()
  File "/usr/lib/python3/dist-packages/certbot/main.py", line 1382, in main
    return config.func(config, plugins)
  File "/usr/lib/python3/dist-packages/certbot/main.py", line 1287, in renew
    renewal.handle_renewal_request(config)
  File "/usr/lib/python3/dist-packages/certbot/renewal.py", line 486, in handle_renewal_request
    raise errors.Error("{0} renew failure(s), {1} parse failure(s)".format(
certbot.errors.Error: 0 renew failure(s), 1 parse failure(s) 
</code></pre></div></div>

<p>Hervorzuheben ist der relevante Fehler:</p>

<blockquote>
  <p>Renewal configuration file /etc/letsencrypt/renewal/example.com.conf is broken. Skipping</p>
</blockquote>

<p>Was aber nur ein Folgefehler ist des Problems:</p>

<blockquote>
  <p>certbot.errors.CertStorageError: expected /etc/letsencrypt/live/example.com/cert.pem to be a symlink</p>
</blockquote>

<p>Jetzt könnte man hingehen und aus den echten Dateien wieder Symlinks machen, welche in das Verzeichnis <code class="language-plaintext highlighter-rouge">/etc/letsencrypt/archive/example.com/</code> 
und dort auf die höchste durchnummerierte <code class="language-plaintext highlighter-rouge">certX.pem</code> Datei zeigen.
Falls Du die Lösung bevorzugst, verifizieren lässt sich das Setup im Anschluss mit <code class="language-plaintext highlighter-rouge">certbot update_symlinks</code>.</p>

<h2>Meine Lösung</h2>

<p>Einfacher ist den folgenden Befehl zu nutzen um alles loszuwerden:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rm -rf /etc/letsencrypt/{live,renewal,archive}/{example.com,example.com.conf}
</code></pre></div></div>

<p>Siehe auch <a href="https://community.letsencrypt.org/t/correct-way-to-completely-remove-issued-certificate-s-for-a-domain/7409/30">hier</a>.</p>

<p>Danach nutzt Du den von Dir bevorzugten Weg, um die Zertifikate neu auszustellen.
Das könnte sowas sein wie <code class="language-plaintext highlighter-rouge">certbot nginx</code> oder <code class="language-plaintext highlighter-rouge">certbot apache</code> oder <code class="language-plaintext highlighter-rouge">certbot certonly --webroot -w /var/www/example.com -d example.com</code>.</p>

<blockquote>
  <p>P.S: Ja, rabiat aber funktional. Aber denk dran: es existiert ein hartes Limit, wie oft man seine Zertifikate 
in einem bestimmten Zeitraum komplett neu ausstellen lassen kann.</p>
</blockquote>]]></content><author><name>Kevin Papst</name><email>kevin@kevinpapst.de</email></author><category term="DevOps" /><summary type="html"><![CDATA[Ein kleiner Quickie für meine eigenen Tipps &amp; Tricks Box, falls mir das Problem nochmal passieren sollte.]]></summary></entry><entry><title type="html">NumberFormatter - Currency formats made easy</title><link href="https://www.kevinpapst.de/blog/php-numberformatter-currency.html" rel="alternate" type="text/html" title="NumberFormatter - Currency formats made easy" /><published>2020-08-29T08:30:00+00:00</published><updated>2020-08-29T08:30:00+00:00</updated><id>https://www.kevinpapst.de/blog/php-numberformatter-currency</id><content type="html" xml:base="https://www.kevinpapst.de/blog/php-numberformatter-currency.html"><![CDATA[<p>Jedem der schon mal näheren Kontakt mit dem NumberFormatter in internationalisierten Projekten hatte, 
dürfte der leichte Sarkasmus im Titel aufgefallen sein. Dies ist mein persönlicher “Rant” über die Implementation, 
aber um konstruktiv zu bleiben auch ein paar funktionierende Beispiele.</p>

<p>Wieso? Insbesondere bei der Formatierung von Währungen gibt es einige Stolpersteine. Einige davon habe ich gefunden,
während ich auf der Suche nach einer Lösung war, die hoffentlich auch auf allen OS und PHP Versionen läuft. 
Und da meine <a href="https://www.kimai.org">Zeiterfassung Kimai</a> die Anzeige von 
monetären Werten (mit und ohne Währung) benötigt, durfte ich mich ein wenig mit der Umsetzung herumschlagen. 
Man sollte meinen das 2020 die Anzeige von Geld eine Trivialität darstellt, nachdem die LowLevel APIs hierfür schon vor 
langer Zeit fertiggestellt wurden.</p>

<p>Aber: der Teufel steckt scheinbar im Detail. Ob es an der hyper-flexiblen Umsetzung in PHP liegt oder die ICU Implementation 
bereits so Anwender-unfreundlich gestaltet ist – wer weiß…</p>

<p>Der NumberFormatter von PHP nutzt im Hintergrund die ICU Datenbank, deren Inhalte sich gerne mal ändern und so kommt es 
nicht nur vor, dass Währungssymbole in einer Sprache existieren und in der anderen nicht, es ändert sich auch mal 
die Interpretation von Parameterwerten oder die Ausgabe (was das automatisierte Testen spaßig macht).</p>

<p>Hier meine Code-Leidensgeschichte um einen Formatter zu erstellen, der Währungswerte OHNE Währungssymbol bzw. Währungsnamen 
anzeigt, aber dennoch die aktuelle Locale berücksichtigt.</p>

<p><strong>Versuch 1</strong> – naiver Optimismus:</p>
<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$formatter</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">NumberFormatter</span><span class="p">(</span><span class="s1">'ru'</span><span class="p">,</span> <span class="nc">NumberFormatter</span><span class="o">::</span><span class="no">CURRENCY</span><span class="p">);</span>
<span class="nv">$formatter</span><span class="o">-&gt;</span><span class="nf">formatCurrency</span><span class="p">(</span><span class="mf">1234567.899</span><span class="p">,</span> <span class="kc">null</span><span class="p">);</span>
</code></pre></div></div>
<p>Ergebnis: <code class="language-plaintext highlighter-rouge">1 234 567,90 XXXX</code></p>

<p>WTF? Willkommen in der Welt der Pattern die der NumberFormatter intern nutzt.
Das Währungspattern beinhaltet Replacer, die hier einfach mit ausgegeben werden:</p>
<ul>
  <li>wie z.B. das <code class="language-plaintext highlighter-rouge">XXX</code> für den Währungsnamen</li>
  <li><code class="language-plaintext highlighter-rouge">¤</code> für das Währungssymbol</li>
  <li><code class="language-plaintext highlighter-rouge"> </code> (das ist ein non-breaking Space) für:
    <ul>
      <li>die Trennung von Werten</li>
      <li>den Prefix für die Währung</li>
      <li>das Suffix für die Währung (z.B. für die Locale <code class="language-plaintext highlighter-rouge">en</code>)</li>
    </ul>
  </li>
</ul>

<p>Okay, da muss man wohl dem NumberFormatter beibringen die richtigen Konfiguration zu nutzen. 
Jetzt schaut Euch bitte mal <a href="https://www.php.net/manual/en/class.numberformatter.php#intl.numberformatter-constants">die Dokumentation der Konstanten an</a>.
Super selbst sprechend, oder? Die hat jemand geschrieben, der alle Regeln guter Dokumentation vernachlässigt hat.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>NumberFormatter::MAX_FRACTION_DIGITS (integer)
   Maximum fraction digits 
</code></pre></div></div>
<p>Wow, und so sind fast alle Konstanten beschrieben. Dazu kommen die vielsagenden Methodennamen <code class="language-plaintext highlighter-rouge">setAttribute()</code>, <code class="language-plaintext highlighter-rouge">setSymbol()</code> und <code class="language-plaintext highlighter-rouge">setTextAttribute()</code>.
Ein Meisterstück des Sadismus.</p>

<p>Trotz Recherche und Testing habe ich es nicht hinbekommen mit den Methoden das richtige Format hinzubekommen.
Also habe ich mit letztlich entschieden, das Pattern direkt zu bearbeiten und neu zu setzen.</p>

<p><strong>Versuch 2</strong> (beachte: das sind non-breaking spaces in dem <code class="language-plaintext highlighter-rouge">str_replace()</code> Aufruf):</p>
<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$formatter</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">NumberFormatter</span><span class="p">(</span><span class="s1">'ru'</span><span class="p">,</span> <span class="nc">NumberFormatter</span><span class="o">::</span><span class="no">CURRENCY</span><span class="p">);</span>

<span class="nv">$formatter</span><span class="o">-&gt;</span><span class="nf">setTextAttribute</span><span class="p">(</span><span class="nc">NumberFormatter</span><span class="o">::</span><span class="no">CURRENCY_CODE</span><span class="p">,</span> <span class="s1">''</span><span class="p">);</span>
<span class="nv">$formatter</span><span class="o">-&gt;</span><span class="nf">setSymbol</span><span class="p">(</span><span class="nc">NumberFormatter</span><span class="o">::</span><span class="no">INTL_CURRENCY_SYMBOL</span><span class="p">,</span> <span class="s1">''</span><span class="p">);</span>
<span class="nv">$formatter</span><span class="o">-&gt;</span><span class="nf">setSymbol</span><span class="p">(</span><span class="nc">NumberFormatter</span><span class="o">::</span><span class="no">CURRENCY_SYMBOL</span><span class="p">,</span> <span class="s1">''</span><span class="p">);</span>

<span class="nv">$pattern</span> <span class="o">=</span> <span class="nv">$formatter</span><span class="o">-&gt;</span><span class="nf">getPattern</span><span class="p">();</span>
<span class="nv">$pattern</span> <span class="o">=</span> <span class="nb">str_replace</span><span class="p">([</span><span class="s1">'¤ '</span><span class="p">,</span> <span class="s1">' ¤'</span><span class="p">,</span> <span class="s1">'-¤'</span><span class="p">,</span> <span class="s1">' XXX'</span><span class="p">,</span> <span class="s1">'XXX '</span><span class="p">],</span> <span class="s1">'¤'</span><span class="p">,</span> <span class="nv">$pattern</span><span class="p">);</span>
<span class="nv">$pattern</span> <span class="o">=</span> <span class="nb">str_replace</span><span class="p">(</span><span class="s1">'XXX'</span><span class="p">,</span> <span class="s1">'¤'</span><span class="p">,</span> <span class="nv">$pattern</span><span class="p">);</span>
<span class="nv">$pattern</span> <span class="o">=</span> <span class="nb">str_replace</span><span class="p">(</span><span class="s1">'¤'</span><span class="p">,</span> <span class="s1">''</span><span class="p">,</span> <span class="nv">$pattern</span><span class="p">);</span>
<span class="nv">$formatter</span><span class="o">-&gt;</span><span class="nf">setPattern</span><span class="p">(</span><span class="nv">$pattern</span><span class="p">);</span>

<span class="nv">$formatter</span><span class="o">-&gt;</span><span class="nf">formatCurrency</span><span class="p">(</span><span class="mf">1234567.899</span><span class="p">,</span> <span class="kc">null</span><span class="p">);</span>
</code></pre></div></div>

<p>Prima, fertig. Das Ergebnis <code class="language-plaintext highlighter-rouge">1 234 567,90</code> sieht richtig aus und alle Tests sind grün (meine Testsuite läuft in PHP 7.2 / 7.3 und 7.4 via GitHub Actions).</p>

<p>Merge, Deployment … kaputt. WTF? Irgendwas läuft schief: die Werte werden einfach gar nicht angezeigt. Recherche ergibt: 
vermutlich geht da intern (je nach ICU Version) ein Aufruf schief und der Wert wird nach <code class="language-plaintext highlighter-rouge">false</code> gecastet – was dann zu 
einer “leeren Ausgabe” führt.</p>

<p>Okay, weiteres try&amp;error direkt auf dem System, das den Fehler zeigt und siehe da: 
die Methode <code class="language-plaintext highlighter-rouge">formatCurrency()</code> mag es <strong>auf einigen Systemen</strong> nicht, für <code class="language-plaintext highlighter-rouge">$currency</code> den Wert <code class="language-plaintext highlighter-rouge">null</code> zu bekommen und 
steigt einfach mit <code class="language-plaintext highlighter-rouge">false</code> aus und das OHNE zumindest <code class="language-plaintext highlighter-rouge">trigger_error()</code> aufzurufen.</p>

<p>Es ist mal wieder so ein Moment, an dem ich verstehe, dass immer noch so viele Witze über PHP gemacht werden:</p>

<blockquote>
  <p>Ein Code der lokal mit 7.3 und 7.4 läuft, im Container mit 7.2, 7.3 und 7.4 keine Probleme macht und erst im
Produktivsystem des Kunden stillschweigend und ohne Fehler aussteigt - das ist wahre Ingenieurskunst!</p>
</blockquote>

<p><strong>Versuch 3</strong> – so schnell gebe ich mich nicht geschlagen:</p>
<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$formatter</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">NumberFormatter</span><span class="p">(</span><span class="s1">'ru'</span><span class="p">,</span> <span class="nc">NumberFormatter</span><span class="o">::</span><span class="no">CURRENCY</span><span class="p">);</span>

<span class="nv">$formatter</span><span class="o">-&gt;</span><span class="nf">setTextAttribute</span><span class="p">(</span><span class="nc">NumberFormatter</span><span class="o">::</span><span class="no">CURRENCY_CODE</span><span class="p">,</span> <span class="s1">''</span><span class="p">);</span>
<span class="nv">$formatter</span><span class="o">-&gt;</span><span class="nf">setSymbol</span><span class="p">(</span><span class="nc">NumberFormatter</span><span class="o">::</span><span class="no">INTL_CURRENCY_SYMBOL</span><span class="p">,</span> <span class="s1">''</span><span class="p">);</span>
<span class="nv">$formatter</span><span class="o">-&gt;</span><span class="nf">setSymbol</span><span class="p">(</span><span class="nc">NumberFormatter</span><span class="o">::</span><span class="no">CURRENCY_SYMBOL</span><span class="p">,</span> <span class="s1">''</span><span class="p">);</span>

<span class="nv">$pattern</span> <span class="o">=</span> <span class="nv">$formatter</span><span class="o">-&gt;</span><span class="nf">getPattern</span><span class="p">();</span>
<span class="nv">$pattern</span> <span class="o">=</span> <span class="nb">str_replace</span><span class="p">([</span><span class="s1">'¤ '</span><span class="p">,</span> <span class="s1">' ¤'</span><span class="p">,</span> <span class="s1">'-¤'</span><span class="p">,</span> <span class="s1">' XXX'</span><span class="p">,</span> <span class="s1">'XXX '</span><span class="p">],</span> <span class="s1">'¤'</span><span class="p">,</span> <span class="nv">$pattern</span><span class="p">);</span>
<span class="nv">$pattern</span> <span class="o">=</span> <span class="nb">str_replace</span><span class="p">(</span><span class="s1">'XXX'</span><span class="p">,</span> <span class="s1">'¤'</span><span class="p">,</span> <span class="nv">$pattern</span><span class="p">);</span>
<span class="nv">$pattern</span> <span class="o">=</span> <span class="nb">str_replace</span><span class="p">(</span><span class="s1">'¤'</span><span class="p">,</span> <span class="s1">''</span><span class="p">,</span> <span class="nv">$pattern</span><span class="p">);</span>
<span class="nv">$formatter</span><span class="o">-&gt;</span><span class="nf">setPattern</span><span class="p">(</span><span class="nv">$pattern</span><span class="p">);</span>

<span class="nv">$formatter</span><span class="o">-&gt;</span><span class="nf">format</span><span class="p">(</span><span class="mf">1234567.899</span><span class="p">,</span> <span class="nc">NumberFormatter</span><span class="o">::</span><span class="no">TYPE_DEFAULT</span><span class="p">);</span>
</code></pre></div></div>

<p>Die Methode <code class="language-plaintext highlighter-rouge">format($amount, NumberFormatter::TYPE_DEFAULT)</code> ersetzt den Aufruf von <code class="language-plaintext highlighter-rouge">formatCurrency($amount, null)</code> eins 
zu eins und das ohne Fehler, das Ergebnis <code class="language-plaintext highlighter-rouge">1 234 567,90</code> macht mich glücklich!</p>

<p>Ja, ich sagte glücklich: kommt einem Runners-High gleich, wenn man nach langer Frickelei (anders kann man das hier nicht nennen) 
endlich eine funktionierende Lösung für so ein Furz-Problem gefunden hat. Hat ja auch nur zu einem Live Bug geführt zwischenzeitlich.</p>

<p>Also: wenn das schon so einfach war, dann muss doch das Pattern-Problem auch anders zu lösen sein - ich stelle mir selber eine 
Bonusaufgabe und nach stumpfem Ausprobieren dutzender Konstanten habe ich eine Lösung, die ohne Manipulation des Pattern auskommt.</p>

<p>Ich präsentiere <strong>Versuch 4</strong>:</p>

<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$formatter</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">NumberFormatter</span><span class="p">(</span><span class="s1">'ru'</span><span class="p">,</span> <span class="nc">NumberFormatter</span><span class="o">::</span><span class="no">CURRENCY</span><span class="p">);</span>

<span class="nv">$formatter</span><span class="o">-&gt;</span><span class="nf">setTextAttribute</span><span class="p">(</span><span class="nc">NumberFormatter</span><span class="o">::</span><span class="no">CURRENCY_CODE</span><span class="p">,</span> <span class="s1">''</span><span class="p">);</span>
<span class="nv">$formatter</span><span class="o">-&gt;</span><span class="nf">setSymbol</span><span class="p">(</span><span class="nc">NumberFormatter</span><span class="o">::</span><span class="no">INTL_CURRENCY_SYMBOL</span><span class="p">,</span> <span class="s1">''</span><span class="p">);</span>
<span class="nv">$formatter</span><span class="o">-&gt;</span><span class="nf">setSymbol</span><span class="p">(</span><span class="nc">NumberFormatter</span><span class="o">::</span><span class="no">CURRENCY_SYMBOL</span><span class="p">,</span> <span class="s1">''</span><span class="p">);</span>

<span class="nv">$formatter</span><span class="o">-&gt;</span><span class="nf">setTextAttribute</span><span class="p">(</span><span class="nc">NumberFormatter</span><span class="o">::</span><span class="no">POSITIVE_PREFIX</span><span class="p">,</span> <span class="s1">''</span><span class="p">);</span>
<span class="nv">$formatter</span><span class="o">-&gt;</span><span class="nf">setTextAttribute</span><span class="p">(</span><span class="nc">NumberFormatter</span><span class="o">::</span><span class="no">POSITIVE_SUFFIX</span><span class="p">,</span> <span class="s1">''</span><span class="p">);</span>

<span class="nv">$formatter</span><span class="o">-&gt;</span><span class="nf">format</span><span class="p">(</span><span class="mf">1234567.899</span><span class="p">,</span> <span class="nc">NumberFormatter</span><span class="o">::</span><span class="no">TYPE_DEFAULT</span><span class="p">);</span>
</code></pre></div></div>

<p>Schön, oder? Nur schade, dass es sowas nicht in der offiziellen Doku gibt.</p>

<p>Aber das hat mir immer noch keine Ruhe gelassen und mir kam der Gedanke, dass ich mir einen Großteil der Arbeit hätte sparen können, 
wäre ich nicht anfangs auf den falschen Pfad <code class="language-plaintext highlighter-rouge">formatCurrency()</code> abgebogen. Vielleicht waren auch die ersten Aufrufe von 
<code class="language-plaintext highlighter-rouge">setTextAttribute()</code> bzw. <code class="language-plaintext highlighter-rouge">setSymbol()</code> überflüssig, da sie sich ja auf ein scheinbares nicht gewolltes/unterstütztes Feature bezogen.</p>

<p>Wie könnte es also anders aussehen? Die Funktion <code class="language-plaintext highlighter-rouge">format()</code> kennt beim Typ <code class="language-plaintext highlighter-rouge">TYPE_DEFAULT</code> ja gar keine 
Währung und wir können daher die initialen Konfigurationen für <code class="language-plaintext highlighter-rouge">CURRENCY_CODE</code>, <code class="language-plaintext highlighter-rouge">INTL_CURRENCY_SYMBOL</code> und <code class="language-plaintext highlighter-rouge">CURRENCY_SYMBOL</code>
einfach entfernen.</p>

<p><strong>Versuch 5</strong> – das Gesellenstück:</p>
<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$formatter</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">NumberFormatter</span><span class="p">(</span><span class="s1">'ru'</span><span class="p">,</span> <span class="nc">NumberFormatter</span><span class="o">::</span><span class="no">CURRENCY</span><span class="p">);</span>
<span class="nv">$formatter</span><span class="o">-&gt;</span><span class="nf">setTextAttribute</span><span class="p">(</span><span class="nc">NumberFormatter</span><span class="o">::</span><span class="no">POSITIVE_PREFIX</span><span class="p">,</span> <span class="s1">''</span><span class="p">);</span>
<span class="nv">$formatter</span><span class="o">-&gt;</span><span class="nf">setTextAttribute</span><span class="p">(</span><span class="nc">NumberFormatter</span><span class="o">::</span><span class="no">POSITIVE_SUFFIX</span><span class="p">,</span> <span class="s1">''</span><span class="p">);</span>
<span class="nv">$formatter</span><span class="o">-&gt;</span><span class="nf">format</span><span class="p">(</span><span class="mf">1234567.899</span><span class="p">,</span> <span class="nc">NumberFormatter</span><span class="o">::</span><span class="no">TYPE_DEFAULT</span><span class="p">);</span>
</code></pre></div></div>

<blockquote>
  <p>Wer negative Zahlen anzeigt, der muss noch die Konstanten <code class="language-plaintext highlighter-rouge">NumberFormatter::NEGATIVE_SUFFIX</code> und <code class="language-plaintext highlighter-rouge">NumberFormatter::NEGATIVE_SUFFIX</code> setzen.</p>
</blockquote>

<p>Es ist erstaunlich, wie viel Zeit jetzt für sowas simples drauf ging 🤮</p>

<p>Wer also nach einer Lösung für</p>
<ul>
  <li>PHP format money without currency</li>
  <li>PHP Geld ohne Währung formatieren</li>
</ul>

<p>oä. gegoogelt hat und hier landete: Ich habs mir ausgedruckt und eingerahmt.</p>

<p>P.S. Nein <code class="language-plaintext highlighter-rouge">setlocale()</code> mit <code class="language-plaintext highlighter-rouge">money_format()</code> ist keine akzeptable Lösung! 
Methoden die nicht den Thread, sondern den gesamten Prozess beeinflussen sind grundsätzlich abzulehnen.</p>]]></content><author><name>Kevin Papst</name><email>kevin@kevinpapst.de</email></author><category term="Programmierung" /><summary type="html"><![CDATA[Jedem der schon mal näheren Kontakt mit dem NumberFormatter in internationalisierten Projekten hatte, dürfte der leichte Sarkasmus im Titel aufgefallen sein. Dies ist mein persönlicher “Rant” über die Implementation, aber um konstruktiv zu bleiben auch ein paar funktionierende Beispiele. Wieso? Insbesondere bei der Formatierung von Währungen gibt es einige Stolpersteine. Einige davon habe ich gefunden, während ich auf der Suche nach einer Lösung war, die hoffentlich auch auf allen OS und PHP Versionen läuft. Und da meine Zeiterfassung Kimai die Anzeige von monetären Werten (mit und ohne Währung) benötigt, durfte ich mich ein wenig mit der Umsetzung herumschlagen. Man sollte meinen das 2020 die Anzeige von Geld eine Trivialität darstellt, nachdem die LowLevel APIs hierfür schon vor langer Zeit fertiggestellt wurden.]]></summary></entry><entry><title type="html">FOSRestBundle - neue API Methoden via Bundle hinzufügen</title><link href="https://www.kevinpapst.de/blog/fosrestbundle-via-bundle.html" rel="alternate" type="text/html" title="FOSRestBundle - neue API Methoden via Bundle hinzufügen" /><published>2019-11-22T08:30:00+00:00</published><updated>2019-11-22T08:30:00+00:00</updated><id>https://www.kevinpapst.de/blog/fosrestbundle-via-bundle</id><content type="html" xml:base="https://www.kevinpapst.de/blog/fosrestbundle-via-bundle.html"><![CDATA[<p>Eine kurze Anleitung wie man sein Symfony Projekt mit Hilfe eines Bundles um neue API Methoden erweitern kann, 
wenn man in seinem Hauptprojekt auf den folgenden Stack setzt:</p>

<ul>
  <li>Symfony &gt;= 4.3</li>
  <li>FOSRestbundle</li>
  <li>JMSSerializer</li>
  <li>NelmioApiDocBundle</li>
</ul>

<h2>Welche Ziele werden verfolgt?</h2>

<p>Es geht hier nicht darum ein vollständig generisches Symfony Plugin zu entwickeln, welches in jedem Symfony Projekt lauffähig ist.</p>

<p>Vielmehr will ich heute ein Bundle für ein bestehendes Symfony-Projekt entwickeln, dessen eingesetzte Bundles bekannt sind.
Dies ist z.B. für viele OpenSource Projekte interessant, deren Grundlagen ja offen zugänglich sind.</p>

<p>Es geht ebenfalls nicht darum, den Code eines vollständigen Bundles zu teilen, sondern nur die Rumpfmethoden und wichtigesten 
Erweiterungspunkte aufzuzeigen.</p>

<h2>Der Code</h2>

<p>Ich verwende ein <code class="language-plaintext highlighter-rouge">PrependExtensionInterface</code> um die benötigten YAML Konfigurationen zu laden.
Statt der gezeigten Methodik mit YAML, könntet ihr auch genausogut XML verwenden oder die Configs direkt 
als Array hinterlegen.</p>

<h3>JMS Serializer Konfiguration</h3>

<p>Unter <code class="language-plaintext highlighter-rouge">Resources/config/jms_serializer.yaml</code> speichern wir die Konfiguration des Serializers:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">jms_serializer</span><span class="pi">:</span>
    <span class="na">metadata</span><span class="pi">:</span>
        <span class="na">directories</span><span class="pi">:</span>
            <span class="na">Demo</span><span class="pi">:</span>
                <span class="na">namespace_prefix</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Acme</span><span class="se">\\</span><span class="s">DemoBundle"</span>
                <span class="na">path</span><span class="pi">:</span> <span class="s2">"</span><span class="s">@DemoBundle/Resources/config/serializer"</span>
        <span class="na">warmup</span><span class="pi">:</span>
            <span class="na">paths</span><span class="pi">:</span>
                <span class="na">included</span><span class="pi">:</span>
                    <span class="pi">-</span> <span class="s2">"</span><span class="s">%kernel.root_dir%/../vendor/acme/DemoBundle/Entity/"</span>
</code></pre></div></div>

<p>Dann wollen wir dem JMSSerializer auch gleich noch mitteilen, welche Felder er wie ausgeben soll.
Das machen wir unter <code class="language-plaintext highlighter-rouge">Resources/config/serializer/Entity.Demo.yml</code>:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">Acme\DemoBundle\Entity\Demo</span><span class="pi">:</span>
    <span class="na">exclusion_policy</span><span class="pi">:</span> <span class="s">All</span>
    <span class="na">custom_accessor_order</span><span class="pi">:</span> <span class="pi">[</span><span class="nv">id</span><span class="pi">,</span> <span class="nv">page</span><span class="pi">,</span> <span class="nv">pageSize</span><span class="pi">]</span>
    <span class="na">properties</span><span class="pi">:</span>
        <span class="na">id</span><span class="pi">:</span>
            <span class="na">include</span><span class="pi">:</span> <span class="kc">true</span>
        <span class="na">page</span><span class="pi">:</span>
            <span class="na">include</span><span class="pi">:</span> <span class="kc">true</span>
        <span class="na">pageSize</span><span class="pi">:</span>
            <span class="na">exclude</span><span class="pi">:</span> <span class="kc">true</span>
    <span class="na">virtual_properties</span><span class="pi">:</span>
        <span class="na">getPageSize</span><span class="pi">:</span>
            <span class="na">serialized_name</span><span class="pi">:</span> <span class="s">pageSize</span>
            <span class="na">exp</span><span class="pi">:</span> <span class="s2">"</span><span class="s">object.getPageSize()</span><span class="nv"> </span><span class="s">===</span><span class="nv"> </span><span class="s">null</span><span class="nv"> </span><span class="s">?</span><span class="nv"> </span><span class="s">50</span><span class="nv"> </span><span class="s">:</span><span class="nv"> </span><span class="s">object.getPageSize()"</span>
            <span class="na">type</span><span class="pi">:</span> <span class="s">int</span>
</code></pre></div></div>

<h3>Nelmio API Doc Konfiguration</h3>

<p>Unter <code class="language-plaintext highlighter-rouge">Resources/config/nelmio_api_doc.yaml</code> speichern wir die Konfiguration des API Doc Bundles:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">nelmio_api_doc</span><span class="pi">:</span>
    <span class="na">models</span><span class="pi">:</span>
        <span class="na">names</span><span class="pi">:</span>
            <span class="pi">-</span> <span class="pi">{</span> <span class="nv">alias</span><span class="pi">:</span> <span class="nv">DemoForm</span><span class="pi">,</span>       <span class="nv">type</span><span class="pi">:</span> <span class="nv">Acme\DemoBundle\Form\DemoForm</span><span class="pi">,</span>   <span class="nv">groups</span><span class="pi">:</span> <span class="pi">[</span><span class="nv">Default</span><span class="pi">,</span> <span class="nv">Entity</span><span class="pi">,</span> <span class="nv">SomeGroup</span><span class="pi">]</span> <span class="pi">}</span>
            <span class="pi">-</span> <span class="pi">{</span> <span class="nv">alias</span><span class="pi">:</span> <span class="nv">DemoEntity</span><span class="pi">,</span>     <span class="nv">type</span><span class="pi">:</span> <span class="nv">Acme\DemoBundle\Entity\Demo</span><span class="pi">,</span>     <span class="nv">groups</span><span class="pi">:</span> <span class="pi">[</span><span class="nv">Default</span><span class="pi">,</span> <span class="nv">Entity</span><span class="pi">,</span> <span class="nv">SomeGroup</span><span class="pi">]</span> <span class="pi">}</span>
            <span class="pi">-</span> <span class="pi">{</span> <span class="nv">alias</span><span class="pi">:</span> <span class="nv">DemoCollection</span><span class="pi">,</span> <span class="nv">type</span><span class="pi">:</span> <span class="nv">Acme\DemoBundle\Entity\Demo</span><span class="pi">,</span>     <span class="nv">groups</span><span class="pi">:</span> <span class="pi">[</span><span class="nv">Default</span><span class="pi">,</span> <span class="nv">Collection</span><span class="pi">,</span> <span class="nv">SomeGroup</span><span class="pi">]</span> <span class="pi">}</span>
</code></pre></div></div>

<h3>Die Bundle Extension Klasse</h3>

<p>Ich habe mich für den Weg entschieden, weil das Hauptprojekt ebenfalls auf YAMl setzt.</p>

<p>Unter <code class="language-plaintext highlighter-rouge">DependencyInjection/DemoExtension.php</code> finden wir die Extension Klasse des Bundles:</p>

<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">namespace</span> <span class="nn">Acme\DependencyInjection</span><span class="p">;</span>

<span class="kn">use</span> <span class="nc">Symfony\Component\Config\FileLocator</span><span class="p">;</span>
<span class="kn">use</span> <span class="nc">Symfony\Component\DependencyInjection\ContainerBuilder</span><span class="p">;</span>
<span class="kn">use</span> <span class="nc">Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface</span><span class="p">;</span>
<span class="kn">use</span> <span class="nc">Symfony\Component\DependencyInjection\Loader</span><span class="p">;</span>
<span class="kn">use</span> <span class="nc">Symfony\Component\HttpKernel\DependencyInjection\Extension</span><span class="p">;</span>
<span class="kn">use</span> <span class="nc">Symfony\Component\Yaml\Parser</span><span class="p">;</span>

<span class="k">final</span> <span class="kd">class</span> <span class="nc">DemoExtension</span> <span class="kd">extends</span> <span class="nc">Extension</span> <span class="kd">implements</span> <span class="nc">PrependExtensionInterface</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">function</span> <span class="n">load</span><span class="p">(</span><span class="kt">array</span> <span class="nv">$configs</span><span class="p">,</span> <span class="kt">ContainerBuilder</span> <span class="nv">$container</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="c1">// ...</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">function</span> <span class="n">prepend</span><span class="p">(</span><span class="kt">ContainerBuilder</span> <span class="nv">$container</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="nv">$yamlParser</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Parser</span><span class="p">();</span>

        <span class="nv">$config</span> <span class="o">=</span> <span class="nv">$yamlParser</span><span class="o">-&gt;</span><span class="nf">parse</span><span class="p">(</span>
            <span class="nb">file_get_contents</span><span class="p">(</span><span class="k">__DIR__</span> <span class="mf">.</span> <span class="s1">'/../Resources/config/jms_serializer.yaml'</span><span class="p">)</span>
        <span class="p">);</span>
        <span class="nv">$container</span><span class="o">-&gt;</span><span class="nf">prependExtensionConfig</span><span class="p">(</span><span class="s1">'jms_serializer'</span><span class="p">,</span> <span class="nv">$config</span><span class="p">[</span><span class="s1">'jms_serializer'</span><span class="p">]);</span>

        <span class="nv">$config</span> <span class="o">=</span> <span class="nv">$yamlParser</span><span class="o">-&gt;</span><span class="nf">parse</span><span class="p">(</span>
            <span class="nb">file_get_contents</span><span class="p">(</span><span class="k">__DIR__</span> <span class="mf">.</span> <span class="s1">'/../Resources/config/nelmio_api_doc.yaml'</span><span class="p">)</span>
        <span class="p">);</span>
        <span class="nv">$container</span><span class="o">-&gt;</span><span class="nf">prependExtensionConfig</span><span class="p">(</span><span class="s1">'nelmio_api_doc'</span><span class="p">,</span> <span class="nv">$config</span><span class="p">[</span><span class="s1">'nelmio_api_doc'</span><span class="p">]);</span>
    <span class="p">}</span>
</code></pre></div></div>

<h3>Demo Rest Controller</h3>

<p>Unter <code class="language-plaintext highlighter-rouge">API/DemoController.php</code> wird der neue API Controller erstellt:</p>

<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">namespace</span> <span class="nn">Acme\DemoBundle\API</span><span class="p">;</span>

<span class="kn">use</span> <span class="nc">Acme\DemoBundle\Demo</span><span class="p">;</span>
<span class="kn">use</span> <span class="nc">FOS\RestBundle\Controller\Annotations</span> <span class="k">as</span> <span class="nc">Rest</span><span class="p">;</span>
<span class="kn">use</span> <span class="nc">FOS\RestBundle\Controller\Annotations\RouteResource</span><span class="p">;</span>
<span class="kn">use</span> <span class="nc">FOS\RestBundle\Request\ParamFetcherInterface</span><span class="p">;</span>
<span class="kn">use</span> <span class="nc">FOS\RestBundle\View\View</span><span class="p">;</span>
<span class="kn">use</span> <span class="nc">FOS\RestBundle\View\ViewHandlerInterface</span><span class="p">;</span>
<span class="kn">use</span> <span class="nc">Sensio\Bundle\FrameworkExtraBundle\Configuration\Security</span><span class="p">;</span>
<span class="kn">use</span> <span class="nc">Swagger\Annotations</span> <span class="k">as</span> <span class="no">SWG</span><span class="p">;</span>
<span class="kn">use</span> <span class="nc">Symfony\Component\HttpFoundation\Request</span><span class="p">;</span>
<span class="kn">use</span> <span class="nc">Symfony\Component\HttpFoundation\Response</span><span class="p">;</span>
<span class="kn">use</span> <span class="nc">Symfony\Bundle\FrameworkBundle\Controller\AbstractController</span><span class="p">;</span>

<span class="cd">/**
 * @RouteResource("Demo")

 * @Security("is_granted('ROLE_USER')")
 */</span>
<span class="k">final</span> <span class="kd">class</span> <span class="nc">DemoController</span> <span class="kd">extends</span> <span class="nc">AbstractController</span>
<span class="p">{</span>
    <span class="cd">/**
     * @var ViewHandlerInterface
     */</span>
    <span class="k">private</span> <span class="nv">$viewHandler</span><span class="p">;</span>

    <span class="k">public</span> <span class="k">function</span> <span class="n">__construct</span><span class="p">(</span><span class="kt">ViewHandlerInterface</span> <span class="nv">$viewHandler</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="nv">$this</span><span class="o">-&gt;</span><span class="n">viewHandler</span> <span class="o">=</span> <span class="nv">$viewHandler</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="cd">/**
     * Returns a collection of demos
     *
     * @SWG\Response(
     *      response=200,
     *      description="Returns a collection of demo entities",
     *      @SWG\Schema(
     *          type="array",
     *          @SWG\Items(ref="#/definitions/DemoCollection")
     *      )
     * )
     * @Rest\QueryParam(name="page", requirements="\d+", strict=true, nullable=true, description="The page to display, renders a 404 if not found (default: 1)")
     * @Rest\QueryParam(name="size", requirements="\d+", strict=true, nullable=true, description="The amount of entries for each page (default: 50)")
     */</span>
    <span class="k">public</span> <span class="k">function</span> <span class="n">cgetAction</span><span class="p">(</span><span class="kt">ParamFetcherInterface</span> <span class="nv">$paramFetcher</span><span class="p">):</span> <span class="kt">Response</span>
    <span class="p">{</span>
        <span class="nv">$demo</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Demo</span><span class="p">();</span>

        <span class="k">if</span> <span class="p">(</span><span class="kc">null</span> <span class="o">!==</span> <span class="p">(</span><span class="nv">$page</span> <span class="o">=</span> <span class="nv">$paramFetcher</span><span class="o">-&gt;</span><span class="nf">get</span><span class="p">(</span><span class="s1">'page'</span><span class="p">)))</span> <span class="p">{</span>
            <span class="nv">$demo</span><span class="o">-&gt;</span><span class="nf">setPage</span><span class="p">(</span><span class="nv">$page</span><span class="p">);</span>
        <span class="p">}</span>

        <span class="k">if</span> <span class="p">(</span><span class="kc">null</span> <span class="o">!==</span> <span class="p">(</span><span class="nv">$size</span> <span class="o">=</span> <span class="nv">$paramFetcher</span><span class="o">-&gt;</span><span class="nf">get</span><span class="p">(</span><span class="s1">'size'</span><span class="p">)))</span> <span class="p">{</span>
            <span class="nv">$demo</span><span class="o">-&gt;</span><span class="nf">setPageSize</span><span class="p">(</span><span class="nv">$size</span><span class="p">);</span>
        <span class="p">}</span>

        <span class="nv">$view</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">View</span><span class="p">([</span><span class="nv">$demo</span><span class="p">],</span> <span class="mi">200</span><span class="p">);</span>
        <span class="nv">$view</span><span class="o">-&gt;</span><span class="nf">getContext</span><span class="p">()</span><span class="o">-&gt;</span><span class="nf">setGroups</span><span class="p">([</span><span class="s1">'Default'</span><span class="p">,</span> <span class="s1">'Collection'</span><span class="p">,</span> <span class="s1">'SomeGroup'</span><span class="p">]);</span>

        <span class="k">return</span> <span class="nv">$this</span><span class="o">-&gt;</span><span class="n">viewHandler</span><span class="o">-&gt;</span><span class="nf">handle</span><span class="p">(</span><span class="nv">$view</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="c1">// ...</span>
<span class="p">}</span>

</code></pre></div></div>

<h3>Die Routen</h3>

<p>Ich setze hier vorraus, dass Ihr Eure Rest Controller im Sub-Namespace und damit auch Verzeichnis <code class="language-plaintext highlighter-rouge">API/</code> speichert (wie 
in der Controller Klasse vorgeschlagen), um diese von den “normalen” Controllern zu trennen,</p>

<p>Diese Route muss in Eurem Hauptprojekt aktiviert werden.</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">demo.api</span><span class="pi">:</span>
    <span class="na">resource</span><span class="pi">:</span> <span class="s2">"</span><span class="s">@DemoBundle/API/"</span>
    <span class="na">type</span><span class="pi">:</span> <span class="s">rest</span>
    <span class="na">prefix</span><span class="pi">:</span> <span class="s">/api</span>
</code></pre></div></div>

<p>Die restlichen Klassen und Bundle Logik sind ausführlich in der Symfony Dokumentation beschrieben, das werde ich 
hier nicht wiedergeben … daher sind wir auch schon: FERTIG!</p>

<p>Viel Spaß 😃</p>]]></content><author><name>Kevin Papst</name><email>kevin@kevinpapst.de</email></author><category term="Programmierung" /><summary type="html"><![CDATA[Eine kurze Anleitung wie man sein Symfony Projekt mit Hilfe eines Bundles um neue API Methoden erweitern kann, wenn man in seinem Hauptprojekt auf den folgenden Stack setzt:]]></summary></entry><entry><title type="html">iMac 2017, Fritz!Box 7590 und das 5GHz Band</title><link href="https://www.kevinpapst.de/blog/fritzbox-7590-imac-2017-wifi-5ghz.html" rel="alternate" type="text/html" title="iMac 2017, Fritz!Box 7590 und das 5GHz Band" /><published>2019-08-03T12:30:00+00:00</published><updated>2019-08-03T12:30:00+00:00</updated><id>https://www.kevinpapst.de/blog/fritzbox-7590-imac-2017-wifi-5ghz</id><content type="html" xml:base="https://www.kevinpapst.de/blog/fritzbox-7590-imac-2017-wifi-5ghz.html"><![CDATA[<p>Da kauft man sich das Flagschiff von AVM, die <strong>Fritz!Box 7590</strong> und freut sich darauf vollen Speed zu genießen und was passiert?!</p>

<p>Der iMac von 2017 mit den neuesten macOS Mojave 10.14.6 will sich partout nicht in das 5GHz Netz einwählen.
Ärgerlich… sehr ärgerlich!</p>

<p>Und dabei funktioneren alle anderen Geräte einwandfrei. Ja klar, die kleinen Spielerein wie Drucker und Kindle nutzen das 2,4GHz Band, 
welches zwar notorisch überlastet ist, aber für die Ansprüche dieser Geräte immer noch vollkommen ausreicht.</p>

<p>Toll, mein iPad Pro und auch meine betagten 6er iPhones nutzen das 5GHz problemlos. Aber mein iMac nicht. Warum auch, 
ist ja nur das teuerste Stück Hardware das ich mir jemals angeschafft habe, das sollte sowas “triviales” wie das WLAN eigentlich problemlos laufen.</p>

<p>Interessanterweise scheint sich der Vorteil des 5GHZ Bands noch immer nicht rumgesprochen zu haben, 
denn es gibt hier ca. 30 Netzwerke im 2,4 GHz Frequenzband, aber nur 2(!) im 5er.</p>

<p>Schaut man sich jetzt die offiziell von Apple <a href="https://support.apple.com/de-de/HT202068">empfohlenen Einstellungen für WLAN-Router und Zugangspunkte</a> an und 
gleicht diese mit den Einstellungen der Fritzbox ab, dann funktioniert die Verbindung einfach nicht.
Nach der Eingabe des Passworts werkelt das System ewig rum, das Systemlog läuft voll mit unverständlichen (Fehler-)Meldungen, 
die Toolbar hängt und dann nach ca. 2 Minuten kommt nur die Meldung <strong>Verbindung zu WLAN Netzwerk konnte nicht hergestellt werden</strong>.</p>

<p>Nach zahllosen Versuchen bin ich dann dankenswerterweise auf <a href="https://www.digitalzimmer.de/artikel/praxis/fritz-box-wlan-probleme-mit-apple-geraeten-loesen/">diesen Beitrag von digitalzimmer</a> gestoßen, 
der mich in die richtige Richtung gelotst hat.</p>

<p>Ausschlag gegeben haben die Einstellungen:</p>
<ul>
  <li><strong>Funkkanal im 5GHz-Frequenzband</strong>: Änderung auf <strong>Kanal 40</strong> (Achtung, 36 scheint nicht immer zu funktionieren und 44 ist eventuell durch AirDrop belegt)</li>
  <li><strong>WLAN-Standard 5-GHz</strong>: den musste ich auf <strong>802.11n+a</strong> ändern</li>
  <li><strong>WLAN/Sicherheit</strong>: musste auf <strong>Alle neuen WLAN-Geräte zulassen</strong> eingestellt werden</li>
</ul>

<p><img src="/images/2019/fritzbox-7590-imac-wifi.png" /></p>

<p>Damit hat der Verbindungsaufbau endlich funktioniert!</p>]]></content><author><name>Kevin Papst</name><email>kevin@kevinpapst.de</email></author><category term="MacOS" /><summary type="html"><![CDATA[Da kauft man sich das Flagschiff von AVM, die Fritz!Box 7590 und freut sich darauf vollen Speed zu genießen und was passiert?!]]></summary></entry><entry><title type="html">MacOS Logs: /var/db/DetachedSignatures - No such file or directory</title><link href="https://www.kevinpapst.de/blog/detachedsignature.html" rel="alternate" type="text/html" title="MacOS Logs: /var/db/DetachedSignatures - No such file or directory" /><published>2019-08-03T08:30:00+00:00</published><updated>2019-08-03T08:30:00+00:00</updated><id>https://www.kevinpapst.de/blog/detachedsignature</id><content type="html" xml:base="https://www.kevinpapst.de/blog/detachedsignature.html"><![CDATA[<p>Aktuell habe ich leider erheblichen Ärger mit meiner Mojave Installation und kämpfe mit möglichen Fehlerquellen und Logeinträgen.</p>

<p>Dabei bin ich u.a. auf die folgende Fehlermeldung gestossen:</p>

<h2>Um welche Fehler geht es?</h2>

<p><img src="/images/2019/untrusted-kexts.png" /></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Untrusted kexts are not allowed
Kext with invalid signature (-67062) denied: /Library/StagedExtensions/System/Library/Extensions/HuaweiDataCardDriver.kext/Contents/PlugIns/14E59974-99C3-4F32-9E41-2AA9634A7F8B.kext
Bundle (/System/Library/Extensions/HuaweiDataCardDriver.kext/Contents/PlugIns/HuaweiDataCardECMControl.kext) failed to validate, deleting: /Library/StagedExtensions/System/Library/Extensions/HuaweiDataCardDriver.kext/Contents/PlugIns/14E59974-99C3-4F32-9E41-2AA9634A7F8B.kext
Unable to stage kext (/System/Library/Extensions/HuaweiDataCardDriver.kext/Contents/PlugIns/HuaweiDataCardECMControl.kext) to secure location.
cannot open file at line 42270 of [95fbac39ba]
os_unix.c:42270: (2) open(/var/db/DetachedSignatures) - No such file or directory
cannot open file at line 42270 of [95fbac39ba]
os_unix.c:42270: (2) open(/var/db/DetachedSignatures) - No such file or directory
</code></pre></div></div>

<p>Die Datei <code class="language-plaintext highlighter-rouge">/var/db/DetachedSignatures</code> wird also offensichtlich versucht vom System zu laden, um unbekannte Software/Signaturen zu bestätigen.
Meine Vermutung lautet, das in dieser Datei die Signaturen hinterlegt werden, welche vom Benutzer selber bestätigt wurden.</p>

<p>Reine Mutmaßung bis auf weiteres, denn ich konnte keine bessere Erläuterung finden…</p>

<h2>open(/var/db/DetachedSignatures) - No such file or directory</h2>

<p>Dieser Fehler scheint bei diversen Benutzern aufzutreten, allerdings in verschiedensten Situationen und oft im Zusammenhang mit Applikationen die man starten will.</p>

<p>Was hat es damit auf sich? Und wieso dokumentiert Apple sowas nicht, wenn das Internet mit der Meldung voll mit der Meldung ist:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>os_unix.c:42270: (2) open(/var/db/DetachedSignatures) - No such file or directory
</code></pre></div></div>

<p>Nervig, das man sich durch dutzende Seiten quer lesen muss, bis man dann endlich einen Hinweise darauf findet.</p>

<p>Ruft man die ManPage für das binary <code class="language-plaintext highlighter-rouge">codesign</code> auf:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>man codesign
</code></pre></div></div>

<p>Und sucht nach <em>detached</em>, dann findet man 2 interessante Hinweise:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> --detached-database
         When signing, specifies that a detached signature should be generated as with the --detached option, but that the resulting signature should be written into a system database, from where it is made automatically available whenever apparently
         unsigned code is validated on the system.
         Writing to this system database requires elevated process privileges that are not available to ordinary users.
</code></pre></div></div>
<p>und:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>FILES
     /var/db/DetachedSignatures  System-wide database of detached code signatures for unsigned code. 
</code></pre></div></div>

<p>Es handelt sich also um eine SQLite Datenbank. <a href="https://geoff.greer.fm/2015/04/26/os-x-code-signing-and-firewalls/">Dieser Blogbeitrag</a> erläutert grob den Inhalt der Datei.</p>

<p>Wieso die Datei <code class="language-plaintext highlighter-rouge">/var/db/DetachedSignatures</code> nicht per default existiert und wieso sie für unsignierte Kexts mehrfach versucht wird zu laden, tja dazu gibt es natürlich keine Hinweise.
Und leider auch nicht dazu, wie man sie neu erzeugt. 
Ich vermute indem man eine Applikation signiert bzw. deren Nutzung bestätigt, sollte ich mehr dazu rausfinden werde ich es hier nachtragen.</p>]]></content><author><name>Kevin Papst</name><email>kevin@kevinpapst.de</email></author><category term="MacOS" /><summary type="html"><![CDATA[Aktuell habe ich leider erheblichen Ärger mit meiner Mojave Installation und kämpfe mit möglichen Fehlerquellen und Logeinträgen.]]></summary></entry><entry><title type="html">MacOS Untrusted Kexts, Fehler und Erklärungen</title><link href="https://www.kevinpapst.de/blog/macos-untrusted-kexts.html" rel="alternate" type="text/html" title="MacOS Untrusted Kexts, Fehler und Erklärungen" /><published>2019-08-03T08:30:00+00:00</published><updated>2019-08-03T08:30:00+00:00</updated><id>https://www.kevinpapst.de/blog/macos-untrusted-kexts</id><content type="html" xml:base="https://www.kevinpapst.de/blog/macos-untrusted-kexts.html"><![CDATA[<p>Wie im <a href="/blog/detachedsignature.html">letzten Beitrag bereits beschrieben</a> habe ich momentan leider Ärger mit meiner Mojave Installation und wühle mich durch Unmengen an möglichen Fehlerquellen und Logeinträgen.</p>

<p>Dabei bin ich u.a. auf die das Problem <code class="language-plaintext highlighter-rouge">Untrusted kexts are not allowed</code> gestossen und konnte ein wenig über den Umgang mit Kexts (MacOS Kernel Extensions) lernen.</p>

<h2>Um welche Fehler geht es?</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Untrusted kexts are not allowed
Kext with invalid signature (-67062) denied: /Library/StagedExtensions/System/Library/Extensions/HuaweiDataCardDriver.kext/Contents/PlugIns/14E59974-99C3-4F32-9E41-2AA9634A7F8B.kext
Bundle (/System/Library/Extensions/HuaweiDataCardDriver.kext/Contents/PlugIns/HuaweiDataCardECMControl.kext) failed to validate, deleting: /Library/StagedExtensions/System/Library/Extensions/HuaweiDataCardDriver.kext/Contents/PlugIns/14E59974-99C3-4F32-9E41-2AA9634A7F8B.kext
Unable to stage kext (/System/Library/Extensions/HuaweiDataCardDriver.kext/Contents/PlugIns/HuaweiDataCardECMControl.kext) to secure location.
</code></pre></div></div>

<p>Dieser <code class="language-plaintext highlighter-rouge">Untrusted kexts are not allowed</code> Fehler wiederholt sich bei mir für ein gutes dutzend verschiedene Files, 
welche scheinbar alle nicht korrekt signiert oder in meinem Falle nicht freigegeben worden sind bzw. für eine mittlerweile veraltete MaxOS Version erstellt worden sind.</p>

<p>Diese nicht geladenen Kernel Erweiterungen werden von MacOS in den Ordner <code class="language-plaintext highlighter-rouge">/Library/StagedExtensions/</code> verschoben.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ ls -la /Library/StagedExtensions/System/Library/Extensions
total 0
drwxr-xr-x@ 3 root  wheel    96B 22 Nov  2010 BJUSBLoad.kext
drwxr-xr-x  3 root  wheel    96B  3 Aug 14:29 HuaweiDataCardDriver.kext
drwxr-xr-x@ 3 root  wheel    96B 28 Jan  2013 IceraUSBMassStorageBypass.kext
drwxr-xr-x@ 3 root  wheel    96B 22 Mai  2012 JMicronATA.kext
drwxr-xr-x  3 root  wheel    96B  3 Aug 14:29 NMHuaweiPhonesVTPCDC_106.kext
drwxr-xr-x  3 root  wheel    96B  3 Aug 14:29 NMSamsungDriver_106.kext
drwxr-xr-x  3 root  wheel    96B  3 Aug 14:29 NovatelWireless3G.kext
drwxr-xr-x@ 3 root  wheel    96B 28 Jan  2013 NovatelWirelessUSBCDCECMControl.kext
drwxr-xr-x@ 3 root  wheel    96B 28 Jan  2013 RIMBBUSB.kext
drwxr-xr-x@ 3 root  wheel    96B 28 Jan  2013 RIMBBVSP.kext
drwxr-xr-x  3 root  wheel    96B  3 Aug 14:29 Vodafone.kext
drwxr-xr-x@ 3 root  wheel    96B 26 Mär  2013 heimdall.kext
drwxr-xr-x  3 root  wheel    96B  3 Aug 14:29 ssuddrv.kext
</code></pre></div></div>

<p>Sie können durch Installation von Software dort landen, bei mir waren es Überbleibsel vergangener Installationen, 
die nicht korrekt bzw. vollständig deinstalliert wurden, denn das verschieben der App in den Papierkorn löscht leider 
nicht alle dazugehörigen Abhängigkeiten.</p>

<p>Wegen solcher Probleme hatte ich Mojave komplett neu installiert und NUR meine Benutzerdaten aus dem TimeMachine Backup wiederhergestellt.
Licht und Schatten solcher Wollmilcheierlegenden-Superlösungen wie Time-Machine… sie wurden wieder mit hergestellt.</p>

<p>Ein gute Erläuterung zu der Meldung <strong>Untrusted kexts are not allowed</strong> liefert <a href="https://forums.developer.apple.com/thread/109455">dieser Forum-Beitrag</a>:</p>

<blockquote>
  <p>The first time an attempt is made to load the kext, macOS should present the user with a popup informing them that it was blocked. The user then needs to go to System Preferences &gt; Security &amp; Privacy in order to approve the kext. Note that the approval needs to happen within 30 minutes of the load attempt or it will disappear. Subsequent load attempts will be rejected silently but will reactivate the prompt within “Security &amp; Privacy” – giving the user another chance to approve the kext.</p>
</blockquote>

<p>Dummerweise habe ich diese Dialoge nach einem Restore aus einem Time-Machine Backup genau einmal bei Booten gesehen und erstmal weggeklickt.</p>

<p>Aber man kann, wenn es denn gewünscht sein sollte, diese immer noch wieder aktivieren in dem man die <strong>Systemeinstellungen</strong> und dort 
zu <strong>Sicherheit/Allgemein</strong> wechselt. Achtung: das muss innerhalb von 30 Minuten nach Reboot gemacht werden, ansonsten verschwindet die Meldung
<strong>Das laden einer Systemsoftware wurde blockiert</strong> und mann kan den <em>Erlauben …</em> Dialog nicht öffnen:</p>

<p><img src="/images/2019/allow-untrusted-kexts.png" /></p>

<p>Ich vermute (ungetestet) das “Haken setzen” und “Neustarten” diese Kernel Erweiterungen laden. Empfehlen würde ich es nicht, 
macht lieber ein Update auf die neueste Version der betroffenen Software. 
Die liefert dann hoffentlich auch ein kompatibles .kext mit.</p>

<h3>Kext Infos einsehen</h3>

<p>Interesse an mehr technischen Informationen vorhanden? Gut, denn man kann sich weitere Informationen über Kernel Extensions anschauen mit:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo kextutil -tn /Library/StagedExtensions/System/Library/Extensions/*.kext
</code></pre></div></div>

<p>Da findet man Informationen wie:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Code Signing Failure: not code signed
Dependency Resolution Failures:
    Only incompatible kexts found for these libraries:
        com.rim.driver.BlackBerryUSBDriverInt

Diagnostics for /Library/StagedExtensions/System/Library/Extensions/RIMBBVSP.kext:
Dependency Resolution Failures:
    Only incompatible kexts found for these libraries:
        com.rim.driver.BlackBerryUSBDriverInt

kext file:///Library/StagedExtensions/System/Library/Extensions/heimdall.kext/ is in hash exception list, allowing to load
Kext rejected due to system policy: &lt;OSKext 0x7fb2ef491410 [0x7fff8a14c8e0]&gt; { URL = "file:///Library/StagedExtensions/System/Library/Extensions/heimdall.kext/", ID = "au.com.glassechidna.heimdall_usb_shield" }
Code Signing Failure: not code signed
Warnings:
    Personality CFBundleIdentifier differs from containing kext's (not necessarily a mistake, but rarely done):
        GalaxyS
        GalaxyS2
        DroidCharge

Diagnostics for /Library/StagedExtensions/System/Library/Extensions/heimdall.kext:
Warnings:
    Personality CFBundleIdentifier differs from containing kext's (not necessarily a mistake, but rarely done):
        GalaxyS
        GalaxyS2
        DroidCharge
</code></pre></div></div>

<p>oder auch</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Memory allocation failure.
/Library/StagedExtensions/System/Library/Extensions/70F75E81-D822-4E69-9103-8CD2A0EAE699.kext does not appear in strict exception list for architecture: x86_64
Untrusted kexts are not allowed
</code></pre></div></div>

<p>Nachdem ich mich ein wenig umgeschaut habe, war klar: weg mit den Kexts, werden nicht benötigt.</p>

<h3>Kernel Extensions löschen</h3>

<p>Will man diese Kexts also nicht nutzen und loswerden, dann stößt man auf ein Problem: aufgrund der SIP können diese nicht einfach gelöscht werden.</p>

<p>Aber dafür gibt es dankenswerterweise ein binary von Apple:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>kextcache <span class="nt">--clear-staging</span>
</code></pre></div></div>

<p>Und schwupps ist der Ordner leer. Toll! Reboot und was sehe ich da: alles wieder wie vorher… Kopf =&gt; Wand.
Okay das war noch nicht die Lösung, der Ordner wird bei jedem Reboot wiederhergestellt.</p>

<p>Dann ein Stück tiefer graben und rausfinden, dass Kexts in den folgenden Ordnern gespeichert werden :</p>

<ul>
  <li>/System/Library/Extensions</li>
  <li>/Library/Extensions</li>
</ul>

<p>Neu installierte Kexts werden also zunächst in <code class="language-plaintext highlighter-rouge">/Library/StagedExtensions</code> gespeichert und nach Freigabe durch den Benutzer in einen der Ordner verschoben.
Wurde dies unter einer alten MacOS Version gemacht, so kann es sein das bei einem Neustart der Kernel auf diese Dateien trifft, sie aber ablehnt da sie nicht mit den neuesten Sicherheitsrichtlinien kompatibel sind.
In solch einem Fall werden sie ungekehrt wieder nach <code class="language-plaintext highlighter-rouge">/Library/StagedExtensions</code> kopiert.</p>

<p>Wie werden wir sie also dauerhaft los?
Spannenderweise kann man mit <code class="language-plaintext highlighter-rouge">sudo</code> Berechtigung Kexts auf dem Ordner <code class="language-plaintext highlighter-rouge">/System/Library/Extensions</code> löschen.</p>

<p>Also neuer Versuch:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo rm</span> <span class="nt">-rf</span> /System/Library/Extensions/heimdall.kext
</code></pre></div></div>
<p>Das ganze wiederholen für alle überflüssigen Kexts und dann</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>kextcache <span class="nt">--clear-staging</span>
</code></pre></div></div>
<p>Jetzt noch ein finaler Reboot … UND: die kexts sind wirklich weg!</p>

<p>Und wer jetzt heiß ist auf noch mehr technische Informationen, dem sei der Blogbeitrag <a href="https://macadmins.co.il/2019/01/21/macos-security-secure-kernel-extension-loading-skel/">Secure Kernel Extension Loading</a> 
ans Herz gelegt!</p>]]></content><author><name>Kevin Papst</name><email>kevin@kevinpapst.de</email></author><category term="MacOS" /><summary type="html"><![CDATA[Wie im letzten Beitrag bereits beschrieben habe ich momentan leider Ärger mit meiner Mojave Installation und wühle mich durch Unmengen an möglichen Fehlerquellen und Logeinträgen.]]></summary></entry><entry><title type="html">Server-Umzug &amp;amp; Wordpress nach Jekyll</title><link href="https://www.kevinpapst.de/blog/serverumzug-jekyll.html" rel="alternate" type="text/html" title="Server-Umzug &amp;amp; Wordpress nach Jekyll" /><published>2019-07-22T14:26:00+00:00</published><updated>2019-07-22T14:26:00+00:00</updated><id>https://www.kevinpapst.de/blog/serverumzug-jekyll</id><content type="html" xml:base="https://www.kevinpapst.de/blog/serverumzug-jekyll.html"><![CDATA[<p>Nachdem ich nun seit Jahren auf verschiedensten Seiten Jekyll (den <a href="https://jekyllrb.com">statischen Webseiten Generator</a>) einsetze und auch 
seit mehr als 1 Jahr darüber blogge, wurde es endlich Zeit meinen eigenen Blog weg von Wordpress und hin zu Jekyll zu migrieren.</p>

<p>Ich nehme momentan einige Umbauarbeiten an meinem Server vor und will meine Wordpress-Multisite Installation loswerden.
Nicht nur, das es eine permanente Sicherheitsbedrohung ist, seien wir ehrlich: ich blogge super selten und auf ein 
Update kommen zehntausende lesende Zugriffe.</p>

<p>Wieso sollte also jede Seite immer und immer wieder neu erzeugt werden, inkl. aller Datenbankzugriffe  etc.
Dazu kommt noch, das sich Wordpress Themes sehr schlecht optimieren lassen und diese zumeist mit dutzenden Assets (JS, CSS) 
vollgemüllt sind. Eine unnötige Belastung für alle involvierten Parteien und den Aspekt Datenschutz haben wir dabei noch gar nicht betrachtet.</p>

<p>Da ist mir eine Jekyll Seite viel lieber, zudem ich diese dann auch noch gleich über GitHub Pages kostenlos hosten kann.</p>

<blockquote>
  <p>Gesagt getan: 1 Tag später ist der Umzug vollendet und die Seite wird über GitHub ausgeliefert.</p>
</blockquote>

<h2>Herausforderungen und Lösungen</h2>

<p>In der Vergangenheit habe ich schonmal über das Thema “<a href="/wordpress-seiten-nach-jekyll-umziehen/">Wordpress zu Jekyll umziehen</a>” geschrieben, 
seitdem hat sich aber eine Kleinigkeit geändert. Eine wesentliche Nicht-Ganz-So-Kleine-Kleinigkeit wie ich anmerken möchte.
Und zwar bin ich auf das <a href="https://github.com/benbalter/wordpress-to-jekyll-exporter">Wordpress to Jekyll Exporter</a> Plugin gestoßen, 
welches deutlich bessere Arbeit leistet als das offizielle Jekyll WP-Importer Plugin.</p>

<p>Das Plugin wurde von <a href="https://github.com/benbalter">Ben Balter</a> geschrieben, einem Entwickler den man kennen sollte, wenn man öfters mit Jekylll zu tun hat.</p>

<p>Die Stärken des Plugins liegen u.a. in den Punkten:</p>

<ul>
  <li>wpcli Support (um Timeouts beim Export zu umgehen)</li>
  <li>Custom Permalinks Unterstützung</li>
  <li>Export des gerenderten, anstatt des in der DB gespeicherten Contents (wenn man viele ShortCodes verwendet hat ein Lebensretter)</li>
  <li>Konvertierung von HTML zu Markdown wo es möglich ist</li>
</ul>

<p>Ich habe den Umzug diesmal mit Hilfe des Plugins vorgenommen und hatte dadurch wesentlich weniger Aufwand bei den Nacharbeiten.
Die ganzen Media Files habe ich mit Hilfe eines <code class="language-plaintext highlighter-rouge">rsync</code> in mein Jekyll Verzeichnis gezogen und einmal via Suchen &amp; Ersetzen über alle Dateien 
die Pfade angepasst.</p>

<p>Bzgl. SEO war mir in dem Falle nur die URLs der Posts wichtig und diese wurden 100% korrekt übernommen. 
Sollte man hingegen für die Bildersuche optimieren sollte man den rsync Schritt 2x überdenken und lieber bei der <code class="language-plaintext highlighter-rouge">wp-content</code> Verzeichnisstruktur bleiben.</p>

<p>You know what they say:</p>

<blockquote>
  <p>A good URL never changes</p>
</blockquote>

<p>Fuck it. Google mit seiner Bild- und Trafficklau Suchmaschine ist mir herzlich egal. 
Hauptsache die Bilder in meinen Artikeln werden vernünftig angezeigt.
Da es sich hier um meine persönliche Seite handelt, kann ich ja machen was ich will und muss auf keine Rankingverluste Rücksicht nehmen.</p>

<p>Und da ich gerade so schön in Fahrt war, habe ich in dem Zuge auch einige alte Posts gelöscht und die Seitenanzahl um ca. 100 Einträge gedrückt, 
da ich in Jekyll auf Kategorie- und Tag-Archive verzichtet und dies lieber über die <a href="/tags/">Archiv-Sitemap</a> gelöst habe.
Das ganze bietet sich ab einer gewissen Posts Anzahl nicht mehr an, für mich funktioniert es aber noch ganz gut.</p>

<h2>Was sonst noch?</h2>

<ul>
  <li>Von über 700kB und etlichen CSS und JS Dateien auf ca 210kB pro Seite mit je einer CSS und JS Datei
    <ul>
      <li>Einzig der genutzte Font liesse sich noch wegoptimieren, aber ein ganz klein bißchen Style darf dann doch übrig bleiben</li>
    </ul>
  </li>
  <li>Umzug zu GitHub Pages, keine Ops-Arbeit mehr mit Certbot, kein PHPFPM, keine MariaDB, keine Deployments mehr notwendig</li>
  <li>Ein neuer Blog Artikel bedeutet jetzt nur ein neues Markdown File</li>
  <li>Und ein neues Design war auch überfällig, das alte war ja schon sicher 2 Jahre online … wo bleibt da der Spaß?!</li>
</ul>

<p>Die Umstellung lief einwandfrei:</p>
<ul>
  <li>CNAME in GitHub angepasst</li>
  <li>die A-Records auf GitHub Pages umgebogen</li>
  <li>eine Stunde war die Seite online</li>
  <li>und nochmal 24h später die Wordpress Seite gelöscht, yeah!</li>
</ul>

<p>Wie war nochmal der Werbe-Slogan: <strong>Technik die begeistert</strong>!?!</p>]]></content><author><name>Kevin Papst</name><email>kevin@kevinpapst.de</email></author><category term="Jekyll" /><summary type="html"><![CDATA[Nachdem ich nun seit Jahren auf verschiedensten Seiten Jekyll (den statischen Webseiten Generator) einsetze und auch seit mehr als 1 Jahr darüber blogge, wurde es endlich Zeit meinen eigenen Blog weg von Wordpress und hin zu Jekyll zu migrieren.]]></summary></entry></feed>