Putting emojis in your database should be a piece of cake, right? You’ve had enough trouble with encodings in your lifetime, and now that we have the blessing of UTF-8, you’re always so careful to use it everywhere, so you’d expect all the characters to just finally work out of the box, right?

Well, I did expect that. But I’ve recently realised I can only put some emojis (like “❤️”) in by blog posts. Most of them were just lost or replaced with “?” by MySQL... Oh, those damn encodings again!

But fortunately the solution is quite simple.

Instead of the utf8 charset, you need to use its superset, utf8mb4. This one handles 4-byte characters and that’s exactly what we need. We just have to make both the database and Doctrine use it.

phpMyAdmin or Adminer let you change the charset easily. Just go to edit table schema and switch the collation of relevant columns and tables to utf8mb4_unicode_ci. Since you’re going from utf8 to its superset, no data should become corrupted in the process. But just to play it safe, better create a backup before you start.

You might encounter an error: “Specified key was too long; max key length is 767 bytes”. That’s because of some limitations of InnoDB regarding indices length. To make an index into mb4, you’ll have to shorten the max length of a column to 191 (instead of max 255 for simple utf8).

When it comes to Doctrine, you have to specify the collation and charset on the level of an entity/table and on the level of the connection.

For an entity, if you’re using annotations:

/**
 * @ORM\Entity
 * @ORM\Table(options={"collate"="utf8mb4_unicode_ci", "charset"="utf8mb4"})
 */

Or if you’re using XML:

<entity name="Acme\DemoBundle\Entity\User">
    <options>
        <option name="charset">utf8mb4</option>
        <option name="collate">utf8mb4_unicode_ci</option>
    </options>
</entity>

As for the connection, go with:

$conn = \Doctrine\DBAL\DriverManager::getConnection(
    [
        'driver'   => 'pdo_mysql',
        'host'     => 'localhost',
        'user'     => 'user',
        'password' => 'password',
        'dbname'   => 'database',
        'charset'  => 'utf8mb4',
    ],
    new \Doctrine\DBAL\Configuration()
);

Or in Symfony:

# app/config/config.yml
doctrine:
    dbal:
        charset:  utf8mb4

Or in Micrus:

# app/Config/parameters.yml
database:
  driver: pdo_mysql
  host: 127.0.0.1
  dbname: database
  user: user
  password: password
  charset: utf8mb4

And that would be it (hopefully). Enjoy your new emoji support! 😊