PHP Reddit – Telegram
PHP Reddit
34 subscribers
286 photos
36 videos
24.7K links
Channel to sync with /r/PHP /r/Laravel /r/Symfony. Powered by awesome @r_channels and @reddit2telegram
Download Telegram
Show the progress of your background jobs in your UI and support cancelling running jobs safely
https://redd.it/1oyynco
@r_php
Weekly Ask Anything Thread

Feel free to ask any questions you think may not warrant a post. Asking for help here is also fine.

https://redd.it/1oz6q1c
@r_php
Weekly help thread

Hey there!

This subreddit isn't meant for help threads, though there's one exception to the rule: in this thread you can ask anything you want PHP related, someone will probably be able to help you out!

https://redd.it/1oz9n6n
@r_php
Disappointed in Laracon AU

It's a trend I've noticed over the last few years, but Laracon AU was probably the final straw.

All credit to Michael and the Laracon AU team, I know organising such an event can't be easy, but the lack of technical talks at what is meant to be a technical conference was really disappointing. And I'm not the only one - my entire team was really disappointed.

For context, we're all senior engineers from 7 to 20+ years experience, and Laracon (of which I've been to 7 across the world) used to be very technical in nature. It either had lots of cool Laravel stuff (such as deep dives into the framework), business stories regarding challenges that were solved, or PHP-related stuff, such as design pattern implementation talks or DDD content.

But of all the talks that were there, only 2 were somewhat technical. First there was James' talk on Laravel Forge and some of the decisions and solutions made there (which was my favourite of the two days), or Auth factories by Mary, which was unfortunately hamstrung by her confusing presentation of the use of factories in Laravel (which weren't wrong, but was convoluted by poorly-communicated examples). I could see what she was going for, but after talking with other seniors at the conference, they were also really confused and found it hard to follow.

Lastly, Jason McCreary's talk on Blueprint was interesting, but not really aimed at senior engineers.

In reality, there was literally no content that provided any value to senior engineers, and so the value of the conference to us was zero.

This is not what Laracon used to be. Half our team also went to the last Laracon EU and felt the same way - that the value of the conference for senior has gone down.

It seems to me the conference is now only aimed at beginners, in addition to an underlying thread of political points that have been present since 2016 and is honestly rather trite.

I really hope this changes, as we've discussed internally that'll likely be the last Laracon we attend, and instead look to other conferences - and I think that's really unfortunate. I have such fond memories of the first few laracons in US/EU and always came away inspired and refreshed, so it's disappointing that the last few have left me feeling rather empty.

I know this feeling isn't universal, I spoke to several other people who enjoyed the conference, but for me and my team, it's hard to be excited about future Laracons.

https://redd.it/1ozdebg
@r_php
Web Socket (Soketi)

Has anyone worked with Soketi (https://docs.soketi.app) as a WebSocket server?

I'm trying to integrate Soketi into my application. I already have it working in my local environment, but I'm having trouble getting it to work in production.

The production environment is a bit more complex than local. The Laravel application runs on two different servers behind a load balancer, and I need to host the Soketi server on a third server for scalability purposes. However, I haven't been able to make it work.

Has anyone dealt with a similar setup and could provide some guidance?



PS: The application is multi-tenant.



https://redd.it/1ozffxp
@r_php
You should reinstall Claude Code

I experienced this exact thing over the weekend. Couldn’t figure out why running php artisan test was wiping out the data in my dev db. Hopefully this helps others out as well

https://x.com/matthieunapoli/status/1990092916690501957?s=46&t=5eaP5DWavAxUxYvsVFS-Kw

Claude Code users (especially Laravel/Symfony): you REALLY want to re-install Claude

Latest Claude versions will load your .env (including secrets!) into Claude Code. Claude then runs your tests with local config instead of testing config!

I found this because my Laravel tests in Claude Code failed with CSRF errors (419), but pass in my terminal.

That is caused by @bunjavanoscript (NodeJS alternative).
Claude Code recently moved from "install via NPM and run via Node" to "download a self-contained binary". Except that binary is running Bun under the hood.
And Bun automatically loads .env files (wtf!)

Which means that your Laravel local config (.env) gets loaded, forcing tests to run in local environment instead of testing, with your entire local config (including tokens & such). If your local DB gets wiped because of Claude, you now know why.

You really want to move back to the npm version of Claude Code:

rm ~/.local/bin/claude
npm install -g @anthropic-ai/claude-code

https://redd.it/1p02w90
@r_php
Laravel conventions as a mantra for development, is wrong (maybe)

First let me state upfront that conventions by themselves are not a bad thing. They provide an easy, simple, jumping-off point for new developers, as well as h3lp (*the real word prevents me from posting here - wtf?*) with cross-project onboarding, and familiarity. However, a trend I have been aware of for quite some time is that we should not change these conventions, that we should leave them alone. That is both an ideological and unrealistic viewpoint to hold. As developers, we ***need*** to be more pragmatic than this.

I regularly feel that many in the Laravel community have never worked on large, long-lived, complex projects, including those who speak regularly and are often considered the face (or faces) of Laravel. I am not however, referring to Taylor or any others of the Laravel team.

One of the main reasons I have been using Laravel since version 3, is the fact that the framework gets *out of my way*, when I need it to. Before Laravel, there had not been a single web framework I had used where I was not fighting it to do what I needed, including Ruby on Rails. With Laravel, I've ***almost*** ***never*** had that problem. Laravel establishes sensible conventions, but you can change or ignore these conventions in favour of approaches that better align with your business requirements or technical challenges, as the need arises.

I also want to be clear that when I talk about "Laravel conventions", I am not necessarily talking about the way in which a new Laravel application is created, but also community-led or supported conventions.

So why do I think Laravel conventions are not great for large projects, and why do I think that claiming that you should only stick to conventions, is a fallacy?

# 1. Directory structure by file type

This is (in my humble opinion) the worst laravel convention. However, I acknowledge that it is likely the easiest mental frame for many to adopt, as it requires little to no context of the application you're working on. Need a controller? No problem, head to the Controllers directory. Looking for models? You know where to find them. However, in a large application, this very quickly falls apart, as you can easily end up with 100s of controllers, models, form requests, anything - and this makes the provided structure difficult to work with, as it implies that all these things are related. They're not. The only thing have in common, is the type of PHP file that they are.

Secondly, this results in related code being split across the application, rather than living next to one another. For example, were I to look at a single request lifecycle, I'd likely need to go to FormRequest directory, a Controllers or Actions directory, the Models directory, perhaps some another Services directory.etc.etc.

It is my opinion that folder structures should be as flat and simple as possible, until such time as it actually makes sense to start categorising your project's files in some other way. This also forces you to be more careful with the naming of those files, classes.etc.

Let's start with a made-up set of features around Users. Perhaps we support registration and profile management, a routes.php file for all user endpoints, a User model, a bunch of form requests.etc. An initial starting point, might look like the following:

* User.php
* RegistrationController.php
* ProfileController.php
* RegistersUser.php <- FormRequest
* SendEmails.php <- listener for sending notifications/emails
* UserRepository.php
* Users.php <- Collection
* UsersServiceProvider
* routes.php

Now whether you like or dislike this approach, is irrelevant for the moment. The fact is that everything related to user registration, profile management, persistence, notifications and validation are all here. I can see it all in app/Domains/Users (as an example). I even have a routes file that registers only the routes specific to those requirements. In short, I can see a complete, vertical slice of this particular domain/subdomain at a glance.

Now I know what
you're thinking, this would quickly become unwieldy, with 100 files there. And you're absolutely right - which is why this is a starting point, not the end result. This is just where we jump off from, and as more features are added and boundaries start to define themselves, grouping logic starts to emerge from our code, so we change it. Refactoring this sort of thing is not difficult, particularly if you're using a proper IDE (like Jetbrains). *Cue IDE wars discussion :P*

If this folder started to get too big and hard to see what's going on, I'd likely break it down into Registration and Profile subfolders, but again - all the code related to those features are right there, there's no need to go anywhere else. It also makes it easier to find things that can be hard to locate, such as event listeners.

Let's move on.

# 2. The action pattern

First, like before - a few caveats. I don't hate the action pattern, I've used it myself, and I think it's a great approach, when it makes sense to do so. However, the starting premise regarding the use of the action pattern, is logically incorrect. If you read some articles, they'll talk about how controllers have too much business logic, therefore - use the action pattern. This is paired with the often-misunderstood "single responsibility".

Using an action class to handle what was previously a single controller method, does not resolve the Single Responsibility problem that was seemingly identified. Your action class is still handling http requests, still fetching data from the database, still making state changes to models through leaky abstractions via Eloquent, and still crafting responses. If your business logic was in the right place to begin with, you probably wouldn't reach for the action pattern.

Put another way, your action classes aren't doing what you think they're doing, you're just moving code from one file to another. If you really care about business logic and where it belongs, there's only a few places they can realistically live: commands (no, not console commands - a [command bus](https://www.arnaudlanglade.com/command-bus-design-pattern/)), or service classes.

>I could talk for days about the command bus and how critical it is for well-designed applications, but that's out of scope for this already very lengthy post.

Here's an experiment you can do yourself: are you able to unit test your business logic, without using Laravel classes, models, or providing mocks? No? Then you haven't isolated your business logic. You've just moved code around. Ideally you write your business logic and test that it all works, before wiring it up to the external world, ala Laravel, but I digress.

Secondly, the action pattern results in more code, not less. If you're using controllers, you can share dependencies via the constructor, and have just the dependencies unique to a specific use case injected as part of that specific controller method. If your controllers are massive, there's likely too much going on anyway, and so it's likely that your controllers aren't built to serve well-modelled domains. Eg. Having user registration exist as part of a UserController, rather than having a specific RegistrationController that handles rendering the form, creating the user, confirmation of the account.etc.

I *can* *hear* the ruffled feathers, so let me extend an olive branch...

I am not saying the action pattern is bad, or that you shouldn't use them. They present a very nice, clean way of having code that represents a single feature or use-case in one spot, and works really well in smaller applications. However, don't use them to just move business logic from your controllers to actions. As web developers, we did this 20 years ago, moving business logic from models to controllers. We're having the exact same conversation we had 20 years ago, today, because we collectively still do not understand where business logic ***belongs***.

Think more deeply about where that logic should live, and ask yourself if the action pattern is really serving you in that regard. If you're unsure, DM
me and ask, or comment below! I love helping others and provide insights where I can (mentoring is a passion of mine).

# 3. Repositories and Eloquent

I want to say first of all that I think Eloquent is *brilliant*, and by far one of the best, if not **the** best implementation of the ActiveRecord pattern I've seen. Therefore, my criticisms of Eloquent are not really about Eloquent itself, but more the ActiveRecord pattern that it utilises to make database access and development so damn easy! So whenever I mention Eloquent, it's really just to reference a collective understanding that represents the ActiveRecord pattern.

The main problem is that using Eloquent, well... it's ***too*** easy. It allows you to shoot yourself in the foot, and this becomes a larger problem as your codebase grows. Let me explain.

**Leaky abstractions**

When you work on a codebase long enough (which btw, is a testament to the business for having lasted so long), you begin to see and experience issues with the use of Eloquent. The first is that leaky abstractions make it *very* difficult to replace it ($model->save()), should you need to. This probably sounds theoretical in nature, and for most projects it probably is, but... and I shall quote the Dark Knight here...

>"You either die a hero, or ***live long enough*** to see yourself ***become*** the ***villain***" - Harvey Dent

I love this quote, first because the Dark Knight film was badass, but secondly (and most importantly for this post), it is a perfect encapsulation of the nightmare that Eloquent can become in your codebase. At this point I'd like to reference Shawn McCool's excellent article on the issues around ActiveRecord, a fantastic read if you're interested: [https://shawnmc.cool/active-record-how-we-got-persistence-perfectly-wrong](https://shawnmc.cool/active-record-how-we-got-persistence-perfectly-wrong)

Let me give you a real world example, rather than wax lyrical about "theoretical" problems. 5-6 years ago we needed to support complex search requirements. MySQL just wasn't up to the task, even with well-aggregated (denormalised) data structures. So, we wanted to use ElasticSearch so that we could provide the search features our clients needed. At that time, just one model that we had to replace took 2 months of heavy development, because of leaky abstractions, and expectations on a model that did not conform to an interface (and you can't, in Eloquent, do that nicely, or easily, due to potential name clashes, complex attribute access methods.etc.).

So we ended up replacing the use of Eloquent for that particular feature, migrating the data across.

A leaky abstraction is where you're working with an object, and calling methods or properties that do not belong to that object, such as my example above: $model->save(). That's not **your** code, that's **Laravel** code. Of course, any class we implemented to represent an ElasticSearch object didn't have a save method, so we now had one of two choices, either:

1. Re-implement the save method and any relationship methods it had or
2. Have a better solution in place in case we have to replace it *again*.

We went with the latter, and the resulting system was cleaner, with well-defined responsibilities and boundaries. This was helped ***a lot*** by our use of the repository pattern, because save() was actually encapsulated inside the repository, as were many other Eloquent methods, meaning outside of replacing things like $model->attribute calls, we needed to replace our EloquentSearchRepository with one called ElasticSearchRepository.

This is just one reason why calling relationships and other database access methods on Eloquent models can cause you nightmares down the road: you never know when you're going to need to replace it. Eloquent allows you to reach into totally separate domains and access their data, meaning you have eloquent tendrils everywhere in your codebase. This is even more of a problem than accessing dynamic attributes. But let's stay on repositories for a minute.

Repositories do two things **really**
well:

1. They encapsulate any database access and return the required object and
2. They become a repository for complex queries (huh, maybe that's why they're called that?)

You can also do really cool stuff with them, like wrap them in a decorator for caching, swap persistence strategies at runtime (maybe you have a Redis front, but fallback to the rdbms if redis is down). I've seen criticisms around Repositories which again make me feel like those authors or creators have never worked on a large, complex, evolving application before. They just don't seem like they've seen the front battlelines, they've never been in the trenches, as many seniors have. Ignorance is bliss, as the saying goes (that's not a hateful comment, btw - I'm genuinely jealous).

# Tests alongside code

In almost every PHP project I've seen, and definitely all Laravel projects, all tests live in the tests/ directory, and often mimic the directory structure of your application, where you can find (hopefully) a 1:1 mapping of test file to class file. With 500k lines of code in an application, and 10000 unique test cases, and 40000 assertions, this becomes a real mess. What we do, is the following: our tests live right alongside the class they're testing. And, we go one, manic step further:

* User.php
* User.test.php

The astute amongst you have already noticed the break away from conventions, here: our test file extension. User.test.php is still UserTest as a class, but we call it .test.php so that the file is literally right next to the class it's testing. Else you see silly things like this:

* User.php
* UserRepository.php
* UserService.php
* UserTest.php
* UserRepositoryTest.php

This might seem a small thing, but on large applications it's a real pain, particularly if (in some of our cases), the folder has 30+ files (including tests). It just becomes harder to manually find the test you're looking for (of course, you can always use your IDE shortcut, which is what we mostly do, but sometimes you just gotta eyeball things - **O.O**).

This is supported by our phpunit.xml configuration, as well as some custom bindings/setup to make it all work.

Is it the right approach? Not necessarily, and maybe not for your project. But ever since we started doing this, I do this in all of my projects now. This is true of our feature/acceptance tests as well, where they live alongside the controller or action they're designed to test. This has the added benefit of seeing where there are obvious gaps in our test suite, without needing to do any code coverage analysis, which by the way, can take forever and a day on a large code base!

I'll wrap this up because I have a bunch more I could write and am thinking about doing so on my own YouTube channel (to come soon), but I could honestly write full essays on each of these points, and will likely talk about them in even greater detail in long-form video.

So let me close by reiterating what I've said before. I am not against all these things or their nature. They have their uses, and they work great at various application sizes, it depends on the use-case. What I am against, is evangelical/ideological views that make bold claims that X is bad and should never be used or Y is the best, always use it. I am against the claim that you should "just follow laravel/php/node/whatever conventions". These are arguments that are not rooted in reality, and lack critical thinking, they lack nuance. As a senior software engineer, you need to be thinking critically about every... single... layer. You have to be a slave to nuance, details, or you'll miss things, and you'll make mistakes, mistakes that cost you or your company a fortune.

It is important as developers that we continue to learn and grow, but most importantly, ***be pragmatic***. The suggestions I've made here are not to say "you should replace all conventions or you're a bad developer". Quite the contrary - I've offered alternatives and reasons for doing so, *when it makes sense*, that you do not ***need*** to follow conventions just because someone told you
to.

Every engineering concept has its use-case, its pros and cons, and has gotchas that you need to be mindful of. But as you master your craft, you begin to understand the intent behind these approaches, how best to utilise them so that you can reap the greatest value they provide. Don't do something because someone told you to, do it because you find it interesting and want to continue to grow, and in doing so, become the Engineer you were always meant to be.

If you made it this far, thank you - I value your time and hope I was able to communicate the thoughts that have been running around my head for the last few years. Let me know what you think, and if you disagree, even moreso. I like being challenged and being proven wrong, because it means I learnt something new, and that makes me a better Engineer.

Cheers!

https://redd.it/1p04d6e
@r_php