Skip to content

Commit 7961b70

Browse files
committed
init claude md
1 parent a604681 commit 7961b70

1 file changed

Lines changed: 224 additions & 0 deletions

File tree

CLAUDE.md

Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Project Overview
6+
7+
This is **Spameri/Elastic** - an ElasticSearch implementation for the Nette Framework. The library provides a typed object-oriented interface to ElasticSearch, where queries, documents, and responses are all represented as PHP objects rather than raw arrays. It follows an ORM-like pattern with an EntityManager for persistence operations.
8+
9+
Key features:
10+
- Typed entities extending `AbstractElasticEntity`
11+
- EntityManager with persist/remove/find operations similar to Doctrine ORM
12+
- Event system for lifecycle hooks (pre/post persist, create, update, delete)
13+
- Single Table Inheritance (STI) support via `STIElasticEntityInterface`
14+
- Type-safe query building via `spameri/elastic-query` package
15+
- Index management commands via Symfony Console
16+
- Import system with locking and progress tracking
17+
- Identity Map pattern for entity caching
18+
- Tracy debug bar integration
19+
20+
## Development Commands
21+
22+
### Testing
23+
```bash
24+
# Run all tests
25+
make tests
26+
27+
# Run tests locally (single thread)
28+
make tests-local
29+
30+
# Run single test file
31+
vendor/bin/tester tests/SpameriTests/path/to/test.phpt
32+
```
33+
34+
### Code Quality
35+
```bash
36+
# Run PHPStan static analysis (level 6)
37+
make phpstan
38+
39+
# Run PHPStan with lowest dependencies
40+
make phpstan-lowest
41+
42+
# Check coding standards
43+
make cs
44+
45+
# Fix coding standards automatically
46+
make csf
47+
48+
# Generate code coverage
49+
make coverage
50+
```
51+
52+
### Dependencies
53+
```bash
54+
# Update composer dependencies (stable)
55+
make composer
56+
57+
# Update to lowest stable versions
58+
make composer-lowest
59+
```
60+
61+
### ElasticSearch Index Management
62+
```bash
63+
# Create an index (requires entity mapping class)
64+
php bin/console elastic:create-index <index-name>
65+
66+
# Delete an index
67+
php bin/console elastic:delete-index <index-name>
68+
69+
# Initialize all indexes from configuration
70+
php bin/console elastic:initialize-indexes
71+
72+
# Dump index data to file
73+
php bin/console elastic:dump-index <index-name>
74+
75+
# Load dumped data back
76+
php bin/console elastic:load-dump <file-path>
77+
78+
# Add/remove aliases
79+
php bin/console elastic:add-alias <index-name> <alias>
80+
php bin/console elastic:remove-alias <index-name> <alias>
81+
```
82+
83+
## Architecture
84+
85+
### Core Components
86+
87+
**EntityManager** (`src/EntityManager.php`)
88+
- Central entry point for all entity operations
89+
- Methods: `find()`, `findOneBy()`, `findBy()`, `findAll()`, `persist()`, `remove()`
90+
- Uses Identity Map pattern to cache entities and prevent duplicates
91+
- Dispatches lifecycle events through EventManager
92+
- All find methods return `ElasticEntityCollection` (except `findOneBy`)
93+
94+
**Entity Layer** (`src/Entity/`)
95+
- All entities extend `AbstractElasticEntity` which implements `ElasticEntityInterface`
96+
- Required property: `ElasticIdInterface $id` - managed by ElasticSearch
97+
- Required methods: `id()`, `entityVariables()`
98+
- Entity properties should use value objects implementing `ValueInterface` for validation
99+
- STI support: entities can implement `STIElasticEntityInterface` for polymorphic storage
100+
101+
**Model Layer** (`src/Model/`)
102+
- Service classes for specific operations: `Insert`, `GetAllBy`, `Delete`, `Search`, `Aggregate`, `Scroll`
103+
- `EntitySettingsLocator` - maps entity classes to their index configurations
104+
- `IdentityMap` - tracks loaded entities to prevent duplicates and enable references
105+
- `ChangeSet` - tracks whether entity is new or existing for event dispatching
106+
- `VersionProvider` - manages ElasticSearch version compatibility
107+
108+
**Factory Pattern** (`src/Factory/`)
109+
- `EntityFactory` - creates entity instances from ElasticSearch Hit objects
110+
- Uses reflection to construct entities with proper property types
111+
- Integrates with Identity Map to reuse existing instances
112+
- Handles nested objects and collections recursively
113+
114+
**Event System** (`src/EventManager.php`, `src/EventManager/`)
115+
- Events: `PRE_PERSIST`, `POST_PERSIST`, `POST_CREATE`, `POST_UPDATE`, `PRE_DELETE`, `POST_DELETE`
116+
- Listeners implement `ListenerInterface` with `getEvent()`, `getEntityClass()`, `handle()` methods
117+
- Auto-discovered from DI container
118+
- Both global event manager and per-entity `dispatchEvents()` support
119+
120+
**Import System** (`src/Import/`)
121+
- `Run` and `SimpleRun` - orchestrate data imports with progress tracking
122+
- `LockInterface` implementations - prevent concurrent imports (`FileLock`, `NullLock`)
123+
- `DataProviderInterface` - source of import data
124+
- `PrepareImportDataInterface` - transforms data before import
125+
- `AfterImportInterface` - post-import hooks
126+
- Exception hierarchy for error handling: `Fatal`, `Error`, `Omit`, `AlreadyLocked`
127+
128+
**Mapping System** (`src/Mapping/`)
129+
- Attributes for entity mapping: `@Entity`, `@Collection`, `@ElasticCollection`, `@STIEntity`, `@STIElasticEntity`, `@Ignored`
130+
- Used by reflection to understand entity structure during persistence/hydration
131+
132+
**Settings & Configuration** (`src/Settings/`, `src/DI/`)
133+
- `SpameriElasticSearchExtension` - Nette DI extension for configuration
134+
- Config options: `host`, `port`, `debug`, `version`, `synonymPath`, `entities`
135+
- `IndexConfigInterface` - defines index mappings via `provide()` returning `\Spameri\ElasticQuery\Mapping\Settings`
136+
- Index configurations use `spameri/elastic-query` objects: `Field`, `SubFields`, `FieldObject`, `FieldCollection`
137+
138+
**Query Building**
139+
- Uses external `spameri/elastic-query` package for type-safe queries
140+
- Main entry point: `\Spameri\ElasticQuery\ElasticQuery`
141+
- Query types: `Term`, `Match`, `Range`, `Bool`, aggregations, etc.
142+
- Passed to EntityManager's `findBy()` or Model layer services
143+
144+
### Important Patterns
145+
146+
**Entity Construction**
147+
- Entities must accept all properties via constructor (used by EntityFactory)
148+
- ID property is always first parameter and typed as `ElasticIdInterface`
149+
- Value objects implementing `ValueInterface` provide type safety and validation
150+
- Use `EmptyElasticId` for new entities, `ElasticId` for existing ones
151+
152+
**Persistence Flow**
153+
1. Call `EntityManager->persist($entity)`
154+
2. EventManager dispatches `PRE_PERSIST` event
155+
3. `Insert` service converts entity to array via reflection
156+
4. Data sent to ElasticSearch
157+
5. EventManager dispatches `POST_PERSIST`, plus `POST_CREATE` or `POST_UPDATE` based on ChangeSet
158+
6. Entity added to Identity Map
159+
160+
**Retrieval Flow**
161+
1. Call `EntityManager->findBy($query, $class)`
162+
2. `GetAllBy` executes query against index (determined by EntitySettingsLocator)
163+
3. Each Hit processed by `EntityFactory->create()`
164+
4. Factory checks Identity Map first (returns cached if exists)
165+
5. Factory uses reflection to resolve constructor parameters
166+
6. Nested entities/collections created recursively
167+
7. New entity added to Identity Map
168+
8. Returns `ElasticEntityCollection` containing results
169+
170+
**Single Table Inheritance (STI)**
171+
- Parent entity implements `STIElasticEntityInterface`
172+
- Child entities extend parent
173+
- Index stores `entityClass` field to identify concrete type
174+
- Factory automatically instantiates correct child class on retrieval
175+
- Enabled via `hasSti()` in index config
176+
177+
## Configuration Example
178+
179+
```neon
180+
extensions:
181+
spameriElasticSearch: \Spameri\Elastic\DI\SpameriElasticSearchExtension
182+
183+
spameriElasticSearch:
184+
host: 127.0.0.1
185+
port: 9200
186+
debug: true # Enables Tracy debug bar panel
187+
version: 8 # ElasticSearch version
188+
entities:
189+
- App\Model\Entity\MyEntity
190+
```
191+
192+
## Code Style
193+
194+
- PHP 8.2+ with strict types (`declare(strict_types = 1)`)
195+
- Constructor property promotion with readonly where applicable
196+
- Fully qualified class names in code (enforced by coding standard)
197+
- Slevomat Coding Standard rules (see `ruleset.xml`)
198+
- PHPStan level 6 analysis
199+
- Properties typed strictly; use union types sparingly
200+
- Nette Tester for unit tests (`.phpt` files)
201+
202+
## Important Conventions
203+
204+
**Never use field named `id` in entity mapping** - it conflicts with ElasticSearch's internal `_id`. Use `databaseId`, `externalId`, etc.
205+
206+
**Entity property order matters** - constructor parameter order must match the order reflection discovers them in.
207+
208+
**Index naming** - use consistent naming between entity config, mapping class, and actual index names.
209+
210+
**Test structure** - tests in `tests/SpameriTests/` mirror `src/` structure; bootstrap purges test indexes before each run.
211+
212+
**ElasticQuery integration** - always use `\Spameri\ElasticQuery\ElasticQuery` objects for queries, not raw arrays, to maintain type safety.
213+
214+
**Event listeners** - must implement `ListenerInterface` and be registered in DI container to be auto-discovered by EventManager.
215+
216+
**Value objects** - prefer value objects implementing `ValueInterface` for entity properties to encapsulate validation logic.
217+
218+
## Testing Notes
219+
220+
- Tests require running ElasticSearch instance (configured via `SpameriTests\Elastic\Config`)
221+
- Bootstrap automatically deletes test indexes before test run
222+
- Tests use `.phpt` format (Nette Tester)
223+
- Temporary directory: `tests/tmp/` (auto-cleaned)
224+
- Test data: `tests/SpameriTests/data.json` (1.2MB fixture file)

0 commit comments

Comments
 (0)