Brian MoonHow I got Disc Golf Network Pro for FREE for 2024 (20.2.2024, 17:48 UTC)

Do you plan to go to a DGPT event this year? Are you a PDGA member? Then it could be worth it to buy the Disc Golf Network yearly plan.

Disc Golf Network (aka DGN) (the media arm of the Disc Golf Pro Tour) (aka DGPT), announced their new pricing tiers for 2024 earlier this month. It was met with some mixed reviews. Some users of the service had issues using it the first week. Most of those appear to be due to users needing to update the app on their devices or using older streaming devices that do not support the new 60fps stream. They have updated their upgrade guide. I experienced this on one of my Roku devices. I was not surprised to be honest. Many of the Roku apps we use on that device are laggy and crash from time to time. It is over 10 years old. The fact that it has kept working at all is a credit to Roku.

As for the pricing for DGN, there are three tiers: Basic, Standard, and Pro. See the link above for the differences. The pricing ranges from $5.99/mo to $19.99/mo for non-PDGA members. While PDGA members can get Basic for free, Standard for $5.99/mo, and Pro for $12.99/mo. There are also yearly options. Basic for $59.99, Standard for $129.99, and Pro for $239.99 for non-PDGA members. And for PDGA members, Standard for $69.99 and Pro for $139.99. Since Basic is free, there is no yearly option for PDGA members of course. Most people I know that want to consume live disc professional disc golf are PDGA members. While some say you have to factor in the $50 annual PDGA membership cost along with the discounted DGN price, that does not apply to me. I would be renewing my PDGA membership either way. So, I will only be speaking about how and why I chose the option I did based on the discounted PDGA pricing.

The first question I had to ask is what do I want to pay monthly or go ahead and pay for the whole year? The Standard plan annual cost only saves you $2 for the year. Not a compeling reason to do it in my opinion. The annual cost for Pro actually saves more than the cost of a month, $139.99 one time compared to $12.99/mo over 12 months totaling $155.88. There are some ways to save if you change your plan for certain months for certain events or remember to cancel after the DGPT Finale in October. But, let's be real. I won't remember to do that. Most people won't remember to do that. That is why the subscription model is so popular in the USA. That is how gyms stay in business to be honest. If you are the kind of person that likes to manage subscriptions that way, go for it. If you micro manage it completely and only pay for February through October and upgrade the months of the USDGC and European Open, you could get all of the coverage for as low as $88.89 for the year as a PDGA member. I think I did that math right. You are probably saying "Hey, your headline says you are getting it free for the whole year! What gives?" Yes, let me get to that.

Here is why I opted for the full year, Pro plan. It’s $139.99 for the year. The kicker for me is that any yearly plan includes two free general adminssion (aka GA) weekend passes to a Disc Golf Pro Tour event as well as 10% off any other DGPT ticket purchases. As a family, we had already booked an AirBnB for Nashville in April to go watch the Music City Open before this announcement was made. My two sons and I are going for all three days. And two other family members will be joining us for Sunday. I had planned to get the weekend VIP pass for myself. So, altogether, our tickets to the Music City Open were going to cost around $350. However, with the yearly DGN option, I get the GA passes for free. And I get a 10% discount on the other tickets. Those ended up costing me around $210 after the discount. So, my savings on tickets (tickets I had already planned to buy before I knew there was a discount available) is around $140. That is the cost of the yearly plan. If you include all of the decimals in all of the math, I technically am spending 17 cents more on the DGN subscription than I am saving on tickets. Would that make a better headline?

Ticket Quantity Regular Price DGN Discounted Price
3-Day General Admission 2 $116.88 ($58.44/ea) FREE
Sunday General Admission 2 $71 ($35.50/ea)

Truncated by Planet PHP, read more at the original (another 2788 bytes)

Matthias NobackNew edition for the Rector Book (12.2.2024, 09:30 UTC)

The cover of the 2024 Edition of the Rector book

A couple of weeks ago, Tomas Votruba emailed me saying that he just realized that we hadn't published an update of the book we wrote together since December 2021. The book I'm talking about is "Rector - The Power of Automated Refactoring". Two years have passed since we published the current version. Of course, we're all very busy, but no time for excuses - this is a book about keeping projects up-to-date with almost no effort... We are meant to set an example here!

In the meantime, a lot has changed. Tomas has become a very successful legacy-project-saver, with this incredibly powerful tool called Rector. The project has gained a lot of traction in the PHP development community. Tomas and the co-authors of the project keep improving the tool, making it more useful, developer-friendly, faster, and more stable every day. Recently he released version 1.0 on-stage at Laracon Europe, in Amsterdam. In important moment, which indicates that we are dealing with a mature tool.

I know Tomas as a hard worker. He'll do everything to Get Things Done. He keeps simplifying things, even in the Git project that's behind the book's manuscript. Always looking for ways to prevent developer (or writer) mistakes and to automate common tasks, he ruthlessly cuts away unnecessary weight. When he reads a convoluted paragraph that works around some quirk in Rector, he fixes the issue in Rector, so the text is once more easy to understand. If people ask the same questions over and over again, he adds a helpful command to Rector's command-line interface, so the question will disappear. In other words, he has a great idea for feedback. What kind of signal does the code give us? Is this too hard to work with? Can we simplify this? What kind of signal do we get from readers? Let's improve!

With a 1.0 version for Rector also comes a new version of the book about Rector. This 2024 Edition provides an even better start for your static analysis & automated refactoring journey. I can testify personally: once you start, you'll never want to go back.

Read more about the updates on Tomas' blog: Rector Book 2024 Release with Brand new Chapter

And get the new version here:

If you already bought a previous version, you can download the latest files for free (of course!).

Evert PotOAuth2 client updates (5.2.2024, 15:00 UTC)

I just released v2.3.0 of @badgateway/oauth2-client, which I wrote because there weren’t any lean, 0-dependency oauth2 clients with modern features such as PKCE.

This new version includes support for:

  • Resource Indicators for OAuth 2.0 (RFC8707).
  • OAuth2 Token Revocation (RFC7009).

Hope you like it!

Derick RethansFriday Night Dinner: East Street by Tampopo (26.1.2024, 18:30 UTC)

Friday Night Dinner: East Street by Tampopo

The idea behind going for a different restaurant every Friday is to try out a wide variety of places, but also of cuisines. We are lucky that in London, we have access to pretty much any sort of dishes we fancy.

Sometimes, you can even find a wide variety of different culture's food in one place, and East Street is such an establishment. It is situated just North of Oxford Street, close to Tottenham Court Road station. It specialised in what can only be described as pan-Asian.

Their menu is extensive, from Szechuan dishes via Japan and Korea to Indonesian and Malay. We started with two of their small plates, the Malaysian Satay Chicken and Korean Popcorn Chicken. They were both delicious, very flavourful and moorish. Good Satay Chicken I remember from my parent's Indonesian friends, and this was just like it. With our starters, we enjoyed a lovely Hokkaido Negroni as we didn't think a bottle of wine would fit with this menu.

Choosing the small plates was hard, as there are so many nice sounding ones. Instead of ordering them all, we also picked a large plate each. I ordered a Rendang Beef Curry, again, with memories of the Indonesian Restaurants you find in the Netherlands. It was accompanied by rice, peanuts, boiled eggs, and some pickled cucumber. My companion ordered a Tamarind Chicken, slices of well cooked moist chicken in a delicious sticky tamarind sauce. It came served with rice, broccoli and crispy onions, this was one of the non-spicy options on the menu, but despite the lack of chillies still had a bit of a kick. Again, not wanting wine, we picked a bog-standard Tiger beer to wash all the delicious flavours down, which paired pretty well.

Although we were pretty full, we could not quite resist the churros, and shared three with a tasty caramel sauce. I don't quite understand how they fit in an Asian kitchen, but they were delightful regardless.

If we were to return, which seems likely, we would probably have a meal made up of more of the smaller dishes (all of which sounded delicious) instead of going for the traditional starter plus main course approach.

The place was pretty full, and when we left I remarked that we were probably amongst the oldest of the clientele, but we didn't feel out of place. Which I think is a good sign.

1 / 5
Chicken Satay
2 / 5
Popcorn Chicken
3 / 5
Tamarind Chicken
4 / 5
5 / 5
Become a Patron!
Derick RethansFriday Night Dinner: Empire Empire (19.1.2024, 18:30 UTC)

Friday Night Dinner: Empire Empire

We visited Empire Empire on a chilly January evening. The restaurant was fairly quiet but even at 18.30 there were some tables seated and enjoying their food.

The restaurant features an old fashioned jukebox type vinyl record player close to the entrance and has a photobooth for some fun snaps should you be so inclined.

We had a beer each from 40ft Brewery in Hackney, which was lovely. It's great to see an Indian restaurant branching out from the usual cobra and kingfisher options. We started with poppadoms and dips, and then I had a well spiced biryani with incredibly tender lamb falling off the shank and a pastry lid. My companion really enjoyed her Empire Butter Chicken and a naan bread. This was not as rich as some butter chicken curries, but was incredibly flavourful with a nice level of spicing and kick. Unfortunately we were both too full to move onto try what sounded like tasty desserts from the menu.

Service at Empire Empire was very welcoming and attentive (and quick, but not rushed) we were out and heading home on the bus about an hour after sitting down.

Butter Chicken
1 / 2
Lamb Biryani
2 / 2
Become a Patron!
Derick RethansFriday Night Dinner: Lokkanta (5.1.2024, 18:30 UTC)

Friday Night Dinner: Lokkanta

As first restaurant of the year, we wanted something low-key. Not far from Paddington station, on Westbourne Grove, there is a whole row of such places. We settled on Lokkanta, a place that specialises in Turkish food.

We started off with Turkish sausage slices with halloumi, while we were waiting for our main course. At the same time, we started enjoying our delicious red wine from Turkey.

The front section of the restaurant features a well ventilated charcoal grill upon which most of the meats were roasted. In my case, a well cooked and flavoured lamb shish. My partner picked a Yogurtly Adana, minced grilled lamb with bread and basted in a tomato sauce and yoghurt.

The service was speedy, and we did not have to wait long. Perhaps that was mostly because when we arrived at 18:30, there was only other table enjoying dinner, so we were almost the only customers. When we left, there were a few more people enjoying their dinner. However, with the restaurant being quite empty, it perhaps lacked a bit of ambience and the tiled interior made it feel a little clinical, I think it would be quite different if it was busy with plenty of hustle and bustle.

In short, the food and wine was good, but the atmosphere was unfortunately missing.

Become a Patron!
Derick RethansFriday Night Dinner: Ma Petite Jamaica (29.12.2023, 18:30 UTC)

Friday Night Dinner: Ma Petite Jamaica

What do you need on a cold and dark winter evening? Exactly, a bit of tropical warmth. Our booking was a little last minute, as we hadn't really thought about arranging something for the last Friday of the year. My wife, who often takes the lead in picking our Friday evening restaurant, suggested this Jamaican place in Camden, not too far from where we live.

We arrived to find the dining room partially full, with Jamaican musing playing and (fake) palm trees. It gave a happy and homely feel to the dining room.

I had never had Jamaican food, so decided that I wanted to try the staples. As my starter I picked the ackee and salt fish, which was served with fried dumplings. My wife chose the chickpea and pumpkin curry. We also decided to share a portion of the jerk chicken spring rolls. All three small plates were very flavourful. With enough hints of scotch bonnets to add a kick, but nothing too overpowering. The dumplings were great for dipping up the sauces.

Because we felt we needed to escape from the cold, we enjoyed a pair of Jamaican Mule cocktails, with our starters, and later mains. The first set was half price as it was still happy hour! There were also a number of Jamaican beers on offer, with a Red Stripe on tap.

I selected the curried goat with rise and peas as my main course. My wife wanted to order a wrap, which they were no longer serving, although they were on the menu. She ended up with their vegetable curry with a roti. Both were excellent.

Our only regret was probably ordering too much food. One and a half starter, and a full main per person was certainly too much. But that's not the worst problem to have if your dinner was so tasty.

Fried Dumpling, with Ackee and Saltfish
1 / 2
Curried Goat
2 / 2
Become a Patron!
Derick RethansFriday Night Dinner: Noon (22.12.2023, 18:30 UTC)

Friday Night Dinner: Noon

Even when we're out of the country, we try to keep our tradition in place, and so we found ourselves on a cold and rainy evening at Noon, in Maastricht, in the Netherlands.

When we arrived just after 18:00, the restaurant was already quite full. With a few dozen tables, some high tables, and a bar where a bar keep was making plenty of colourful cocktails. We were seated at a high table right in the middle of the stylishly appointed establishment.

While enjoying a glass of cava, we shared a couple of starters. The Drunken Salmon (salmon cured in gin and yoghurt), and the Asian slow-roasted Pork Belly. Both were excellent. Flavourful and succulent.

For my main, I chose the Asian Ribs. I realised it was another Asian-flavoured dish — I know, "Asia" isn't a country. I am usually not keen on ribs, but these were boneless, and that made all the difference. That, and the lovely, and slightly spicy sauce that was slathered over the ribs with a few tiny bits of red chilli.

My partner's choice was the butter steak, medium rare. That came with carrots and a delicious mushroom foam. The sauce was made with Pedro Ximénez sherry, and had a nice shine to it. With our mains, we each enjoyed a glass of Merlot. The only (minor) let down were their chips that were served with our mains. They were slightly chewy.

It was a very enjoyable meal in a charming environment, and with very reasonable prices. A great birthday meal!

Become a Patron!
Matthew Weier O'PhinneyAdvent 2023: PSR-15 (14.12.2023, 23:21 UTC)

I've mentioned a few times over the course of this 2023 Advent series that the longer I'm in the tech field, the more I appreciate and favor simple solutions. I was reminded of this yesterday when I read this article on return types in Laravel controllers by Joel Clermont.


Please, please, please do not take this as an attack on Laravel or on Joel. I have nothing but respect for Joel, and while I'm not a fan of Laravel, I'm also not a hater. It's never a bad thing to have a popular framework that brings folks to a language; Laravel has done that in spades for PHP.

Summarize the article, already...

In the article, Joel notes the problem with providing return types in a Laravel controller is due to the fact that it could return a view, a JSON response, an array, a redirect, or more. If there are multiple types that could be returned, based on the request context, you would need to provide a union type. And if you refactor or make changes to the controller later that result in new types being returned, you now need to remember to change the return type declaration.

In other words, it introduces brittleness.

So what?

I've worked on multiple iterations of a major MVC framework, and I ran into these same issues. As PHP's type system got incrementally better, the cracks in how frameworks interact with controllers became more evident. Personally, I find the increasing number of type capabilities in PHP to be a huge boon in helping the correctness of applications, and preventing whole classes of errors. But if the framework prevents you from using the type system, or makes adding type declarations into a situation that can now introduce errors, it puts the developer and maintainer of an application into a problematic situation.

What are the alternatives?

I worked for quite some time on PSR-7 HTTP Message Interfaces, largely so that we could have a proper HTTP message abstraction in PHP on which to build a better foundation for applications and frameworks. From this emerged PSR-15 HTTP Server Request Handlers (which I sponsored and collaborated on, but was not primary author of).

What I love about PSR-15 is that there is no ambiguity about what you return from middleware or a handler. You return a response. That's all you can return.

This means there's no magic about different return values resulting in different behavior from the framework. You don't need to keep a mental map about what will happen, or do a deep dive into the framework internals to understand the ramifications of returning a view versus an array.

Instead, your handler will create a response, and provide the logic for how that is done. If you need HTML, you render a template, and feed it to the response. If you need JSON, you serialize data to JSON, and feed it to the response. If you need a redirect, you create a response with the appropriate status code and Location header. And so on and on.

Yes, this can lead to a little extra code at times, but:

  • You can see exactly what you intend to return to the user, and why.
  • If you try and return anything but a response, it'll result in a TypeError.
  • You can test all of the different possible returns easily, by doing assertions on the returned response based on different requests provided to the handler or middleware.

But should you do everything in a handler? What about things that will happen for whole sections of the site, or will be repeated in many locations, like initializing a session, or checking for an authenticated user, or validating headers, or caching?

For those things, PSR-15 provides middleware. These are expected to be chained together, like a pipeline or a command bus, and the request is passed down through them, and a response returned on the way back up. They're a powerful way to provide re-usable pieces of functionality to your application.

What's more, using middleware is often far easier to understand than how and when various events will intercept a request. You can see the list of middleware for a given handler, and understand that they act either as filters on the incoming request (authentication, caching, etc.), or as decorators on the response (e.g. encoding or compressing the response, caching, etc.). Since each does exactly one thing (ideally), you can test how each works, and understand how and when to compose each, and how they might work in combination.

Truncated by Planet PHP, read more at the original (another 865 bytes)

Matthew Weier O'PhinneyAdvent 2023: Doctrine DBAL (11.12.2023, 15:21 UTC)

I've mostly taken database abstraction for granted since I started at Zend. We had a decent abstraction layer in ZF1, and improved it for ZF2. There were a lot quirks to it — you really had to dive in and look at the various SQL abstraction classes to understand how to do more complex stuff — but it worked, and was always right there and available in the projects I worked on.

In the last couple of years, though, we came to the realization in the Laminas Project that we didn't really have anybody with the expertise or time to maintain it. We've marked it security-only twice now, and while we've managed to keep it updated to each new PHP version, it's becoming harder and harder, and whenever there's a CI issue, it's anybody's guess as to whether or not we'll be able to get it resolved.

My alternatives have been straight PDO, or Doctrine DBAL, with the latter being my preference.

Doctrine what?

When most folks who use PHP hear "Doctrine", they immediately think "ORM"; it's how most folks use it, and what it's best known for.

Underlying the ORM is its database abstraction layer (hence "DBAL"). This library exposes an API that will work across any database it supports; this is essentially what zend-db, and later laminas-db, were doing as well. What most folks don't realize is that you can use the DBAL by itself, without the ORM.

Why no ORM?

ORMs are fine. Really. But they add an additional layer of complexity to understanding what you are actually doing. Additionally, if you want to do something that doesn't quite fit how the ORM works, you'll need to drop down to the DBAL anyways. So my take has always been: why not just use the DBAL from the beginning?

So, how does Matthew write code that interacts with the database?

I start by writing value objects that represent discrete aspects of the application. Most of my work will be in consuming or creating these. From there, I write a repository class that I use for purposes of persisting and retrieving them. I can usually extract an interface from this, which aids in my testing, or if I decide I need a different approach to persistence later.

I push the work of mapping the data from the database to these objects, and vice versa, either in the repository, or in the value objects themselves (often via a named constructor). Using these approaches creates lean code that can be easily tested, and for which there's no real need to understand the underlying system; it's all right there in what I've written for the application.

Some gripes about the documentation, and some tips

The Doctrine DBAL docs are a bit sparse, particularly when it comes to its SQL abstraction. And there's no "getting started" or "basic usage" guide. In fact, it's not until the third page within the docs that you get any code examples; thankfully, at that point they give you information on how to get a database connection:

use Doctrine\DBAL\DriverManager;

$connectionParams = [
    'dbname'   => 'mydb',
    'user'     => 'user',
    'password' => 'secret',
    'host'     => 'localhost',
    'driver'   => 'pdo_mysql',
$conn = DriverManager::getConnection($connectionParams);

They also provide a number of other approaches, including using a DSN (an acronym they never explain, but based on using PDO, likely means "data source name").

Once you have a connection, what do you do? Well the DBAL connection allows you to prepare and execute queries, including via the use of prepared statements. It provides a variety of methods for fetching individual or multiple rows, with a variety of options for how the data is returned (indexed arrays, associative arrays, individual columns, individual values, etc.). These retrieval methods are mirrored in the result instances returned when executing prepared statements as well.

And that brings me to the SQL abstraction.

First, it's really, really good. It's minimal, but it covers just about anything you need to do. If you need to write something complex, you probably can; the beauty is that if you can't, you can always fall back to a SQL query, and using the connection's API for binding values.

But the documentation could be better.

It felt like it was written by a database admin who has forgotten more than most people ever learn about databases, and never considered that

Truncated by Planet PHP, read more at the original (another 7318 bytes)

LinksRSS 0.92   RDF 1.
Atom Feed   100% Popoon
PHP5 powered   PEAR
ButtonsPlanet PHP   Planet PHP
Planet PHP