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

Php Document Store Laravel Package

event-engine/php-document-store

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the Package:
    composer require event-engine/php-document-store
    
  2. Define the Interface in Laravel: Create a contract file at app/Contracts/DocumentStore.php:
    namespace App\Contracts;
    
    use EventEngine\DocumentStore\DocumentStore as BaseDocumentStore;
    
    interface DocumentStore extends BaseDocumentStore {}
    
  3. Bind the Implementation: In AppServiceProvider@boot():
    $this->app->bind(
        \App\Contracts\DocumentStore::class,
        \EventEngine\DocumentStore\InMemoryDocumentStore::class
    );
    
  4. First Use Case: Inject the store into a service and use it for basic operations:
    use App\Contracts\DocumentStore;
    use EventEngine\DocumentStore\Document;
    
    class MyService {
        public function __construct(private DocumentStore $store) {}
    
        public function createUser(string $id, array $data): void {
            $doc = new Document($id, $data);
            $this->store->saveDoc($doc);
        }
    }
    

Key Starting Points


Implementation Patterns

Core Workflows

1. CRUD Operations

  • Save/Update:
    $doc = new Document('user-123', ['name' => 'John']);
    $this->store->saveDoc($doc); // Upsert
    $this->store->replaceDoc($doc); // Force replace (no merge)
    
  • Partial Updates:
    $this->store->updateDoc('user-123', ['name' => 'John Doe']);
    $this->store->replaceDoc($doc); // Atomic replace
    
  • Delete:
    $this->store->deleteDoc('user-123');
    $this->store->deleteMany(['user-123', 'user-456']);
    

2. Querying Documents

  • By ID:
    $doc = $this->store->findDoc('user-123');
    $partial = $this->store->getPartialDoc('user-123', ['name', 'email']);
    
  • Filtered Queries:
    use EventEngine\DocumentStore\Filter\EqualsFilter;
    
    $filter = new EqualsFilter('status', 'active');
    $docs = $this->store->findDocs($filter);
    
  • Conditional Filters (And/Or):
    use EventEngine\DocumentStore\Filter\AndFilter;
    use EventEngine\DocumentStore\Filter\EqualsFilter;
    
    $filter = new AndFilter(
        new EqualsFilter('status', 'active'),
        new EqualsFilter('role', 'admin')
    );
    $docs = $this->store->findDocs($filter);
    

3. Indexing

  • Create Index:
    $this->store->createIndex('email', 'email', true); // Unique index
    
  • Drop Index:
    $this->store->dropIndex('email');
    
  • Bulk Operations:
    $this->store->saveMany([$doc1, $doc2]);
    $this->store->deleteMany(['id1', 'id2']);
    

4. Testing Pattern

Use the in-memory store for unit tests:

use EventEngine\DocumentStore\InMemoryDocumentStore;

public function testDocumentStore()
{
    $store = new InMemoryDocumentStore();
    $store->saveDoc(new Document('test', ['key' => 'value']));
    $this->assertEquals('value', $store->findDoc('test')->getData()['key']);
}

Laravel-Specific Patterns

Dependency Injection

Bind the store to Laravel’s container with environment-based configurations:

// config/document_store.php
return [
    'default' => env('DOCUMENT_STORE_DRIVER', 'in_memory'),
    'drivers' => [
        'in_memory' => EventEngine\DocumentStore\InMemoryDocumentStore::class,
        'postgres' => EventEngine\PostgresDocumentStore\PostgresDocumentStore::class,
    ],
];

// AppServiceProvider
$this->app->bind(\App\Contracts\DocumentStore::class, function ($app) {
    $config = $app['config']['document_store'];
    return new $config['drivers'][$config['default']](
        $app->make('db.connection')->getPdo()
    );
});

Event Integration

Dispatch Laravel events for document changes:

use Illuminate\Support\Facades\Event;

$this->store->saveDoc($doc);
Event::dispatch(new DocumentStored($doc));

Caching Layer

Cache document queries to reduce database load:

use Illuminate\Support\Facades\Cache;

public function getCachedDoc(string $id): ?Document
{
    return Cache::remember("doc_{$id}", now()->addMinutes(5), function () use ($id) {
        return $this->store->findDoc($id);
    });
}

Repository Pattern

Wrap the store in a repository for business logic:

class UserDocumentRepository
{
    public function __construct(private DocumentStore $store) {}

    public function getActiveUsers(): array
    {
        $filter = new AndFilter(
            new EqualsFilter('status', 'active'),
            new EqualsFilter('role', 'user')
        );
        return $this->store->findDocs($filter);
    }
}

Gotchas and Tips

Pitfalls

  1. Unique Index Conflicts:

    • saveDoc() or replaceDoc() will throw an exception if a unique index is violated.
    • Fix: Use updateDoc() for partial updates or handle exceptions gracefully:
      try {
          $this->store->saveDoc($doc);
      } catch (UniqueConstraintViolationException $e) {
          // Handle conflict (e.g., retry with updated data)
      }
      
  2. In-Memory Store Limitations:

    • The in-memory store is not thread-safe and resets on each test run.
    • Tip: Use it only for unit tests, not integration tests or production.
  3. BC Breaks:

    • v0.3.0: dropIndex() now accepts either a string or Index object (not backward compatible).
    • Tip: Pin to a specific version in composer.json during migration:
      "event-engine/php-document-store": "0.2.*"
      
  4. Partial Document Merges:

    • By default, updateDoc() performs a shallow merge (not recursive).
    • Tip: Use replaceDoc() for atomic updates or implement custom merge logic.
  5. Circular Dependencies in Tests:

    • The in-memory store requires classes from event-engine/persistence.
    • Workaround: Copy the required classes to your test namespace or use a monorepo setup.

Debugging Tips

  1. Enable Logging: Add debug logs for store operations:

    $this->store->setLogger(new \Monolog\Logger('document_store'));
    
  2. Check Index Names: Ensure index names match exactly when dropping them:

    // Correct:
    $this->store->dropIndex('email_index');
    // Incorrect (will fail silently):
    $this->store->dropIndex('email'); // If the index was named 'email_index'
    
  3. Verify Document IDs:

    • IDs must be strings (not integers or objects).
    • Fix: Convert IDs explicitly:
      $this->store->findDoc((string) $id);
      
  4. Filter Performance:

    • Complex filters (e.g., nested AndFilter/OrFilter) can be slow in the in-memory store.
    • Tip: Use filterDocIds() for large datasets to reduce memory usage:
      $docIds = $this->store->filterDocIds($filter);
      $docs = $this->store->findMany($docIds);
      

Extension Points

  1. Custom Filters: Extend the filter system by implementing FilterInterface:

    class GreaterThanFilter implements FilterInterface {
        public function __construct(private string $field, private $value) {}
    
        public function matches(Document $doc): bool {
            return $doc->getData()[$this->field] > $this->value;
        }
    }
    
  2. Custom DocumentStore: Implement the interface for a new backend (e.g., Elasticsearch):

    class ElasticsearchDocumentStore implements DocumentStore {
        public function saveDoc
    
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.
besmartand-pro/php-quality-config
sentix/ai-chatbot
terminal42/code-quality-tools
codifyo/ts-generator-bundle
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity