Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Doctrine Snowflakes Bundle Laravel Package

c4ys/doctrine-snowflakes-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require c4ys/doctrine-snowflakes-bundle
    

    Add to config/bundles.php (Symfony):

    return [
        // ...
        KaiGrassnick\DoctrineSnowflakesBundle\DoctrineSnowflakesBundle::class => ['all' => true],
    ];
    
  2. Entity Configuration: Add the @ORM\CustomIdGenerator annotation to your entity’s ID field:

    use KaiGrassnick\DoctrineSnowflakesBundle\Generator\SnowflakeGenerator;
    use Doctrine\ORM\Mapping as ORM;
    
    /**
     * @ORM\Entity()
     */
    class MyEntity {
        /**
         * @ORM\Id()
         * @ORM\GeneratedValue(strategy="CUSTOM")
         * @ORM\Column(type="bigint")
         * @ORM\CustomIdGenerator(class=SnowflakeGenerator::class)
         */
        private string $id;
    }
    
  3. First Use Case: Run migrations (php bin/console doctrine:migrations:diff) and generate IDs:

    $entity = new MyEntity();
    $entityManager->persist($entity); // Auto-generates a snowflake ID
    $entityManager->flush();
    

Implementation Patterns

Workflow Integration

  1. Snowflake IDs in Services: Use the generated IDs in business logic (e.g., API responses, caching keys):

    public function getEntityData(MyEntity $entity): array {
        return [
            'id' => $entity->getId(), // Snowflake ID (e.g., "1234567890123456789")
            'name' => $entity->getName(),
        ];
    }
    
  2. Bulk Operations: Snowflakes are deterministic per machine/process. For distributed systems:

    • Configure worker_id in config/packages/doctrine_snowflakes.yaml:
      kai_grassnick_doctrine_snowflakes:
          worker_id: %env(int:WORKER_ID, 1)%
      
    • Ensure uniqueness across workers (e.g., via environment variables or Kubernetes pods).
  3. Migrations:

    • New Tables: Use strategy="CUSTOM" for all new entities needing snowflakes.
    • Existing Tables: Add a new snowflake_id column (if needed) and backfill via a custom migration:
      public function up(SchemaManagerInterface $sm, \Closure $rollback) {
          $this->addSql('ALTER TABLE my_entity ADD snowflake_id BIGINT NOT NULL');
          $this->addSql('UPDATE my_entity SET snowflake_id = :snowflake', [
              'snowflake' => (new SnowflakeGenerator())->generate(),
          ]);
      }
      
  4. Testing: Mock the generator in unit tests:

    $generator = $this->createMock(SnowflakeGenerator::class);
    $generator->method('generate')->willReturn('1234567890123456789');
    $entityManager->getConnection()->getConfiguration()->addCustomStringFunction(
        'SNOWFLAKE',
        $generator
    );
    

Gotchas and Tips

Pitfalls

  1. Clock Skew: Snowflakes rely on a timestamp. If your server’s clock drifts (e.g., NTP misconfiguration), IDs may violate uniqueness or sorting. Mitigate with:

    • A local NTP server or reliable time sync.
    • Fallback to a database sequence if skew exceeds 1ms.
  2. Worker ID Collisions:

    • Default worker_id is 1. In distributed environments, ensure each worker has a unique worker_id (e.g., via Docker/K8s labels or environment variables).
    • Validate uniqueness by checking for duplicate IDs during flush().
  3. Database Constraints:

    • Some databases (e.g., MySQL) may reject BIGINT as a primary key if the table is large. Use UNSIGNED BIGINT instead:
      @ORM\Column(type="bigint", options={"unsigned": true})
      
  4. Doctrine Cache: Clear the metadata cache after adding the bundle:

    php bin/console cache:clear
    

Debugging

  1. ID Generation Issues:

    • Check the generator’s output:
      $generator = new SnowflakeGenerator();
      var_dump($generator->generate()); // Debug raw output
      
    • Log the timestamp/worker ID:
      kai_grassnick_doctrine_snowflakes:
          debug: true # Logs generation details
      
  2. Performance:

    • Snowflakes are O(1) but may add ~1ms latency per entity. Benchmark in your stack.
    • For bulk inserts, consider batching IDs (pre-generate and assign manually).

Extension Points

  1. Custom Snowflake Logic: Extend the generator:

    class CustomSnowflakeGenerator extends SnowflakeGenerator {
        protected function getWorkerId(): int {
            return hash('crc32', $_SERVER['HOSTNAME']) % 1024; // Example: Hash hostname
        }
    }
    

    Update the entity annotation:

    @ORM\CustomIdGenerator(class="App\Generator\CustomSnowflakeGenerator")
    
  2. Hybrid IDs: Combine snowflakes with UUIDs for external systems:

    public function getExternalId(): string {
        return 'SNOW_' . $this->id . '_UUID_' . $this->uuid;
    }
    
  3. Event Listeners: Trigger actions on snowflake generation:

    $entityManager->getEventManager()->addEventListener(
        \Doctrine\ORM\Events::prePersist,
        function (LifecycleEventArgs $args) {
            $entity = $args->getObject();
            if ($entity instanceof MyEntity && empty($entity->getId())) {
                // Custom logic post-generation
            }
        }
    );
    

Configuration Quirks

  • Default Values:
    • datacenter_id: 1 (10-bit, max 1024).
    • worker_id: 1 (10-bit, max 1024).
    • epoch: 2020-01-01 00:00:00 (adjust if needed). Override in config/packages/doctrine_snowflakes.yaml:
    kai_grassnick_doctrine_snowflakes:
        epoch: "2010-01-01 00:00:00"
        datacenter_id: %env(int:DATACENTER_ID, 1)%
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
directorytree/privacy-filter-classifier
directorytree/privacy-filter
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata
splash/openapi
splash/scopes
splash/toolkit
testo/output-teamcity
testo/bridge-symfony
spatie/flare-daemon-runtime