Category: Uncategorized

enum in symfony
Symfony Development Uncategorized

Enum in Symfony

Hey folks, I hope you are doing well. In this post, we are going to understand what enums are and how we can use enum in Symfony. Before we go through, let’s understand what an enum is. What is Enum? Enums, short for enumerations, are a data type that allows you to define a set of named values. They are useful for representing fixed sets of related constants, improving code readability, and ensuring type safety. In Symfony, enums can help you manage state, roles, and other sets of predefined values more effectively. Why Use Enums? Readability: Enums replace magic numbers and strings with descriptive names. Type Safety: Enums restrict variables to predefined values, reducing errors. Maintainability: Centralized definition makes it easy to update values in one place. How to Use Enum in Symfony? Symfony does not provide a data type for enums, so which data types does Symfony provide us? Let’s see. Create a Symfony App: I hope you know how to create a Symfony app. If not, just follow my lead; I’ll explain everything to you.As per the Symfony documentation, you can create a Symfony app in different ways. The first way is to create an app using Composer, and another way is to create an app using Symfony CLI. you can follow Symfony documentation for more details. here are commands you can use to create an app.
composer create-project symfony/skeleton new-test-app
or
symfony new new-test-app --full
now move into your new app directory and start the local server as follows.
cd /new-test-app

symfony server:start
once your server starts you can click on the link, which will be 127.0.0.1:8000, the port can be different, after you open that page, you will see a page like this. Now let’s create an entity in which we are going to use an enum. Run the command in the terminal where your project directory exists. Once you install the package, run the make:entity command again, which I have added above. create an entity for user, from the make: entity command and add following fields. username: Name: username Type: string Length: 150 Not Null: Yes password: Name: password Type: string Length: 255 Not Null: Yes role: Name: role type: for type just type ? and enter, and you will see datatypes provided by Symfony. Symfony does not provide a built-in enum datatype. However, we can explore alternative methods to achieve similar functionality in Symfony. Let’s explore our options. Enum in Symfony: we are going to create a custom enum type field in Symfony, so we will create a Custom Doctrine Type for Enums, we’ll call that class AbstractEnumType. before that install this package which we will use to create enum classes.
composer require elao/enum
create a new directory inside the src folder of your app, called DBAL in which we can create custom datatype fields for our app, in that directory we’ll need to create two more directories one is TypedFieldMapper, and another one is Types. create a new Interface in the Types directory, called SQLEnumTypeInterface.
<?php

declare(strict_types=1);

namespace App\DBAL\Types;

use BackedEnum;
use Elao\Enum\ReadableEnumInterface;

interface SQLEnumTypeInterface extends ReadableEnumInterface, BackedEnum
{
    public function getExcludeFromSQLEnumDeclaration(): bool;
}
now create another interface in the Types directory called SQLEnumTypeDefaultForNullInterface.
<?php

declare(strict_types=1);

namespace App\DBAL\Types;

interface SQLEnumTypeDefaultForNullInterface extends SQLEnumTypeInterface
{
    public static function getDefaultForNull(): self;
}
now create AbstractClass in the Types directory for Enum Type.
<?php

declare(strict_types=1);

namespace App\DBAL\Types;

use BackedEnum;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Platforms\SqlitePlatform;
use Doctrine\DBAL\Types\Type;
use LogicException;

abstract class AbstractEnumType extends Type
{
    /** @return class-string<SQLEnumTypeInterface> */
    abstract public static function getEnumClass(): string;

    public function getName(): string // the name of the type.
    {
        return static::getEnumClass();
    }

    /**
     * {@inheritdoc}
     */
    public function getSQLDeclaration(array $column, AbstractPlatform $platform): string
    {
        $class = static::getEnumClass();

        if (!is_a($class, SQLEnumTypeInterface::class, true)) {
            throw new LogicException(sprintf('%s must be of %s type', $class, SQLEnumTypeInterface::class));
        }

        $values = [];

        foreach ($class::cases() as $val) {
            if (!$val->getExcludeFromSQLEnumDeclaration()) {
                $values[] = "'{$val->value}'";
            }
        }

        if ($platform instanceof SqlitePlatform) {
            return "TEXT CHECK( " . $column['name'] . " IN (" . implode(", ", $values) . ") )";
        }

        return "enum(" . implode(", ", $values) . ")";
    }

    /**
     * {@inheritdoc}
     */
    public function convertToDatabaseValue($value, AbstractPlatform $platform): mixed
    {
        if ($value !== null && !($value instanceof BackedEnum)) {
            /** @var SQLEnumTypeInterface $class */
            $class = static::getEnumClass();
            $value = $class::tryFrom($value);
        }

        if ($value instanceof SQLEnumTypeDefaultForNullInterface && $value === $value::getDefaultForNull()) {
            return null;
        }

        if ($value instanceof SQLEnumTypeInterface) {
            if ($value->getExcludeFromSQLEnumDeclaration()) {
                throw new LogicException(sprintf('%s is not a valid value for %s in database', $value->value, get_debug_type($value)));
            }

            return $value->value;
        }

        return null;
    }

    /**
     * {@inheritdoc}
     */
    public function convertToPHPValue($value, AbstractPlatform $platform): ?BackedEnum
    {
        if (false === enum_exists(static::getEnumClass(), true)) {
            throw new LogicException("This class should be an enum");
        }

        /** @var SQLEnumTypeInterface $class */
        $class = static::getEnumClass();

        if (is_a($class, SQLEnumTypeDefaultForNullInterface::class, true) && $value == null) {
            /** @var SQLEnumTypeDefaultForNullInterface $class */
            return $class::getDefaultForNull();
        }

        if ((!is_int($value)) && !is_string($value)) {
            return null;
        }

        return $class::tryFrom($value);
    }

    /**
     * @codeCoverageIgnore
     */
    public function requiresSQLCommentHint(AbstractPlatform $platform): bool
    {
        return true;
    }
}

create a new Trait for the enum,
<?php

declare(strict_types=1);

namespace App\DBAL\Types;

use Elao\Enum\ExtrasTrait;
use Elao\Enum\ReadableEnumTrait;

trait SQLEnumTypeTrait
{
    use ReadableEnumTrait;
    use ExtrasTrait;

    public function getExcludeFromSQLEnumDeclaration(): bool
    {
        return !!$this->getExtra('excludeFromSQLEnumDeclaration', false);
    }
}
and create a new class inside TypeFieldMapper called AbstractEnumMapper, this class will map the enum type field into doctrine.
<?php

declare(strict_types=1);

namespace App\DBAL\TypedFieldMapper;

use App\DBAL\Types\SQLEnumTypeInterface;
use Doctrine\ORM\Mapping\TypedFieldMapper;
use ReflectionNamedType;
use ReflectionProperty;

class AbstractEnumMapper implements TypedFieldMapper
{
    public function validateAndComplete(array $mapping, ReflectionProperty $field): array
    {
        $type = $field->getType();
        if (
            ! isset($mapping['type'])
            && ($type instanceof ReflectionNamedType)
        ) {
            if (!$type->isBuiltin() && enum_exists($type->getName()) && is_subclass_of($type->getName(), SQLEnumTypeInterface::class)) {
                $mapping['type'] = $type->getName();
            }
        }

        return $mapping;
    }
}
now we need to register our classes in service.yaml file which is exist inside config directory.
    App\:
        resource: '../src/'
        exclude:
            - '../src/DependencyInjection/'
            - '../src/Entity/'
            - '../src/Kernel.php'
    _instanceof:
        App\DBAL\Types\AbstractEnumType:
            tags: [ 'app.doctrine_enum_type' ]

    App\DBAL\TypedFieldMapper\AbstractEnumMapper:

    Doctrine\ORM\Mapping\DefaultTypedFieldMapper:

    Doctrine\ORM\Mapping\ChainTypedFieldMapper:
        arguments:
            $typedFieldMappers:
                - '@App\DBAL\TypedFieldMapper\AbstractEnumMapper'
                - '@Doctrine\ORM\Mapping\DefaultTypedFieldMapper'

    doctrine.orm.configuration:
        class: Doctrine\ORM\Configuration
        calls:
            - setTypedFieldMapper: [ '@Doctrine\ORM\Mapping\ChainTypedFieldMapper' ]
now one final thing we need to do is to register all the enums that we created in to kernel, so every time we create a new enum we don’t need to write them into doctrine.yaml file, we’ll do that from the kernel.
<?php

declare(strict_types=1);

namespace App;

use App\DBAL\Types\AbstractEnumType;
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Kernel as BaseKernel;

class Kernel extends BaseKernel implements CompilerPassInterface
{
    use MicroKernelTrait;

    public function process(ContainerBuilder $container): void
    {
        $typesDefinition = [];
        if ($container->hasParameter('doctrine.dbal.connection_factory.types')) {
            /** @var array $typesDefinition */
            $typesDefinition = $container->getParameter('doctrine.dbal.connection_factory.types');
        }

        $taggedEnums = $container->findTaggedServiceIds('app.doctrine_enum_type');

        foreach ($taggedEnums as $enumType => $definition) {
            /** @var AbstractEnumType $enumType */
            $typesDefinition[$enumType::getEnumClass()] = ['class' => $enumType];
        }

        $container->setParameter('doctrine.dbal.connection_factory.types', $typesDefinition);
    }
}
now we’ve configured the enum in symfony how do we use them? let’s see. using enums in symfony: create a new directory inside your Entity directory. which we’ll use to create Enum classes, so we’ll call this directory Enum, and create a new Enum class UserRole.
<?php

declare(strict_types=1);

namespace App\Entity\Enum;

use App\DBAL\Types\SQLEnumTypeInterface;
use App\DBAL\Types\SQLEnumTypeTrait;
use Elao\Enum\Attribute\EnumCase;

enum UserRole: string implements SQLEnumTypeInterface
{
    use SQLEnumTypeTrait;

    #[EnumCase('Admin')]
    case ADMIN = 'ROLE_ADMIN';

    #[EnumCase('User')]
    case USER = 'ROLE_USER';
}

now create another file inside the Types Directory, called UserRoleType.
<?php

declare(strict_types=1);

namespace App\DBAL\Types;

use App\Entity\Enum\UserRole;

class UserRoleType extends AbstractEnumType
{
    public static function getEnumClass(): string
    {
        return UserRole::class;
    }
}
now run the make:entity command and enter your class name which we have created at the starting, so use the User class add a new field role, and again type ? and hit enter, you will see our newly created enum class there and also you can assign this datatype to role. here is User Entity,
<?php

namespace App\Entity;

use App\Entity\Enum\UserRole;
use App\Repository\UserRepository;
use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity(repositoryClass: UserRepository::class)]
#[ORM\Table(name: '`user`')]
class User
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[ORM\Column(length: 150)]
    private ?string $username;

    #[ORM\Column(length: 255)]
    private ?string $password;

    #[ORM\Column(type: UserRole::class)]
    private UserRole $role;

    public function getId(): int
    {
        return $this->id;
    }

    public function getUsername(): string
    {
        return $this->username;
    }

    public function setUsername(string $username): static
    {
        $this->username = $username;

        return $this;
    }

    public function getPassword(): string
    {
        return $this->password;
    }

    public function setPassword(string $password): static
    {
        $this->password = $password;

        return $this;
    }

    public function getRole(): UserRole
    {
        return $this->role;
    }

    public function setRole(UserRole $role): static
    {
        $this->role = $role;

        return $this;
    }
}

now if you run the make:migration command in which you can see thet we’ve successfully used enum in Symfony.
CREATE TABLE `user` (id INT AUTO_INCREMENT NOT NULL, username VARCHAR(150) NOT NULL, password VARCHAR(255) NOT NULL, role enum(\'ROLE_ADMIN\', \'ROLE_USER\') NOT NULL COMMENT \'(DC2Type:App\\\\Entity\\\\Enum\\\\UserRole)\', PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB
now, we’ve successfully implemented Enum in Symfony, if you want to learn how to add a cron job in Symfony you can check it from here.
Uncategorized

How to implement tailwind CSS

In the ever-evolving world of web development, Tailwind CSS has emerged as a powerful and flexible utility-first CSS framework. It allows developers to build custom designs without leaving their HTML, making the development process more efficient and maintainable. In this blog, we’ll walk you through the steps to implement Tailwind CSS in your project, whether you are starting from scratch or integrating it into an existing setup Tailwind CSS is a utility-first CSS framework that makes it easy to build custom designs directly in your HTML. The simplest and fastest way to get up and running with Tailwind CSS from scratch is by using the Tailwind CLI tool. The CLI is also available as a standalone executable, allowing you to use it without the need to install Node.js. In this blog post, we’ll walk you through the process of setting up Tailwind CSS using the CLI tool. 1. Install Tailwind CSS First, you’ll need to install Tailwind CSS via npm and create your tailwind.config.js file. Open your terminal and run the following commands:
npm install -D tailwindcss
npx tailwindcss init
2. Configure Your Template Paths Next, you need to configure the paths to all your template files. This helps Tailwind CSS to purge unused styles in production, making your CSS file as small as possible. Edit your tailwind.config.js file to include the paths to your HTML and JavaScript files:
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: ["./src/**/*.{html,js}"],
  theme: {
    extend: {},
  },
  plugins: [],
}
3. Add the Tailwind Directives to Your CSS Create a CSS file (e.g., src/input.css) and add the @tailwind directives for each of Tailwind’s layers:
/* src/input.css */

@tailwind base;
@tailwind components;
@tailwind utilities;
4. Start the Tailwind CLI Build Process Now, you need to run the CLI tool to scan your template files for classes and build your CSS. Run the following command in your terminal:
npx tailwindcss -i ./src/input.css -o ./src/output.css --watch

This command tells Tailwind to take src/input.css as input and output the processed CSS to src/output.css. The –watch flag makes sure Tailwind rebuilds your CSS whenever you make changes to your template files. 5. Start Using Tailwind in Your HTML Finally, include your compiled CSS file in your HTML and start using Tailwind’s utility classes to style your content. Here’s an example of what your src/index.html file might look like:
<!doctype html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link href="./output.css" rel="stylesheet">
</head>
<body>
  <h1 class="text-3xl font-bold underline">
    Hello world!
  </h1>
</body>
</html>

Conclusion And that’s it! You’ve successfully set up Tailwind CSS using the CLI tool. Now you can start using Tailwind’s utility-first classes to style your HTML. This setup ensures a smooth and efficient development process, allowing you to focus more on building your design and less on writing custom CSS.
×