Laravel: Hotfix for SQLite Drop Foreign Exception
Tags: laravel, 100daysofcode, codenewbie, webdev
Published: 2021-07-06 14:55:41

---
title: "Laravel: Hotfix for SQLite Drop Foreign Exception"
published: true
description: "Inside the TestCase class, create a function that calls the Connection class resolverFor method. It takes the driver's name as the first parameter and a callback as the second."
tags: Laravel, 100daysofcode, codenewbie, webdev
cover_image: https://faruknasir.com//images/blog/2021/sqlite_drop_foreign.png
---

By convention, you can not use `ALTER TABLE` sql statement to drop a foreign key in sqlite. To do that, you will have to rename the table, create a new table without the foreign key, and then copy the data into the new table.

<div style="width:100%;height:0;padding-bottom:56%;position:relative;"><iframe src="https://giphy.com/embed/VvMZkreP3TMqfvcCLP" width="100%" height="100%" style="position:absolute" frameBorder="0" class="giphy-embed" allowFullScreen></iframe></div><p><a href="https://giphy.com/gifs/tlc-network-90-day-fiance-happily-ever-after-VvMZkreP3TMqfvcCLP">via GIPHY</a></p>

This behaviour has been [baked in to Laravel](https://github.com/laravel/framework/pull/24052) in the form of an exception since Laravelv5.7. Unfortunately, this removes the possibility to simply ignore foreign keys using the same migrations across different drivers. This has been a real bottleneck for me because I mostly use in-memory sqlite database for my tests and real world databases schema definitions are messy with lots of `changes` and `droppings` through out the lifetime of your project.

If you are like me, you are in luck because I will be sharing with you [a solution](https://github.com/laravel/framework/issues/25475#issuecomment-439342648) I found that does not involve you updating any migration.

<div style="width:100%;height:0;padding-bottom:56%;position:relative;"><iframe src="https://giphy.com/embed/xT5P0WEiP5n4WMGUG4" width="100%" height="100%" style="position:absolute" frameBorder="0" class="giphy-embed" allowFullScreen></iframe></div><p><a href="https://giphy.com/gifs/simonrex-simon-rex-dirt-nasty-xT5P0WEiP5n4WMGUG4">via GIPHY</a></p>

<div class="blognote">
<strong>Note:</strong> 
This example is for when you are using in-memory sqlite for tests!
</div>

Inside the `TestCase` class, create a function that calls the `Connection` class `resolverFor` method. It takes the **driver's name** as the first parameter and a **callback** as the second.

The callback will return a new class extending `SQLiteConnection` and override the `getSchemaBuilder` method:

```php
public function hotfixSqlite()
{
    \Illuminate\Database\Connection::resolverFor('sqlite', 
        function ($connection, $database, $prefix, $config) {
        return new class($connection, $database, $prefix, $config) 
            extends SQLiteConnection {
            public function getSchemaBuilder()
            {
                if ($this->schemaGrammar === null) {
                    $this->useDefaultSchemaGrammar();
                }

                return new class($this) extends SQLiteBuilder {
                    protected function createBlueprint($table, Closure $callback = null)
                    {
                        return new class($table, $callback) extends Blueprint {
                            public function dropForeign($index)
                            {
                                return new Fluent();
                            }
                        };
                    }
                };
            }
        };
    });
}
```

The final step is to call the newly created function in the `TestCase`'s constructor class. Your final `TestCase` class should look like the following:

```php
abstract class TestCase extends BaseTestCase
{
    public function __construct(?string $name = null, array $data = [], string $dataName = '')
    {
        $this->hotfixSqlite();
        parent::__construct($name, $data, $dataName);
    }

    /**
     *
     */
    public function hotfixSqlite()
    {
        \Illuminate\Database\Connection::resolverFor('sqlite', 
            function ($connection, $database, $prefix, $config) {
            return new class($connection, $database, $prefix, $config) 
                extends SQLiteConnection {
                public function getSchemaBuilder()
                {
                    if ($this->schemaGrammar === null) {
                        $this->useDefaultSchemaGrammar();
                    }

                    return new class($this) extends SQLiteBuilder {
                        protected function createBlueprint($table, Closure $callback = null)
                        {
                            return new class($table, $callback) extends Blueprint {
                                public function dropForeign($index)
                                {
                                    return new Fluent();
                                }
                            };
                        }
                    };
                }
            };
        });
    }
}
```

<div class="blognote">
<strong>Important:</strong> 
For PHPUnit 9, it is important that you call the hotfix
method before the parent constructor in the constructor method.
</div>

<div style="width:100%;height:0;padding-bottom:67%;position:relative;"><iframe src="https://giphy.com/embed/Mp4hQy51LjY6A" width="100%" height="100%" style="position:absolute" frameBorder="0" class="giphy-embed" allowFullScreen></iframe></div><p><a href="https://giphy.com/gifs/smile-done-Mp4hQy51LjY6A">via GIPHY</a></p>

> This post appeared [here](https://faruknasir.com/2021/4/squash-commits-into-one-git) first.