Skip to content

Instantly share code, notes, and snippets.

@rozsazoltan
Last active February 7, 2024 11:37
Show Gist options
  • Save rozsazoltan/a4c49d23a549fed686715d4dfe2d707e to your computer and use it in GitHub Desktop.
Save rozsazoltan/a4c49d23a549fed686715d4dfe2d707e to your computer and use it in GitHub Desktop.
Troubleshooting the Issue of Change to mediumInteger Type in Laravel

Updated

Original

Troubleshooting the Issue of Change to mediumInteger Type in Laravel

The Laravel framework utilizes the doctrine/dbal package to update column parameters. The dbal package has its own naming conventions, so for instance, the bigInteger used in Laravel corresponds to bigint in dbal. However, there is no equivalent for mediumInteger used in Laravel within dbal; there is no mediumint (as dbal convention) or mediuminteger (as Laravel convention).

The solution involves implementing mediumint.

If you want to update to mediumInteger, you can use the DB::statement call and simply accomplish this using NATIVE SQL.

Why dbal does not support mediumInteger is unknown. I created this description for those who prefer not to rewrite many already written mediumInteger calls into NATIVE SQL format.


Creating a mediuminteger in dbal

doctrine/dbal/src/Types/Types.php (Changed)
  public const BIGINT               = 'bigint';
+ public const MEDIUMINT            = 'mediuminteger'; // NEW (mediuminteger by Laravel)

The dbal convention suggests 'mediumint', but to avoid altering Laravel, which passes 'mediuminteger' strings, we'll stick with 'mediuminteger' here. For more details, see the getDoctrineColumnType function in the ChangeColumn.php file, where the default $type passed by the match will be 'mediuminteger' (in row 163).

doctrine/dbal/src/Platforms/AbstractMySQLPlatform.php (Changed)
  /**
   * {@inheritDoc}
   */
  public function getBigIntTypeDeclarationSQL(array $column)
  {
      return 'BIGINT' . $this->_getCommonIntegerTypeDeclarationSQL($column);
  }

+ /**
+  * {@inheritDoc}
+  */
+ public function getMediumIntTypeDeclarationSQL(array $column) // NEW (we're doing all this because of invoking this function)
+ {
+     return 'MEDIUMINT' . $this->_getCommonIntegerTypeDeclarationSQL($column);
+ }
doctrine/dbal/src/Platforms/AbstractPlatform.php (Changed)
  abstract public function getBigIntTypeDeclarationSQL(array $column);
    
+ /**
+ * Returns the SQL snippet that declares an 3 byte integer column.
+ *
+ * @param mixed[] $column
+ *
+ * @return string
+ */
+ abstract public function getMediumIntTypeDeclarationSQL(array $column); // NEW
doctrine/dbal/src/Types/MediumIntType.php (New File)
<?php

/**************/
/** NEW FILE **/
/**************/

namespace Doctrine\DBAL\Types;

use Doctrine\DBAL\ParameterType;
use Doctrine\DBAL\Platforms\AbstractPlatform;

/**
 * Type that maps a database MEDIUMINT to a PHP string.
 */
class MediumIntType extends Type implements PhpIntegerMappingType
{
    /**
     * {@inheritDoc}
     */
    public function getName()
    {
        return Types::MEDIUMINT;
    }

    /**
     * {@inheritDoc}
     */
    public function getSQLDeclaration(array $column, AbstractPlatform $platform)
    {
        return $platform->getMediumIntTypeDeclarationSQL($column); // use the getMediumIntTypeDeclarationSQL function of the AbstractMySQLPlatform class
    }

    /**
     * {@inheritDoc}
     */
    public function getBindingType()
    {
        return ParameterType::INTEGER;
    }

    /**
     * {@inheritDoc}
     *
     * @param T $value
     *
     * @return (T is null ? null : string)
     *
     * @template T
     */
    public function convertToPHPValue($value, AbstractPlatform $platform)
    {
        return $value === null ? null : (string) $value;
    }
}
doctrine/dbal/src/Types/Type.php (Changed)
/**
 * The map of supported doctrine mapping types.
 */
private const BUILTIN_TYPES_MAP = [
    // ...
    Types::BIGINT               => BigIntType::class,
+   Types::MEDIUMINT            => MediumIntType::class, // NEW (use the new MediumIntType class)
    // ...
];

Summary

If you have created the new class to handle MediumInt (alias mediuminteger) and integrated it into your dbal library with the listed file modifications, your mediumInteger() column modification called from Laravel Schema will now function properly.

Example for Testing

1970_01_01_000000_update_example_table.php
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    public function up()
    {
        Schema::table('example_table', function (Blueprint $table) {
            $table->unsignedMediumInteger('example_column_1')->change(); // will work
            $table->mediumInteger('example_column_2')->change(); // will work
        });
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment