Laravel Horror Stories

I believe that most of us at some point in our lives were tasked with maintaining or updating a Laravel application that someone else wrote. Unlike other frameworks laravel is somewhat opinionated when it comes to what goes where. Thankfully the vast majority of things have a home somewhere in /app. Worst case scenario for beginners is that they have fat controllers. But is that the case?

**Case 1)** A friend of mine works for a very small web dev agency which at some point inherited clients from an other company that closed down. One of those clients wanted to change something in their website. Personally the first thing i do when i handle a new laravel project is look at the routes to get a feeling of whats going on. Well, that website used a new innovative architecture that was too complex even for Taylor to understand. EVERYTHING WAS INSIDE THE CONTROLLER. There we no models and you could see raw sql queries inside the controller. To be fair it could have been a lot worse. SQL queries inside the blade files.

**Case 2)** Someone asks me to add few features on a web app that was meant for a shipping company. After a day or so i get access to the Github repo. I start browsing the code and the first thing i see is a bunch of models sitting in /app. I open them and surprisingly they are well written. They only had defined relationships tho. I went ahead to see the controllers because that's where usually the horror starts. I open /Http/Controllers and i see only the base controller. Oh well.. I wanted to notify the client that the repo was out of date and that he hadn't pushed the controllers. The project was almost ready and that how i knew that there were controllers somewhere. SOMEWHERE. I checked one last time the web.php routes file and it was the default file. I then checked the api.php file. OH\_GOD.php.... It took a while to load because it contained 2000 lines. Each route had a closure and everything was inside the api.php file. WHY?????.php

Do you have anything interesting to share?

26 thoughts on “Laravel Horror Stories”

  1. Gonna keep a close eye on this thread to make sure I’m not doing something mentioned. We’re in the middle of migrating a pretty massive intranet and multi-tenant SaaS setup we inherited from spaghetti ColdFusion without any MVC or frameworks over to Laravel. So far I love it, that everything has a specific place to go, but it’s taking a while to learn where they all are. And unfortunately a lot of what we’re doing with our tenancy doesn’t seem to have a simple answer out of the box, so it’s frustrating when I see simple examples that I either can’t apply as-is or have to find a slightly different method for because our requirements are so complicated. Trying to stay as DRY as possible because we’ve got a lot of overhead for such a small team (3).

    Reply
  2. “`
    if ($user && $user->staff->level >= 1) {
    Route::get(“diary”, function (Request $r) {
    “`
    Here. Take some enterprise level security

    Reply
  3. I have had a case 1 before. I was working for a web dev company and a job came in for a friend of the boss. So he wanted quick turn around with little development. I think it was a basic shop site he wanted. I was like 1-2 months at best.

    So a day later I get sent a zip file with a Laravel e commerce site in it. I powered it up had a look round the site and it looked okay it all seemed to work. Looks like all I needed to do was add a few things and we could sell it. Then I look at the code if you can even call it that. Zero models, Two massive controllers, I think one was around 10,000 lines and every query was a DB query. No migrations just a sql file that the installer imports into the database.

    I found out off the boss that it was for sale on the theme forest website for £30. I had a look at the page when it was bought from. The owner claimed to have done everything the laravel way! At this point I was like I don’t need to see or ready any more.

    After a conversation with the boss, I didn’t end up working on the project, thank god.

    Moral of the story, don’t buy cheap Laravel projects form any site with out seeing code first.

    Reply
  4. Well, here’s my mess I’m sitting with right now.

    Three separate projects (plus other non-Laravel stuff) with poorly optimized databases with confusing table names (mix of English and local language).

    Two projects have recently been upgraded from 4.2 to 5.7 (not 5.8, for some reason, which was already released). But without test coverage I discovered quite a few functions that are now broken *in production*. Also, server is set to the wrong time zone, and so is the Laravel configuration and to fix it they change the dates when inserting or displaying values.

    Also, some really weird decisions. They lack interfaces for most stuff and apparently just added things right in the database. To get you started on how odd they’ve been working, take this scenario: Adding a page required you to add a key value pair to an array in the Model (why?) and a value to the routes. And a blade view containing a reference to a text identifier.

    It actually takes more time to add these sub pages than just copy + pasting a static HTML site and this is probably the only problem I’ve encountered so far that actually worked as intended, just that the way it works is incredibly silly.

    Reply
  5. A company I used to work for inherited a weird Frankenstein project that was half Code Ignitor 2 and half Laravel 4. Both frameworks were wired up with the same database. It was pretty hacky. All of the Laravel controller functions were in one giant PagesController.php. I could never wrap my head around whatever madness was happening on the CI side. Users would login using CI’s authentication and then the request was forwarded to a url something like “/pages/user/{id}/manual-auth” that was on the Laravel side. Then the user would then be “logged into” the Laravel side of the application.

    I was messing around with it and showed the boss, you could just bypass all that and change the url to any other id and you’d be logged in as that user. I was able to login as the original developer using the id 1.

    Even after that they wanted to recreate what was on the production server and then fix the authentication issues. I tried pulling the repo and running composer install, etc, but it turns out that the original dev working on it made all these changes to the core CI and Laravel files in the vendor folder (and similar changes to JS files in the node_modules folder) on the production server and without those changes, the application wouldn’t work (if you can call what was on the production server working).

    To top it off the dev that had worked on it before was hosting it and charging something like $800 or $900 a month for what looked to me to be a $20 a month DO droplet. The main thing they wanted us to do was get it running somewhere else cheaper. The production server also had like 45 second page load times and they wanted that improved.

    I tried literally copying all the files including the vendor folder and node_modules as it was on production and even then it wouldn’t run on a new server. There were some elaborate redirects allowing the CI routes to work with the Laravel routes.

    We hired an outside contractor who was “an expert in cleaning up disaster projects” to come in and move it to a new server. I told him about the vendor folder and node_module thing but he didn’t believe me. He ran composer install and npm install on the old production server and it broke the production site.

    When I left that company it still wasn’t working anymore and they hired the guy who originally managed it when all these terrible decisions were made to run the Laravel team.

    Reply
  6. Does anyone have a link to a GitHub repo with examples of bad practice? (Without naming and shaming unfairly). I’d like to see examples of good and bad projects so I can learn.

    Reply
  7. As a fellow greek Laravel developer, I’ve seen some horror projects from previous developers (from Greece and Middle East).

    1. **Blade templates, but stored in configuration files**

    A Laravel 4 project was sending emails using a blade template, but instead of @include the header and the footer, the Blade partials were stored in config files: `{!! Config::get(’email.header’) !!}`

    2. **Scheduled tasks, but with controllers**

    There was another project that needed to run some scheduled tasks, but there was no task scheduler or cron.

    So there was an AbstractController that EVERY controller was extending, and in its constructor there was a method that was calling other controller methods directly. E.g.: CustomerController::updateSomeData(), ManagerController::doSomething(), etc. So every time a request was hitting a controller, all these other controllers methods were being called before.

    3. **AjaxController**

    This was a AJAX-heavy project, but instead of having explicit routes for every endpoint and RESTful controllers, there was an AjaxController with 2000 lines for every action.

    Reply
  8. Kept having to fix migrations because a contract dev was given direct access to the production database and changing the database structure. He would send .SQL files to the client to upload as well. Kept on screwing up the deployment flow and a lot of time wasted cleaning it all up.

    Reply
  9. > and everything was inside the api.php

    I’m a bit of a Laravel novice. Are you saying stuff that should be in `/App/Http/Controllers` files was in the api.php route file?

    Reply
  10. I have seen (and dealt with) one with SQL queries and a lot of @php directives inside blade templates. It also has weird model names (mix of both local language and English). It’s terrible and quite difficult to read, but at least it’s modifiable without causing more disaster.

    Reply
  11. I work with a guy who absolutely refuses to work the Laravel way, but insists at every turn that he’s doing things correctly. He’s been programming longer than I’ve been alive but somehow has never written a class (in any language) until about a month ago. Says OOP is for idiots (and FP is a waste of time). But I digress…

    We were changing a route from using bigInt IDs to using UUIDs. My boss sent him an article explaining how to set UUIDs using model hooks in the boot method.

    ‘Too complicated.’ he said. Also, he complained about it being a ‘Laravel-only feature’ that wouldn’t work in base PHP. I have yet to figure out his logic on this statement, or who the fuck cares, because this code will never be run outside of a Laravel application!

    So instead, he OVERRIDES THE MODEL CONSTRUCTOR and doesn’t call the parent constructor. I told him I knew for a fact it would break tons of other code, because the parent constructor is what turns the array of attributes into model fields.

    “Well, it doesn’t break any of these tests I wrote.”

    The tests were garbage and never once used `Model::create()` or `$model->relationship ()->create()` and thus did not reflect our actual code at all. The guy has gone on tirades against TDD, saying “if we don’t already know how to design a program, what are we even doing here?”. And now he’s using tests to defend literally breaking the framework our app is built on.

    The worst part is that I might end up being this guy’s boss some day. He’s written entire apps with this mindset that are in production now. He somehow figured out a way of passing an array of user preferences from controller method to view to controller method without ever touching the session.

    Reply
  12. I worked on a project where they decided that Eloquent was too slow for their needs, so they also added Doctrine models as well. There’s two versions of every model. As well, some parts of the application use Eloquent – others use Doctrine. Not to mention the additional overhead of Doctrine’s complexities. It’s a shit-show.

    Reply
  13. Inherited a project that was built by two completely incompetent agencies … oh boy:

    -Fat controllers, there’s about 15-20 controllers and each individual one is well over 70k lines of code. A few of them are over 400k lines

    -Routing – there is one single routes file that is over 50k lines of code. Rather than grouping routes that require the same middleware, each route individually has middleware attached to it

    -No migrations – I ended up using a package to generate migrations from the existing database

    -Database … is just a disaster

    -Blindly accepting user data – no data validation at all just talking whatever is in $_POST

    -Hundreds of queries in the boot method of the AppServiceProvider injecting data into all views

    -Lack of extending from a base template, each individual blade file is the full HTML/CSS.

    -The system has 13 different user roles and each role has their own dedicated subdirectory of vies

    -The vast majority of the blade view files have a ton of raw php running queries and logic

    -A dozen or so “helper” files mixed into the same directory as the Eloquent models. Each helper files is thousands of lines long just filled with a ton of different functions

    -Eloquent models are absolutely stuffed with a whole buncha spaghetti logic

    …. currently in the process of rebuilding the entire thing from the ground up

    Reply
  14. Just started working on a project for a small agency. The client doesn’t trust phps performance (thanks to their ‘consultant’ who’s a .net guy). So the entire API is in .net.

    The blade templates are all inline Vue components in the views directory. All the scripts though are in resources/js in separate files. Very anti dry, and they’re using laravel endpoints basically as a proxy to the API.

    I’ve basically rearranged it all to be basically 90% Vue spa with vuex and persistence. Getting rid of all blade views except the entry pages. Added Vue templates based on authentication. And all axios calls now bypass local controller methods and hit the .net API instead.

    If I had architected this myself it would’ve been all Vue no laravel or maybe quasar.

    Also had to take 50% off my normal rate because of desperation. ($25 vs $50)…

    So basically I’m gutting the whole thing making it less of a laravel app more just a frontend app.

    Reply
  15. 1)

    I had a job interview where I had to create a Laravel 4 based “static” website. Yes, using a framework has its advantages, eg. extending views/layouts, include views etc, but I had a question: why do we need a framework for this? Answer: because it’s good, we need a framework, and Laravel, yadayadayada…. Okay, I created the views, layout, made a catch-all controller (yes I know, bad practice) that explodes the path, checks if view exists then renders it, else throws a 404 (eg. `/our/company/about` path’s view is located in `views/our/company/about.blade.php`) and so on.

    Everything worked flawlessly, but there was an uber-rocket-scientist-php-master-of-puppets guy, he mentioned the followings:

    \- why is everything handled in one controller and one controller method? He showed me the code of their current website. Everything was separated to different controllers, eg. `/about => [email protected]`, `/something => [email protected]` and so on. Why?

    \- I mentioned that maybe it would be better to use some CMS, eg. Joomla or Drupal. Answer: naw, Joomla cannot do everything my (!) framework does.

    \- there was an earlier version of their website, where the above mentioned Mr. Magic used CodeIgniter. Everything was commented out from index.php except one line: `include “site/index.html”`.

    2)

    I was working as an ERP dev. The Holy CIO was a totally self educated guy – which is not a problem, self education is good. The problem was that he imagined himself as an Elemental Laravel god of Infernal Coding Eternity. He gave me access to VCS, I pulled everything, let’s see the code. 60k+lines per controller in `__construct()` method (we speak about 60-70 controllers). Blimey. Raw SQL queries (Eloquent is for the p\*ssies right?), try-catch everywhere. Master password was hard-coded, foreach everywhere instead of collection map(), transform() or filter(), aaaand ladies and gentlemen: plaintext passwords!

    And here comes another twist. On every index page, there was a filter. The filter itself was a very well working stuff, but there was one weak spot: Javascript with observables. Filter fields were defined in JS (they were observables!) in the following format: table.field, eg. invoice.invoice\_number. I don’t want to go deeper in this stuff, but if you change field names and search for email (wildcard is okay, eg. \*@thisunnamedcorporate.com), you will get a JSON response. This response of course will not be processed, because there will be new fields (and some missing fields too) that don’t exist in current list, but you can parse the JSON response in Chrome dev tools and voila, here comes the username-password combo…

    I mentioned him that we should stop using plaintext passwords and hash them. Naw, no one knows this and they don’t know how to open dev tools too (same for everything: if they don’t know if url path exists, it’s safe, so it’s enough to hide the menuitem from them). Security level over 9000. I resigned. Aftermath: theye were hacked about half year later.

    Reply
  16. Inhereted an app written by a guy who didn’t know you could put parameters in routes. So he was updating the routes file to add new routes for every new user…

    /users/1/dashboard
    /users/2/dashboard
    /users/3/dashboard
    ….

    The file was thousands of lines long.

    Reply
  17. > you could see raw sql queries inside the controller

    Where else would you write your SQL queries (assuming they are not model specific)? As far as I know, Laravel does not encourage the repository pattern like a lot of other frameworks, so the controller seems like the most logical place. Is there some secret Laravel repository pattern equivalent I’m missing?

    Reply
  18. 1. I was the first internal dev hire for a startup that had previously hired a government contractor to developer their eCommerce app.
    At first glance, it was bad but not catastrophic:

    * No migrations whatsoever
    * No SQL transactions…. and it was eCommerce related, so routinely support would de-duplicate dozens of charges daily.
    * Boolean values were switched for certain tables. For example, in some tables 1 meant false, 0 meant true. When we confronted the lead developer he explained that “Oh, \[Other Dev\] wrote it and he is a history major”.
    * They had explicitly disabled password hashing, so we had \~10,000 plaintext passwords stored in our database.
    * The /vendor folder was not being powered by composer.. They were copying .php files.
    * There was no backup strategy. Everything was on one server.
    * Icing on the cake: Code in git was different than what was deployed because changes were made live on the server *or* uploaded via FTP.

    They were fired later that month.

    2. This was a horror story that occurred after my team completed a major project for a multinational huge law firm.

    The plan was to hand over the project for a period of maintenance to an internal development team of 3 guys.

    We gave them a ton of documentation on the project, devops, and general maintenance of an Ubuntu server (they were a Windows shop).

    About 2 months later, their counsel calls us to demand to know why we had spun up *hundreds* of EC2 servers on their AWS account. They claimed that the key used to do it was the key we were issued for development and migration.

    Of course we had nothing to do with that. We determined rather quickly that their own team had setup a development server that was publicly accessible and had debugging turned on, so the default Whoops error page was showing up because they had disabled our protections for only displaying Whoops on local. To make matters worse, they had setup nginx to serve the app on all interfaces (instead of just the hostname) so when you went directly to the server by IP address on http, it unveiled every secret stored in the .env file — which happened to be the prod details because they never bothered to use the staging or dev env file we provided.

    This was by far the worst horror story I’ve ever seen. They had to cycle every key. I don’t know whether there was fallout, but I let them know that a mistake like this could easily destroy their firm. But hey, they shot the messenger and cancelled our contracts.

    Reply
  19. I work on a separate laravel project from some of my colleagues, and I follow a lot of standard ways (using eloquent and observers for example), where as they make helper files that use standard PDO, instead of an ORM, all because one of them didn’t want to learn how to use an ORM when they started the project.

    Another colleague just started working on that project, and has been moaning and groaning about it since starting.

    Looking at their repository hurts me.

    Basically not using the tools of laravel at all, and reimplementing everything, but still having laravel sit there…

    Reply

Leave a Comment