All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
(none yet)
(none)
(none)
(none)
- JsonFaker: Preserva precisión de floats al codificar valores generados por esquema usando
JSON_PRESERVE_ZERO_FRACTION, para quejson_decode()devuelvafloatde forma consistente en PHP 8.5+. - GenerateMongoAnonymizedFieldCommand: Durante el escaneo de documentos, ahora salta ficheros PHP no legibles (
is_readable()), evitando warnings de “Permission denied” y haciendo el comportamiento determinista entre entornos. - AnonymizationHistoryServiceTest: Hace la prueba de rebuildIndex robusta frente a flakiness por el cambio de segundos (cutoff temporal).
(none)
- Docker Compose (bundle root and demos): MySQL and PostgreSQL are no longer published on the host (
portsremoved). PHP, phpMyAdmin, pgAdmin, and other services on the same Compose network still reach them asmysql:3306andpostgres:5432. This avoids common WSL2 / Docker Desktop failures when binding host ports (e.g.forwards/expose500) and reduces exposed surface on the workstation. MongoDB in demos may still publish an optional host port for local tools (unchanged).
- PHPUnit (integration): Assertions on Symfony Console output were updated to tolerate wrapped lines (e.g. MongoDB warning, “no entities” notes,
.gitignorenote) somake test-coveragestays green across terminal widths and CI environments. - DbalHelperTest: No longer configures
Connection::quoteSingleIdentifieron mocks when that method is final or static (Doctrine DBAL 4 / PHP 8.1 CI); the test still exercises the fallback path viagetDatabasePlatform()throwing.
- composer.lock (symfony6, symfony7, symfony8): Synchronized with
composer.jsonsonowo-tech/twig-inspector-bundle(require-dev) is present in the lock file;composer installduringmake upno longer fails with “package is not present in the lock file”.
- README, FAKERS.md, CONFIGURATION.md, ROADMAP.md: Faker count aligned with
FakerType— 40 types (includingmap,utm, etc.), not 39. - README (Roadmap): Current release 1.0.16; test/coverage stats remain phrased so numbers do not go stale (1100+ methods; use
composer test/make test-coveragefor current figures). - TESTING_COMMANDS.md: Aligned with
scripts/test-commands.sh— 26 combinations; per-section counts and notes (export has no--dry-run; real export runs in demos). - README: Demo script description updated to 26 combinations.
- demo/README.md and demo/symfony6|7|8/README.md: Document database access via the internal Compose network and admin UIs (phpMyAdmin / pgAdmin); home Twig templates updated with correct admin ports per demo.
- Command runner abstraction: New
Nowo\AnonymizeBundle\Service\CommandRunnerInterfaceand default implementationSystemCommandRunner.DatabaseExportServicenow uses this abstraction so database export logic (MySQL/PostgreSQL/SQLite/MongoDB) is testable without depending on real binaries or host environment. - Statistics display service: New
Nowo\AnonymizeBundle\Service\AnonymizeStatisticsDisplayextracted fromAnonymizeCommandto handle statistics rendering and export (tables, JSON/CSV, success rates) with dedicated unit tests. - Documentation: New and expanded docs for configuration, command usage, testing, and demos:
docs/CONFIGURATION.md,docs/COMMANDS.md,docs/TESTING_COMMANDS.md,docs/INSTALLATION.md,docs/RECIPE.md,docs/FAKERS.md, and example guides for pattern-based filters and polymorphism (EXAMPLES_PATTERN_BASED.md,EXAMPLES_POLYMORPHISM_ANONYMIZE_SERVICE.md).docs/DEMO-FRANKENPHP.mddescribes running the demos with FrankenPHP and Caddy (dev images, Caddyfile, PHP ini).docs/PROPUESTA-TESTS-COBERTURA.md,docs/ENGRAM.md, anddocs/ROADMAP.mdexpanded with testing and architecture notes.
- DatabaseExportService: Refactored to delegate all shell command execution (mysqldump/pg_dump/mongodump/tar/gzip/bzip2/zip) to
CommandRunnerInterface. Behaviour is unchanged for consumers (CLI commands still export databases the same way), but the implementation is now covered by deterministic tests using fake runners. - History command:
AnonymizationHistoryCommandnow delegates statistics rendering of anonymization runs toAnonymizeStatisticsDisplay, improving separation of concerns and allowing higher coverage of reporting logic. - CI / tooling:
- CI workflows now use a consistent
composer updatestrategy and ignorecomposer.lockin validation steps where appropriate, while keepingcomposer.lockunder version control for reproducible installs. composer.jsonplatform PHP version set to8.1.34for consistent dependency resolution in CI and local development.Makefileand demoMakefiles updated to align testing, coverage, and demo verification targets; README updated to reflect the current tooling.
- CI workflows now use a consistent
- Resilience of export and history reporting tests: The new abstractions and test coverage flush out edge cases around command availability (
tar,gzip,bzip2,zip) and statistics display. No user-facing API changes, but future regressions are less likely.
- README.md: Updated feature list, installation instructions, and links to the expanded documentation set (commands, configuration, usage, testing, demos).
- UPGRADING.md: New section “Upgrading to 1.0.15” describing that this is a non-breaking release focused on internal refactors, test coverage and documentation, with no required configuration changes.
- Main Makefile: New
release-checktarget runs pre-release checks: code style (cs-fix,cs-check), tests with coverage (test-coverage), and demo healthchecks (build and verify each demo). Use before creating a tag. - Demo Makefiles (symfony6, symfony7, symfony8): New targets
release-verify(healthcheck for the demo),restart(down + up), andbuild(build containers). Help text updated for all targets.
- Code style: PHP CS Fixer fixes applied (no functional change). [CI]
(none)
- docs/RELEASE.md: Release process (CHANGELOG, UPGRADING, tag, push). docs/SECURITY.md: Security policy and reporting.
- Custom anonymizer service (anonymizeService): When you reference the service by class name (e.g.
#[Anonymize(anonymizeService: MyAnonymizer::class)]), the bundle resolves it via$container->get(). In Symfony, services are private by default and get inlined at compile time, so the bundle can no longer retrieve them by id. You must declare your custom anonymizer service aspublic: trueinconfig/services.yaml(or equivalent) so the bundle can resolve it. See the demos:App\Service\SmsNotificationAnonymizerServiceis explicitly set topublic: trueindemo/symfony6,demo/symfony7, anddemo/symfony8.
- Demo (symfony6, symfony7, symfony8):
make installandmake upno longer fail with "service php is not running" when the PHP container exits becausevendor/is missing. Composer is now run withdocker-compose run --rm php composer installso dependencies install in a one-off container; thendocker-compose up -d phpis run to start the PHP service with the app ready. - Demo (symfony6, symfony7, symfony8):
SmsNotificationAnonymizerServiceis declared withpublic: trueinconfig/services.yamlsonowo:anonymize:runcan resolve the custom anonymizer and processSmsNotificationwithout "service has been removed or inlined". - Demo (PostgreSQL init): The
userstable indemo/docker/init/postgres/init.sqlnow uses columnsfirst_name,last_name, andcredit_card(instead offirstname,lastname,creditcard) to match Doctrine's underscore naming strategy. Pre-flight checks for thepostgresentity manager no longer fail with "Column first_name (from mapping) does not exist". If you already have a Postgres data volume from a previous run, remove it (e.g.rm -rf demo/symfony8/.data/postgres) and runmake setupagain so the init script runs with the new schema.
- UPGRADING.md: New section "Upgrading to 1.0.13" with the requirement to make custom anonymizer services public when using FQCN, and demo-specific notes (recreate Postgres volume if needed).
- Chunked processing and bounded memory:
AnonymizeService::anonymizeEntity()now loads records in chunks ofbatch_size(LIMIT/OFFSET with ORDER BY primary key) instead of loading all rows at once. Memory usage is bounded by the configured batch size. A singleCOUNT(*)query is run once for progress reporting. - Transaction per chunk: All updates for a chunk are committed in one transaction (one commit per chunk instead of per row), improving throughput when using a custom anonymizer or property-based anonymization.
- EntityAnonymizerServiceInterface: Two new methods for custom anonymizer services:
supportsBatch(): bool— Returntrueto have the bundle callanonymizeBatch()once per chunk;falseto callanonymize()for each record.anonymizeBatch(EntityManagerInterface $em, ClassMetadata $metadata, array $records, bool $dryRun): array— Receives the full chunk of records and returns a maprecord index => (column => new value). Only called whensupportsBatch()returnstrue.
- EntityAnonymizerServiceInterface (breaking): The interface now requires three methods:
supportsBatch(),anonymize(), andanonymizeBatch(). Existing implementations must addsupportsBatch()andanonymizeBatch(). For record-by-record behavior, returnfalsefromsupportsBatch()and implementanonymizeBatch()e.g. by delegating toanonymize()per record (see demos and USAGE.md).
(none)
- CONFIGURATION.md:
batch_sizedescription updated to state that it limits rows loaded per query (memory) and that one transaction is committed per chunk (performance). - USAGE.md: Section "Anonymizing via a custom service" updated with the three interface methods and the record-by-record vs batch behaviour.
- UtmFaker: For types
campaign,term, andcontent,min_lengthandmax_lengthare now enforced again after applying the output format (snake_case, kebab-case, lowercase, etc.). Formatting can shorten the string (e.g. lowercase removes underscores), so the final value now respects the requested length. Fixes flaky testtestGenerateContentWithMinMaxLengthwhen the formatted value was shorter thanmin_length. - Tests / CI:
testConfigureDefinesOptionsno longer usesApplication::add()(not available in all Symfony Console versions used in CI). The test only instantiates the command and reads its definition; options are registered inconfigure()called from the parent constructor.
anonymizeServicewithout#[AnonymizeProperty]: When an entity has only#[Anonymize(anonymizeService: '...')]and no property with#[AnonymizeProperty], the command now processes it and calls the custom service for each record instead of skipping with "No properties found". You can use a custom anonymizer service without defining any property-level attributes. USAGE.md updated to state that no#[AnonymizeProperty]is required when using onlyanonymizeService.
- Tests:
testConfigureDefinesOptionsno longer asserts the-eshortcut for--entity(removed in 1.0.9 to avoid conflict with Symfony's--env).
- DI / FakerFactory:
AnonymizeServiceandPreFlightCheckServicenow receiveFakerFactoryvia explicit injection (@nowo_anonymize.faker_factory) in the bundle'sservices.yaml, so the container builds correctly when the app (or the bundle's autowiring pattern) excludesFakerFactoryfrom autowiring. Fixes "Cannot autowire service ... argument $fakerFactory needs an instance of FakerFactory but this type has been excluded". - Synthetic kernel: Commands and services no longer use the
kernelservice (synthetic until boot). They use thekernel.project_dirparameter orgetParameter('kernel.project_dir')where available, with fallback togetcwd(). Fixes "The 'kernel' service is synthetic, it needs to be set at boot time" in runtimes such as FrankenPHP. Affected:AnonymizeCommand,ExportDatabaseCommand,AnonymizationHistoryCommand,GenerateMongoAnonymizedFieldCommand,DatabaseExportService,KernelParameterBagAdapter. - Console option conflict: The
--entityoption no longer uses the-eshortcut, to avoid conflict with Symfony's global--env(-e). Use--entityonly.
- Demo Makefiles: All three demos (symfony6, symfony7, symfony8) aligned: same targets and help text,
cache-cleartarget added,update-bundleruns fullcache:clear(with warmup). Symfony 6 keepsupdate-symfonyin help and as a target.
nowo:anonymize:run: New--entityoption to process only the given entity class name(s). Can be used multiple times. Useful to test a single entity, itsanonymizeServiceor event listeners. See COMMANDS.md.- FakerFactory: Public alias
nowo_anonymize.faker_factoryfor injection in app services. CONFIGURATION.md now includes a section "Using FakerFactory in your own services" explaining that services depending onFakerFactorymust be registered only in dev/test (where the bundle is loaded) to avoid "no such service exists" when the container is built.
- Tests: DateFaker future-date assertion now compares by date string (avoids timezone/midnight flakiness). AnonymizeCommand entity-filter test updated for DBAL
Resultreturn type and ORM metadata mocks.
- Doctrine DBAL 4 / PHP 8.1 CI: Identifier quoting now uses the database platform when available, so the bundle works with DBAL 4 where
Connection::quoteSingleIdentifiermay be final or static and not mockable.DbalHelper::quoteIdentifier()prefers$connection->getDatabasePlatform()->quoteSingleIdentifier()first, then falls back to connection-level quoting or driver-aware manual quoting. No change for end users; tests were updated to mock the platform instead of the connection so CI passes on PHP 8.1 with DBAL 4.
- PostgreSQL / AnonymizeService: The
anonymizedcolumn (boolean) is now written with SQL literalsTRUE/FALSEon PostgreSQL instead of1/0, fixingSQLSTATE[42804]: Datatype mismatch: column "anonymized" is of type boolean but expression is of type integer. MySQL and other platforms continue to use1/0. Detection usesDbalHelper::getDriverName()(pgsql) for compatibility across DBAL versions.
- UPGRADING.md: Standardized section headings to "Migration Steps" (was mixed with "Upgrade Steps"). Renamed duplicate "Upgrading to 1.0.0 (Initial Release)" to "Installing the bundle (first-time install)" for clarity.
- ROADMAP.md: Vision, adoption strategy (Phases A–C), and four pillars for community adoption; Implementation Priority aligned with adoption milestones.
-
Anonymization via custom service (
anonymizeService): Entity-level option to delegate anonymization to a service instead ofAnonymizePropertyattributes.- New parameter on
#[Anonymize]:anonymizeService(string, service id). When set, the bundle calls this service for each record instead of applying property-based anonymization. - New interface:
Nowo\AnonymizeBundle\Service\EntityAnonymizerServiceInterfacewith methodanonymize(EntityManagerInterface $em, ClassMetadata $metadata, array $record, bool $dryRun): array(returns column => value for updates). - Useful for polymorphic entities (different logic per subtype), API-based anonymization, or complex rules. Documented in USAGE.md and CONFIGURATION.md.
- Demos:
SmsNotificationusesSmsNotificationAnonymizerServicein all demo projects (symfony6, symfony7, symfony8).
- New parameter on
-
Truncate by discriminator (polymorphic entities): When an entity uses Doctrine inheritance (STI/CTI) and
truncate: true, the bundle now deletes only rows for that entity's discriminator value instead of truncating the whole table.- Detection is automatic via
inheritanceType,discriminatorColumn, anddiscriminatorValuein metadata. - No extra configuration: normal entities still get full table truncate; polymorphic entities get
DELETE FROM table WHERE discriminator_column = value. - When loading records for anonymization, the query is also restricted by discriminator so only rows of that subtype are processed.
- Detection is automatic via
- AnonymizeService: Constructor accepts optional
ContainerInterface $containerto resolveanonymizeServiceby id. Required when any entity usesanonymizeService(bundle wiring provides it when available).
- USAGE.md: New section "Anonymizing via a custom service (anonymizeService)" with interface and example; truncation section extended with "Polymorphic entities (STI/CTI)".
- CONFIGURATION.md:
#[Anonymize]syntax updated withanonymizeServiceand polymorphic truncate behavior. - Demo folders: References updated from
demo-symfony6/7/8tosymfony6/7/8in docs and scripts where applicable.
- Notification CRUD (symfony6, 7, 8): Fixed breadcrumb route
notification_index_index→notification_indexin_breadcrumbs.html.twig(use_route,listRoute/indexRoute/routePrefix, and entityName fallback for Notifications). Notification index/show templates now passlistRoute: 'notification_index'androutePrefix: 'notification'withonlyto avoid context leakage. All three demos aligned (same breadcrumb logic and notification includes).
- Doctrine ORM 3 compatibility:
AnonymizeService::getDiscriminatorForTruncate()now accepts both array (ORM 2.x) andDiscriminatorColumnMappingobject (ORM 3.x) fordiscriminatorColumnmetadata. Tests useDiscriminatorColumnMappingwhen available. - UtmFaker:
generateCampaign()now enforcesmin_lengthandmax_lengthin all code paths (predefined patterns and random words); previously a single short word could yield a campaign shorter thanmin_length. - AnonymizeTest:
testAnonymizePropertiesArePublicnow usesproperty_exists()instead ofisset()so nullable properties (e.g.truncate_order) are correctly reported as present.
-
Map Faker: New faker type for value substitution ("if value is X, put Y")
- Options:
map(required, associative arrayoriginal_value => replacement_value),default(optional; if omitted, unmapped values are left as-is). - Use case: anonymize status/role fields by mapping each original value to a fixed replacement (e.g.
active→status_a,inactive→status_b). - Registered as
mapinFakerTypeandFakerFactory. Documented inFAKERS.md. - Tests:
MapFakerTest. Demo:FakerTypeExampleentity withstatusfield in all demos (Symfony 6, 7, 8).
- Options:
-
Demos: AnonymizePropertySubscriber: Example listener for
AnonymizePropertyEvent- Dispatched before each property is anonymized; allows pre-processing (e.g. migrate files from Amazon S3 to another storage before replacing the field).
- Declared with
#[AsEventListener(event: AnonymizePropertyEvent::class)](Symfony 6.3+). - Located in
demo/*/src/EventSubscriber/AnonymizePropertySubscriber.phpwith commented S3 migration example.
-
Tests: AnonymizePropertyListenerTest: Tests for the listener pattern on
AnonymizePropertyEvent- Covers: listener no-op,
setAnonymizedValue(),setSkipAnonymization(), readinggetRecord().
- Covers: listener no-op,
- FakerFactory: Match keys now use
FakerType::CONSTANT->valueinstead of string literals for consistency with the enum and easier maintenance.
- UtmFaker:
generateTerm()now enforcesmin_lengthandmax_length; previously a single short word could yield a result shorter thanmin_length(e.g. 2 chars when min was 5).
- Map faker already documented in
FAKERS.md. Event listener example withAsEventListenerinUSAGE.md.
-
excludePatterns / includePatterns: array value (OR for one field)
Pattern values can be an array of strings; the record matches if the field value matches any option.- Example:
'email' => ['%@nowo.tech', 'operador@example.com']— exclude when email matches any option. - Same syntax for
includePatterns. Backward compatible: string values (and|within string) still work.
- Example:
-
excludePatterns / includePatterns: multiple configs (OR between configs)
You can pass a list of pattern sets; the record is excluded (or included) when any config matches.- Example:
[ ['role' => 'admin', 'email' => '%@nowo.tech'], ['status' => 'deleted'], ['id' => '<=100'] ]— exclude when (config1) OR (config2) OR (config3). - Within each config all fields are AND; between configs the logic is OR.
- Same for
includePatterns. Documented in CONFIGURATION.md and USAGE.md.
- Example:
-
Demos: bundle from repo
Demos now use the bundle code from the repository via path repository (/bundles) when run with Docker, so you can test local changes (e.g. new excludePatterns) without publishing. Seedemo/README.md.
-
ProtectedUser demo
Uses the new multiple-configs syntax forexcludePatterns(list of configs) for clearer examples. -
UserAccount demo
Uses array value forexcludePatternson email:'email' => ['%@visitor.com', '%@internal.com']. -
PatternMatcher
Supports pattern value as string or array (OR), and patterns as single config or list of configs (OR between configs). -
AnonymizeService
UsesgetPatternFieldNames()so entity/property patterns work correctly when using list of configs (all field names collected for query building). -
PreFlightCheckService
Validates both array values and list-of-configs forincludePatternsandexcludePatterns.
- CONFIGURATION.md: "Array of options" and "Multiple configs (OR between sets)" with examples.
- USAGE.md: Examples 4 (array value) and 5 (multiple configs).
- EXAMPLES_PATTERN_BASED.md: excludePatterns with array of options.
- demo/README.md: "Bundle code from the repo" explains path repo usage.
- Table Truncation Support: Added
truncateandtruncate_orderoptions to#[Anonymize]attribute- Tables can now be emptied (truncated) before anonymization
truncate_orderallows controlling the order of truncation for tables with dependencies- Tables without explicit order are truncated alphabetically after those with orders
- Automatic handling of foreign key constraints (MySQL, PostgreSQL, SQLite)
- Support for dry-run mode to preview truncation
- New demo entities:
TempData,CacheData,LogEntrydemonstrating truncation scenarios - New demo fixtures:
TempDataFixtures(8 records),CacheDataFixtures(6 records),LogEntryFixtures(10 records) for testing truncation functionality
-
New Faker: UTM Faker: Generate anonymized UTM (Urchin Tracking Module) parameters for marketing campaign tracking
- Supports all UTM parameter types:
source,medium,campaign,term, andcontent - Multiple format options:
snake_case,kebab-case,camelCase,lowercase,PascalCase - Custom lists support:
custom_sources,custom_mediums,custom_campaigns - Prefix and suffix options for generated values
- Configurable min/max length for campaign, term, and content types
- Predefined common sources (google, facebook, twitter, linkedin, etc.)
- Predefined common mediums (cpc, email, social, organic, etc.)
- Predefined campaign patterns (spring_sale, product_launch, etc.)
- Registered as
utmfaker type inFakerTypeenum - Comprehensive test coverage: 25 tests with multiple assertions
- Perfect for anonymizing marketing campaign tracking data while maintaining realistic parameter formats
- Supports all UTM parameter types:
-
Example Custom Faker: Reference implementation for creating custom faker services
- Located at
src/Faker/Example/ExampleCustomFaker.php - Comprehensive example demonstrating best practices for custom fakers
- Shows how to preserve original values (useful for testing events)
- Demonstrates accessing other fields from the current record
- Shows how to access related entities using EntityManager
- Includes extensive documentation with code examples
- Perfect reference for users creating their own custom fakers
- Can be copied and adapted for project-specific needs
- Comprehensive test coverage: 13 tests with 26+ assertions
- Located at
-
Demo: CustomFakerExample Entity: New example entity demonstrating
ExampleCustomFakerusage- Shows how to use custom faker services with
preserve_originaloption - Demonstrates accessing record fields and custom options
- Includes comprehensive fixtures with 5 records covering various scenarios
- Available in all demo projects (Symfony 6, 7, 8)
- Perfect reference for understanding custom faker implementation
- Shows how to use custom faker services with
-
Demo: MarketingCampaign Entity: New example entity demonstrating
UtmFakerusage- Shows how to use UTM faker for all parameter types (source, medium, campaign, term, content)
- Demonstrates different formats (snake_case, kebab-case)
- Shows custom sources and length constraints
- Includes comprehensive fixtures with 8 records covering various UTM scenarios
- Available in all demo projects (Symfony 6, 7, 8)
- Perfect reference for anonymizing marketing campaign data
-
Documentation: Enhanced documentation for custom fakers and UTM faker
- Added comprehensive section in
USAGE.mdabout custom service fakers - Detailed examples showing how to use
ExampleCustomFakeras reference - Complete documentation for UTM faker with all options and examples
- Updated
FAKERS.mdwith UTM faker description and custom faker reference - All examples include multiple use cases and edge cases
- Added comprehensive section in
-
Total Faker Types: Increased from 38 to 39 fakers
- Added
utmfor generating anonymized UTM parameters - Added
ExampleCustomFakeras reference implementation (not counted in total, but available)
- Added
-
Test Coverage: Improved test coverage
- Added comprehensive tests for
UtmFaker(25 tests) - Added comprehensive tests for
ExampleCustomFaker(13 tests, 26+ assertions) - All tests passing successfully
- Added comprehensive tests for
-
FakerFactory: Updated to support UTM faker
- Added service registration for
utmfaker - Added direct instantiation fallback for
utmfaker - Integrated with existing faker infrastructure
- Added service registration for
-
FakerType Enum: Updated to include UTM faker
- Added
UTM = 'utm'case to enum - Maintains type safety and IDE autocompletion
- Added
-
Demo: ProtectedUser Entity: New comprehensive example entity demonstrating
excludePatternsat entity level- Shows how to exclude entire records from anonymization when fields match specific patterns
- Demonstrates multiple exclusion patterns working together:
- Email pattern matching:
'email' => '%@visitor.com' - Role-based exclusion:
'role' => 'admin' - ID range exclusion:
'id' => '<=100' - Status-based exclusion with OR operator:
'status' => 'archived|deleted'
- Email pattern matching:
- Includes comprehensive fixtures with 25+ records covering all exclusion scenarios
- Demonstrates edge cases (records matching multiple exclusion patterns)
- Available in all demo projects (Symfony 6, 7, 8)
- Perfect reference for understanding entity-level pattern filtering
-
Documentation: Enhanced documentation for entity-level
excludePatterns- Clarified how
excludePatternswork at entity level to exclude entire records - Added comprehensive examples in
ProtectedUserentity - Updated usage examples to show multiple exclusion patterns
- Clarified how
- Demo Coverage: Improved demo coverage for pattern-based filtering
- Existing demos (Order, Employee, Customer) already demonstrate
excludePatterns - New
ProtectedUserdemo provides comprehensive multi-pattern examples - All demos include detailed comments in fixtures explaining exclusion logic
- Existing demos (Order, Employee, Customer) already demonstrate
- Enhanced examples showing how to exclude records based on multiple criteria
- Clarified the difference between entity-level and property-level pattern filtering
- Added comprehensive use cases for
excludePatternsat entity level
-
New Faker: Pattern-Based Faker: Constructs values from other fields with pattern extraction
- Perfect for fields derived from other fields that need to preserve patterns (e.g., username from email with number suffix)
- Extracts a pattern from the original value and appends it to the anonymized source field value
- Options:
source_field(required),pattern(regex),pattern_replacement,separator,fallback_faker,fallback_options - Example:
['source_field' => 'email', 'pattern' => '/(\\(\\d+\\))$/']preserves number in parentheses - Automatically receives the full record with already anonymized values
- Registered as
pattern_basedfaker type - Comprehensive test coverage: 13 tests with 26 assertions
-
New Faker: Copy Faker: Copies values from other fields
- Perfect for fields that should be identical after anonymization (e.g., email and emailCanonical)
- Simply copies the anonymized value from the source field
- Options:
source_field(required),fallback_faker,fallback_options - Example:
['source_field' => 'email']copies anonymized email value - Automatically receives the full record with already anonymized values
- Registered as
copyfaker type - Comprehensive test coverage: 9 tests with 19 assertions
-
Demo: UserAccount Entity: New example entity demonstrating
copyandpattern_basedfakers together- Shows how to use
copyto makeemailCanonicalsame asemail - Shows how to use
pattern_basedto constructusernamefromemailwhile preserving pattern - Includes comprehensive fixtures with 10 records
- Demonstrates complete workflow: email → username (with pattern) → usernameCanonical (same) → emailCanonical (copy)
- Available in all demo projects (Symfony 6, 7, 8)
- Shows how to use
-
Documentation: Enhanced documentation with comprehensive examples
- Added
EXAMPLES_PATTERN_BASED.mdwith detailed examples ofpattern_basedandcopyfakers - Updated
USAGE.mdwith complete examples showingpattern_basedandcopyworking together - Updated
FAKERS.mdwith descriptions of new fakers - All examples include multiple use cases and edge cases
- Added
-
Total Faker Types: Increased from 35 to 37 fakers
- Added
pattern_basedfor constructing values from other fields with pattern extraction - Added
copyfor copying values from other fields
- Added
-
Test Coverage: Improved test coverage
- Total tests: 788 tests with 2166 assertions (increased from 766 tests)
- Code coverage metrics:
- Classes: 67.69% (44/65)
- Methods: 75.61% (186/246)
- Lines: 61.79% (1942/3143)
- Added comprehensive tests for
pattern_basedfaker (13 tests, 26 assertions) - Added comprehensive tests for
copyfaker (9 tests, 19 assertions) - All tests passing successfully
-
AnonymizeService: Enhanced to support
pattern_basedandcopyfakers- Modified to pass merged record (original + anonymized values) to these fakers
- Ensures
source_fieldcontains the anonymized value if it was processed earlier - Maintains correct processing order based on
weightattribute
-
FakerFactory: Updated to support new faker types
- Added service registration for
pattern_basedandcopyfakers - Added direct instantiation fallback for both fakers
- Integrated with existing faker infrastructure
- Added service registration for
-
Nullable Option for All Fakers: Added support for generating
nullvalues with configurable probability- New options:
nullable(bool) andnull_probability(0-100) - Works with all faker types
- Useful for simulating optional fields and creating more realistic anonymized datasets
- Example:
['nullable' => true, 'null_probability' => 30]generates null 30% of the time - When a value is determined to be null, it bypasses faker generation and sets the field to
nulldirectly - Preserves null values during type conversion to prevent null from being converted to empty strings
- New options:
-
Preserve Null Option for All Fakers: Added support for preserving null values (skip anonymization when original is null)
- New option:
preserve_null(bool) - Works with all faker types
- If
preserve_nullistrueand the original value isnull, the field is skipped (not anonymized) - If
preserve_nullistrueand the original value has a value, it is anonymized normally - Useful for anonymizing only fields that have values, leaving nulls unchanged
- Example:
['preserve_null' => true]- only anonymizes if the field has a value - Takes precedence over
nullableoption when original value is null
- New option:
-
New Faker: DNI/CIF/NIF Faker: Spanish identification number anonymization
- Supports DNI (8 digits + 1 letter), CIF (1 letter + 7 digits + 1 letter/digit), and NIF formats
- Auto-detects type from original value if available
- Optional formatting with separators (e.g.,
12345678-AorA-1234567-4) - Generates valid identification numbers with proper checksum validation
- Options:
type(dni/cif/nif/auto),formatted(bool) - Example:
#[AnonymizeProperty(type: 'dni_cif', options: ['type' => 'auto', 'formatted' => false])]
-
New Faker: Name Fallback Faker: Handles nullable related name fields
- Perfect for entities with multiple name fields (e.g.,
nameandfirstname) where one can be nullable - Ensures data consistency: if one field has value and the other is null, generates a random value for the null field
- Automatically uses the full database record to check related field values
- Options:
fallback_field(required),gender(male/female/random),locale_specific(bool) - Example:
#[AnonymizeProperty(type: 'name_fallback', options: ['fallback_field' => 'firstname'])] - Behavior:
- If current field is null but related field has value → generates random name
- If current field has value → anonymizes normally
- If both are null → generates random name
- If both have values → anonymizes both normally
- Perfect for entities with multiple name fields (e.g.,
-
New Faker: HTML Faker: Generates anonymized HTML content with lorem ipsum
- Perfect for anonymizing email signatures, HTML templates, and HTML content
- Supports multiple types:
signature(email signature-like),paragraph,list,mixed - Generates valid HTML with lorem ipsum text while maintaining realistic structure
- Options:
type,include_links,include_styles,min_paragraphs,max_paragraphs,min_list_items,max_list_items - Signature type includes name, title, company, contact info with optional links and styles
- Example:
#[AnonymizeProperty(type: 'html', options: ['type' => 'signature', 'include_links' => true])]
-
Demo: Person Entity: New example entity demonstrating
name_fallbackfaker- Shows how to handle nullable related name fields
- Includes comprehensive fixtures covering all use cases:
- Both fields have values
- Only
namehas value (firstname is null) - Only
firstnamehas value (name is null) - Both fields are null
- Available in all demo projects (Symfony 6, 7, 8)
-
Demo: EmailSignature Entity: New example entity demonstrating
htmlfaker- Shows how to anonymize email signatures and HTML email bodies
- Includes comprehensive fixtures with realistic email signatures
- Demonstrates different HTML faker types (signature, paragraph)
- Available in all demo projects (Symfony 6, 7, 8)
-
Demo: Contact Entity: New example entity demonstrating
nullableandpreserve_nulloptions- Shows how to use
nullablewithnull_probabilityto generate null values with configurable probability - Shows how to use
preserve_nullto skip anonymization when original value is null - Includes comprehensive fixtures with 8 records covering all use cases
- Demonstrates both options working together with different faker types
- Available in all demo projects (Symfony 6, 7, 8)
- Shows how to use
-
Total Faker Types: Increased from 32 to 35 fakers
- Added
dni_ciffor Spanish identification numbers - Added
name_fallbackfor nullable related name fields - Added
htmlfor HTML content with lorem ipsum (perfect for email signatures)
- Added
-
Test Coverage: Improved test coverage
- Total tests: 766 tests with 2121 assertions (increased from 726 tests)
- Code coverage metrics:
- Classes: 68.25% (43/63)
- Methods: 75.42% (181/240)
- Lines: 61.29% (1884/3074)
- Added comprehensive tests for
nullableandpreserve_nulloptions - All tests passing successfully
-
Test Coverage: Significantly improved code coverage across the entire bundle
- Added comprehensive test suites for multiple components
- Total tests: 726 tests with 2011 assertions (increased from 660 tests)
- Code coverage metrics:
- Classes: 73.33% (44/60) - 44 classes with 100% coverage
- Methods: 75.89% (170/224)
- Lines: 59.57% (1731/2906)
- All tests passing successfully
-
Command Tests: Added comprehensive test coverage for commands
GenerateAnonymizedColumnCommand: 9 new tests covering instantiation, configuration, execution scenariosExportDatabaseCommand: 9 new tests covering command structure, formatBytes, getParameterBagGenerateMongoAnonymizedFieldCommand: 12 new tests covering script generation, file output, project root detectionAnonymizationHistoryCommand: Enhanced test coverage
-
Attribute Tests: Complete test coverage for attribute classes
Anonymize: 6 tests covering all constructor parameters and property accessAnonymizeProperty: 9 tests covering all faker types, options, and property access- Both attribute classes now have 100% code coverage
-
Faker Tests: Enhanced test coverage for faker classes
HashPreserveFaker: 4 additional tests for preserve_format edge cases (long hashes, float/integer values)EnumFaker: 4 additional tests for weighted value selection, zero weights, small weights, locale supportJsonFaker: 4 additional tests for object type with zero depth, number type, random structure edge casesDbalHelper: 6 additional tests for quoteIdentifier and getDriverName edge cases
-
Service Tests: Enhanced test coverage for core services
AnonymizeService: Additional tests for buildQueryWithRelationships with duplicate patternsAnonymizeStatistics: Enhanced tests for formatDuration edge casesPatternMatcher: Additional edge case testsPreFlightCheckService: Comprehensive test coverage improvementsEnvironmentProtectionService: Complete test coverageDatabaseExportService: Enhanced test coverage
-
Event Tests: Complete test coverage for all event classes
AnonymizePropertyEvent: All getters, setters, and skip functionality testedBeforeAnonymizeEvent: Complete test coverageAfterAnonymizeEvent: Complete test coverageBeforeEntityAnonymizeEvent: Complete test coverageAfterEntityAnonymizeEvent: Complete test coverage- All event classes now have 100% code coverage
-
Trait Tests: Complete test coverage for AnonymizableTrait
- 7 tests covering all methods and edge cases
- 100% code coverage achieved
-
Enum Tests: Complete test coverage for enum classes
FakerType: All enum cases testedSymfonyService: All constants tested- Both enum classes now have 100% code coverage
-
Dependency Injection Tests: Complete test coverage
AnonymizeExtension: All methods testedConfiguration: Complete test coverage- Both classes now have 100% code coverage
-
Bundle Tests: Complete test coverage for AnonymizeBundle
getContainerExtensionmethod fully tested- 100% code coverage achieved
-
PasswordFaker: Fixed intermittent test failures
- Ensured guaranteed inclusion of special characters and numbers when options are enabled
- Improved password generation algorithm for deterministic character type inclusion
-
PatternMatcher: Fixed TypeError with non-string values
- Added type check before calling
str_starts_with()to prevent errors with boolean values
- Added type check before calling
-
AnonymizeStatistics: Fixed CSV export with empty properties
- Only includes property header when there are actual properties to report
-
Test Robustness: Improved test reliability
- Fixed multiple test failures related to mocking final classes
- Improved test assertions for edge cases
- Enhanced test data generation for better coverage
- AnonymizeService: Fixed boolean and null value handling in SQL UPDATE queries
- Boolean
falsevalues were incorrectly converted to empty string''instead of'0' - Boolean
truevalues now correctly converted to'1' nullvalues now correctly converted to SQLNULL(unquoted)- Resolves
SQLSTATE[HY000]: General error: 1366 Incorrect integer value: '' for column 'is_active'error - Affects MySQL
tinyintcolumns and other boolean-type columns
- Boolean
- Demo Projects: Enhanced Symfony 6 demo Makefile
- Added
update-symfonycommand to help migrate from Symfony 6.0 to 6.1+ - Updated help text to reflect Symfony 6.1+ requirement
- Improved documentation for bundle installation process
- Added
- Services Configuration: Fixed FakerFactory autowiring error
FakerFactorywas excluded from autowiring pattern but needed byAnonymizeServiceandPreFlightCheckService- Now explicitly registered in
services.yamlwith locale parameter - Resolves "Cannot autowire service AnonymizeService: argument FakerFactory has been excluded" error
-
Services Configuration: Simplified
services.yamlusing autowiring pattern- Replaced explicit faker definitions with autowiring pattern and
exclude - Reduced configuration from ~165 lines to ~95 lines (42% reduction)
- All fakers now use
#[Autowire('%nowo_anonymize.locale%')]attribute - Requires Symfony 6.1+ (already documented requirement)
- More maintainable and cleaner configuration
- Replaced explicit faker definitions with autowiring pattern and
-
Documentation: Complete documentation update for Symfony 6.1+ requirement
- Updated all documentation files to consistently state Symfony 6.1+ requirement
- Added requirement notes to all major documentation files
- Updated demo projects documentation
- Fixed inconsistencies in demo composer.json files
- Demo Projects: Fixed Symfony version inconsistencies
- Updated
demo-symfony6/composer.jsonto use^6.1for all Symfony dependencies - Updated
debug-bundleandweb-profiler-bundleto^6.1 - Updated Symfony Flex
requireto6.1.* - Updated demo README files to reflect Symfony 6.1+ requirement
- Updated
-
Standardized Faker API: All fakers now receive
original_valueparameterFakerInterfaceupdated to documentoriginal_valueas standard parameter- All fakers receive the original database value automatically
- Enables more intelligent fakers that can use original values when needed
- Improves versatility and extensibility for custom fakers
-
Improved PreFlightCheckService: Enhanced column existence checking
- Now queries actual database columns instead of relying solely on Doctrine mapping
- Case-insensitive matching for better compatibility
- More informative error messages showing available columns
- Helps identify mapping issues (e.g., firstname vs firstName)
-
Symfony Version Requirement: Minimum Symfony version increased to 6.1+
- Required for
#[Autowire]attribute support in constructor parameters - All fakers now use
#[Autowire('%nowo_anonymize.locale%')]attribute - Symfony 6.0 is no longer supported
- Updated
composer.json, documentation, and demo projects
- Required for
-
AnonymizeService: Always passes
original_valueto all fakers- Standardized API: all fakers receive
original_valueautomatically - Backward compatibility:
hash_preserveandmaskingstill supportvaluekey - Fakers can use or ignore the original value as needed
- Standardized API: all fakers receive
-
HashPreserveFaker and MaskingFaker: Support both
original_valueandvalue- Accept
original_value(standard) orvalue(backward compatibility) - Prioritize
original_valueif available
- Accept
- PreFlightCheckService: Fixed column name detection
- Now queries actual database schema instead of relying on mapping
- Better error messages with column suggestions
- Case-insensitive matching for database compatibility
- Symfony 6.1+ Compatibility: Fixed services.yaml configuration error
- Removed autowiring pattern with
exclude(incompatible with Symfony 6.0, now requires 6.1+) - Explicitly defined all 28 fakers that require
localeparameter - Resolved error: "Argument #1 ($resource) must be of type string, array given"
- Services configuration now works correctly in Symfony 6.1+, 7.0, and 8.0
- Removed autowiring pattern with
-
DbalHelper Enhancement: New
getDriverName()method for DBAL compatibility- Provides cross-version compatibility for getting database driver names
- Supports DBAL 2.x and 3.x with multiple fallback strategies
- Extracts driver name from platform class, connection params, or defaults to 'pdo_mysql'
- Used by
ExportDatabaseCommandandDatabaseExportServicefor better compatibility
-
Demo UI Improvements: Enhanced navigation and visual consistency
- Added breadcrumbs navigation to all CRUD pages (index, show, new, edit)
- Standardized anonymized badge display with icons and consistent colors
- Created reusable
_breadcrumbs.html.twigand_anonymized_badge.html.twigcomponents - All 156 templates across 3 demos now have consistent navigation and badges
-
MongoDB Fixtures: Improved fixture loading and data generation
- Enhanced
load-fixtures.jsscript with better error handling - Created
scripts/reload-mongodb-fixtures.shscript for manual fixture reloading - Improved
entrypoint.shfor better MongoDB container detection - All 5 MongoDB collections now have sample data (125 documents per demo)
- Enhanced
-
HashPreserveFaker: Fixed "requires a 'value' option" error
AnonymizeServicenow automatically passes the original value toHashPreserveFaker- No need to manually specify
valueoption in#[AnonymizeProperty]attributes - Resolved error when anonymizing entities with
hash_preservefaker type - Affects
SystemLogentity and any entity usinghash_preservefaker
-
ExportDatabaseCommand: Fixed DBAL compatibility error
- Replaced
$connection->getDriver()->getName()withDbalHelper::getDriverName() - Resolved "Call to undefined method Driver::getName()" error in Symfony 6.1+/7.0
- Improved compatibility across different Doctrine DBAL versions
DatabaseExportServicealso updated to use the new helper method
- Replaced
-
AnonymizeService: Enhanced faker option handling
- Automatically injects original value for
hash_preservefaker type - Maintains backward compatibility with existing configurations
- Improves developer experience by reducing required configuration
- Automatically injects original value for
-
Demo Templates: Standardized UI components
- All anonymized badges now use consistent styling (green check for anonymized, gray X for not anonymized)
- Bootstrap Icons used for visual clarity
- Breadcrumbs follow consistent pattern: Home > Entity (connection) > Current Page
-
DbalHelper: New static helper class for DBAL operations
- Created
DbalHelper::quoteIdentifier()static method for database identifier quoting - Compatible with both DBAL 2.x and 3.x versions
- Can be used from anywhere without instantiation
- Centralized location for DBAL compatibility methods
- Created
-
AbstractCommand: New base class for all bundle commands
- Provides common functionality for all commands
- Includes wrapper method for
quoteIdentifier()for command convenience - All 6 commands now extend from
AbstractCommand
-
Testing Infrastructure: Added testing script and documentation
- Created
scripts/test-commands.shscript for automated command testing - Added
docs/TESTING_COMMANDS.mdguide for testing all commands - Script supports testing in all three demo applications (Symfony 6, 7, 8)
- Created
- Code Refactoring: Improved code organization and reusability
- Moved
quoteIdentifier()logic to staticDbalHelperclass - All commands now extend
AbstractCommandinstead ofCommanddirectly AnonymizeServicenow usesDbalHelper::quoteIdentifier()directly- Eliminated code duplication across commands and services
- Replaced
Command::SUCCESS/FAILUREwithself::SUCCESS/FAILUREfor consistency
- Moved
-
PreFlightCheckService: Fixed
getEntityManager()method call errorClassMetadatadoes not havegetEntityManager()method- Updated
checkColumnExistence()to receiveEntityManagerInterfaceas parameter - Resolved error: "Call to undefined method Doctrine\ORM\Mapping\ClassMetadata::getEntityManager()"
-
DBAL Compatibility: Fixed
quoteSingleIdentifier()compatibility issues- Added fallback for DBAL versions that don't have
quoteSingleIdentifier()method - Supports DBAL 2.x (
quoteIdentifier) and DBAL 3.x (quoteSingleIdentifier) - Manual fallback with backticks for maximum compatibility
- Added fallback for DBAL versions that don't have
- Demo Improvements: Enhanced demo applications with better navigation and user experience
- Added "Back to List" links in all form pages (new.html.twig and edit.html.twig) for better navigation
- Added missing links in home page for EmailSubscription, SystemLog, and all MongoDB collections
- Added SQLite connection links in sidebar navigation for all ORM entities
- Improved consistency across all three demo applications (Symfony 6, 7, and 8)
- Demo Navigation: Fixed missing
connectionparameter in home page links- EmailSubscription and SystemLog links now correctly include the
connectionparameter - All home page links now follow the same pattern as other entities (MySQL, PostgreSQL, SQLite)
- Resolved routing error: "Some mandatory parameters are missing ("connection") to generate a URL"
- EmailSubscription and SystemLog links now correctly include the
-
Symfony 6.1+ Compatibility: Fixed compatibility issue
- Moved command help text from
#[AsCommand]attribute parameter tosetHelp()method inconfigure() - The
helpparameter in#[AsCommand]is only available from Symfony 6.1+ - All commands now use
setHelp()for maximum compatibility (Symfony 6.1+, 7.0, 8.0) - Affected commands:
AnonymizeCommand,AnonymizationHistoryCommand,ExportDatabaseCommand,AnonymizeInfoCommand,GenerateAnonymizedColumnCommand,GenerateMongoAnonymizedFieldCommand
- Moved command help text from
-
DatabaseExportService Configuration: Fixed autowiring issue for
DatabaseExportService- Service now explicitly configured in
services.yamlwith all required parameters - Excluded from automatic autowiring to prevent parameter resolution issues
- All parameters (
outputDir,filenamePattern,compression,autoGitignore) now correctly resolved from bundle configuration
- Service now explicitly configured in
-
UsernameFaker Overflow Warning: Fixed PHP warning for float-to-int conversion
- Limited
remainingLengthto maximum 9 to prevent overflow when calculatingpow(10, n) - Prevents warning: "The float ... is not representable as an int, cast occurred"
pow(10, 9) = 1,000,000,000is safe for int representation in PHP
- Limited
-
TextFakerTest Flaky Test: Improved test robustness for Faker randomness
- Test now runs 10 iterations to account for Faker's random word generation
- More lenient assertions that handle Faker's occasional generation of fewer words than requested
- Test verifies minimum word count across iterations rather than single assertion
-
Interactive Mode: Step-by-step confirmation prompts for anonymization
- New
--interactiveor-ioption for thenowo:anonymize:runcommand - Summary display before starting anonymization
- Confirmation prompts for each entity manager
- Confirmation prompts for each entity before processing
- Shows entity details (table name, property count) in interactive mode
- Verbose mode shows property details (faker types) in interactive prompts
- Allows selective processing of entity managers and entities
- Improves safety and user control during anonymization
- New
-
Enhanced Reporting: Improved statistics and export capabilities
- New
--stats-csvoption to export statistics to CSV format - Success rate calculation and display (global and per-entity)
- Enhanced statistics tables with success rate column
- CSV export includes: global statistics, entity statistics, and property statistics
- Improved statistics display with more detailed metrics
- CSV format suitable for spreadsheet analysis and reporting
- Configurable output directory for statistics via
stats_output_dirconfiguration - Relative file paths automatically use configured output directory
- Absolute paths are used as-is for maximum flexibility
- New
-
Database Export Command: Export databases to files with optional compression
- New
nowo:anonymize:export-dbcommand for exporting databases - Supports MySQL (mysqldump), PostgreSQL (pg_dump), SQLite (file copy), and MongoDB (mongodump)
- Configurable output directory and filename patterns with placeholders
- Compression support: gzip, bzip2, zip (auto-detects available tools)
- Automatic
.gitignoremanagement to exclude export directory - Selective export: export specific connections or all connections
- Configurable via bundle configuration (
nowo_anonymize.export.*) - Filename pattern placeholders:
{connection},{database},{date},{time},{format} - Command-line options for overriding configuration
- Detailed export summary with file sizes and success/failure counts
- New
-
Configuration Enhancements:
- New
stats_output_dirconfiguration option for statistics export directory - New
exportconfiguration section for database export settings - All command help text moved to
#[AsCommand]attributes for better organization - Symfony Flex recipe updated with all new configuration options
- New
-
Anonymization History: Track and manage anonymization runs
- New
nowo:anonymize:historycommand to view and manage anonymization history - Automatic saving of anonymization run metadata after each execution
- List all anonymization runs with filtering options (limit, connection)
- View detailed information about specific runs
- Compare two anonymization runs side-by-side
- Cleanup old runs to manage storage
- History stored in JSON format with index file for quick access
- Configurable history directory via
history_dirconfiguration option - Includes metadata: environment, PHP version, Symfony version, command options
- Comparison shows differences in entities processed, updated, and duration
- New
-
Relationship Patterns Support: Patterns can now reference related entities using dot notation
- Support for relationship patterns in
includePatternsandexcludePatterns(e.g.,'type.name' => '%HR') - Automatic SQL JOIN construction for relationship patterns
- Works with all pattern operators: comparison (
>,<,=, etc.), SQL LIKE (%), and OR (|) - Supports
ManyToOneandOneToOnerelationships - Example:
#[Anonymize(includePatterns: ['type.name' => '%HR', 'status' => 'completed'])] - The bundle automatically detects relationship patterns and builds appropriate SQL queries with LEFT JOINs
- PatternMatcher updated to access nested relationship values
- Documented in
docs/USAGE.mdanddocs/CONFIGURATION.md
- Support for relationship patterns in
-
Demo: Type Entity and Relationship Example: New example demonstrating relationship patterns
- Created
Typeentity (id, name, description) in all demo projects - Added
ManyToOnerelationship fromOrdertoType - Updated
Orderentity with relationship pattern example:['type.name' => '%HR'] - Created
TypeFixtureswith 7 types (HR, HR Management, Sales, IT, Marketing, Finance, Operations) - Updated
OrderFixturesto include type relationships - Applied to all demo projects (Symfony 6, 7, 8)
- Created
- Demo: MongoDB CRUD Navigation: Enhanced menu navigation in all demo projects
- Added MongoDB section to sidebar menu in
base.html.twig - "User Activities (MongoDB)" link now visible in navigation menu
- Better integration of MongoDB CRUD with other entity CRUDs
- Applied to all demo projects (Symfony 6, 7, 8)
- Added MongoDB section to sidebar menu in
- MongoDB Field Migration Command: New command to generate MongoDB scripts for adding
anonymizedfieldnowo:anonymize:generate-mongo-field: Generate JavaScript scripts (compatible with mongosh) to addanonymizedfield- Supports
--scan-documentsto automatically detect MongoDB document classes with#[Anonymize]attribute - Supports
--collectionoption to manually specify collection names - Supports
--databaseoption to specify target database - Generates scripts that use
updateMany()to addanonymized: falseto existing documents - Output can be saved to file with
--outputoption - Complements the existing SQL migration command (
nowo:anonymize:generate-column-migration) - Documented in
docs/COMMANDS.mdandREADME.md
-
Demo: Enhanced CRUD Navigation: Updated home page in all demo projects to show all available CRUDs
- Added links for Product, Order, Invoice, Employee entities across all SQL connections (MySQL, PostgreSQL, SQLite)
- All CRUD interfaces now accessible from home page
- Better organization of CRUD links by entity type
- Applied to all demo projects (Symfony 6, 7, 8)
-
Demo: MongoDB Scripts: Improved MongoDB fixture scripts
- Updated scripts to use current database connection (already connected via mongosh)
- Better comments explaining script usage
- Applied to all demo projects (Symfony 6, 7, 8)
-
Pattern Matching Enhancement: PatternMatcher now supports multiple values with
|(OR) operator- Allows matching multiple values in a single pattern (e.g.,
'status' => 'inactive|unsubscribed') - Supports SQL LIKE patterns with
%wildcard combined with OR operator - Useful for complex pattern matching scenarios
- Example:
includePatterns: ['email' => '%@test-domain.com|%@example.com|%@demo.local']
- Allows matching multiple values in a single pattern (e.g.,
-
Demo: EmailSubscription Entity: New entity demonstrating comprehensive pattern-based anonymization
- Shows how to anonymize emails based on domain patterns
- Demonstrates conditional anonymization based on status
- Includes ~50 fixture records covering all pattern combinations
- Examples of all pattern types: domain matching, status-based conditions, date conditions
- Applied to all demo projects (Symfony 6, 7, 8)
-
Demo: MongoDB Infrastructure: Added MongoDB support to all demo projects
- MongoDB 7.0 service added to docker-compose.yml in all demos
- Mongo Express added for MongoDB management (ports: 8088/8087/8086)
- MongoDB connection variables (MONGODB_URL) configured
- Entrypoint scripts updated to wait for MongoDB readiness
- Sample document (
UserActivity) prepared for when bundle supports MongoDB ODM - Dockerfiles updated with mongodb-tools
- Healthchecks configured for MongoDB
- MongoDB fixtures script (
load-fixtures.js) loads 30 user activities automatically - MongoDB CRUD interface (
/mongodb/user-activity) for viewing and managing documents anonymizedfield added to MongoDB documents (similar toAnonymizableTraitin ORM entities)- Applied to all demo projects (Symfony 6, 7, 8)
-
Demo: SQLite Support: Added SQLite database support to all demo projects
- SQLite connection configured in doctrine.yaml
- File-based database at
var/data/anonymize_demo.sqlite - pdo_sqlite extension added to Dockerfiles
- Automatic setup in entrypoint scripts
- Same entities and fixtures as MySQL/PostgreSQL
- Applied to all demo projects (Symfony 6, 7, 8)
-
Entity-Level Pattern Filtering: Fixed issue where entity-level
includePatterns/excludePatternswere not applied- Patterns from
#[Anonymize]attribute are now correctly applied before processing records - Ensures entities like
OrderandCustomerfilter records correctly based on entity-level patterns - Example:
Ordernow correctly only processes records withstatus='completed'andid>5
- Patterns from
-
Service Registration: Fixed
CustomReferenceFakerservice registration in demos- Now uses
#[Autoconfigure(public: true)]attribute instead of explicit YAML configuration - More declarative and consistent with bundle patterns
- Applied to all demo projects (Symfony 6, 7, 8)
- Now uses
-
EventDispatcher Injection: Fixed optional EventDispatcher injection compatibility
- Changed from
@?event_dispatcherto full interface name for better compatibility - Prevents configuration loading errors
- Changed from
-
SystemLog Fixtures: Added missing fixtures for
SystemLogentity in all demo projects- Ensures
SystemLogtable exists and has data for anonymization testing - Applied to all demo projects (Symfony 6, 7, 8)
- Ensures
- Demo Coverage: Enhanced demo fixtures with comprehensive test cases
- EmailSubscription fixtures expanded to ~50 records
- Covers all pattern combinations: domain matching, status conditions, with/without backup emails, with/without notes
- All source types represented: website, newsletter, promotion, partner
- Different date ranges for comprehensive testing
-
Enhanced Existing Fakers: Improved IbanFaker, AgeFaker, NameFaker, and SurnameFaker
IbanFaker: AddedvalidandformattedoptionsAgeFaker: Addeddistribution(uniform/normal),mean, andstd_devoptionsNameFaker: Addedgender(male/female/random) andlocale_specificoptionsSurnameFaker: Addedgenderandlocale_specificoptions for API consistency- All improvements backward compatible
-
New Fakers: Added 3 new faker types (Phase 2 - Data Preservation Strategies)
HashPreserveFaker: Deterministic anonymization using hash functions- Maintains referential integrity (same input → same output)
- Options:
algorithm(md5/sha1/sha256/sha512),salt,preserve_format,length - Use cases: When you need to maintain referential integrity
ShuffleFaker: Shuffle values within a column while maintaining distribution- Preserves statistical properties
- Options:
values(required),seed(for reproducibility),exclude - Use cases: When statistical properties must be preserved
ConstantFaker: Replace with constant value- Options:
value(required, can be any type including null) - Use cases: Null out sensitive data or replace with fixed values
- Options:
- All new fakers registered in FakerType enum and FakerFactory
- Total fakers available: 32 (29 from v0.0.12 + 3 new)
- Comprehensive test coverage for all new fakers
-
Pre-flight Checks: Comprehensive validation before anonymization execution
- Database connectivity validation
- Entity existence validation
- Column existence validation
- Faker type and options validation
- Pattern validation (include/exclude)
- Clear error messages for all validation failures
- Integrated in
AnonymizeCommandbefore processing - New
PreFlightCheckServicefor centralized validation
-
Progress Bars: Visual progress indicators for anonymization process
- Real-time progress bars using Symfony Console ProgressBar
- Shows percentage, elapsed time, and estimated time
- Displays current status message
- Updates every 1% of progress
- Option
--no-progressto disable progress bars - Compatible with
--stats-onlymode - Progress callback system in
AnonymizeService
-
Enhanced Environment Protection: Improved safety checks
- New
EnvironmentProtectionServicefor comprehensive environment validation - Validates environment (dev/test only)
- Validates debug mode
- Validates configuration files (detects production config)
- Validates bundle registration in
bundles.php - Clear error messages with actionable guidance
- Integrated in both
AnonymizeCommandandGenerateAnonymizedColumnCommand
- New
-
Debug and Verbose Modes: Enhanced output options
--verbose, -v: Increase verbosity of messages--debug: Enable debug mode with detailed information- Shows detailed entity information in verbose mode
- Shows property details, patterns, and options in debug mode
- Shows pre-flight check information
- Shows total records per table
- Shows property statistics after processing
- Compatible with Symfony Console verbosity system
-
Info Command: New command to display anonymizer information
nowo:anonymize:info: Display information about anonymizers- Shows location of each anonymizer (entity and property)
- Shows configuration (faker type, options, patterns)
- Shows execution order (based on weight)
- Shows statistics about how many records will be anonymized
- Options:
--connection,--locale
-
Event System: Symfony events for extensibility
BeforeAnonymizeEvent: Dispatched before anonymization startsAfterAnonymizeEvent: Dispatched after anonymization completesBeforeEntityAnonymizeEvent: Dispatched before processing each entityAfterEntityAnonymizeEvent: Dispatched after processing each entityAnonymizePropertyEvent: Dispatched before anonymizing each property- Allows listeners to modify anonymized values or skip anonymization
- Supports event listeners and subscribers
- EventDispatcher is optional (works without it)
-
Demo Coverage: Complete faker examples in all demos
- New
SystemLogentity demonstrating all remaining fakers - Demonstrates: password, ip_address, mac_address, uuid, hash, coordinate, color, boolean, numeric, file, json, text, enum, country, language, hash_preserve, shuffle, constant
- All 32 fakers now have examples in demos (100% coverage)
- Updated in all demo projects (Symfony 6, 7, 8)
- New
-
Services Configuration: Optimized
services.yamlfor better maintainability- Removed 32 redundant explicit alias definitions
- Aliases now created automatically from
#[AsAlias]attributes - Fakers without locale parameter use
#[Autoconfigure(public: true)]attribute - Reduced YAML from 89 to 52 lines (35% reduction)
- More declarative configuration in PHP classes
-
Demo Templates: Enhanced conditional display of anonymized column
- Column
anonymizednow displayed conditionally in all list views - Only shown when column exists in database (checked via
SchemaService) - Visual indicators: ✓ Yes (green) for anonymized, ✗ No (gray) for not anonymized
- Updated in all 18 templates across Symfony 6, 7, and 8 demos
- Prevents errors when column doesn't exist
- Column
-
Code Quality: Improved service registration
- Fakers use
#[Autoconfigure(public: true)]instead of YAML configuration - Configuration moved from YAML to PHP attributes (more maintainable)
- Consistent pattern across all fakers
- Fakers use
-
Command Options: Enhanced command-line interface
- Better error messages and warnings
- More informative output in verbose/debug modes
- Improved user experience with progress indicators
-
Safety: Enhanced protection against accidental production execution
- Multiple layers of environment validation
- Configuration file validation
- Clear warnings and error messages
-
Developer Experience: Better debugging and monitoring
- Detailed information in debug mode
- Progress tracking for long-running operations
- Comprehensive validation feedback
-
Tests: Enhanced test coverage for improved fakers
- 216 tests, 512 assertions - All passing
- Comprehensive tests for all enhanced faker options
- New Fakers: Added 15 new faker types (Phase 1 completion - 100%)
- Phase 1 continued (9 fakers):
PasswordFaker,IpAddressFaker,MacAddressFaker,UuidFaker,HashFaker,CoordinateFaker,ColorFaker,BooleanFaker,NumericFaker - Phase 1 final (6 fakers):
FileFaker,JsonFaker,TextFaker,EnumFaker,CountryFaker,LanguageFaker - All new fakers registered in FakerType enum and FakerFactory
- Total fakers available: 29 (8 original + 21 new)
- Phase 1 of roadmap: 100% complete (21/21 fakers implemented)
- Comprehensive test coverage for all new fakers
- Phase 1 continued (9 fakers):
-
EmailFaker: Enhanced with new options
domain: Custom domain optionformat: 'name.surname' or 'random' format optionlocal_part_length: Control local part length- Backward compatible with existing usage
-
PhoneFaker: Enhanced with new options
country_code: Specific country code option (e.g., '+34')format: 'international' or 'national' format optioninclude_extension: Include phone extension option- Backward compatible with existing usage
-
CreditCardFaker: Enhanced with new options
type: 'visa', 'mastercard', 'amex', or 'random' optionvalid: Generate valid Luhn numbers optionformatted: Include spaces/dashes in card number option- Backward compatible with existing usage
-
Tests: Added comprehensive test suites for all new and enhanced fakers
- 187 tests executed
- 435 assertions
- All tests pass
-
Documentation: Updated README, CONFIGURATION, ROADMAP, and UPGRADING guides
- Phase 1 marked as 100% complete
- All new fakers documented
- Enhanced faker options documented
-
Service Registration: Fixed MaskingFaker service registration issue
-
New Fakers: Added 6 new faker types (Phase 1 implementation)
AddressFaker: Generate anonymized street addresses with country, format, and postal code optionsDateFaker: Generate anonymized dates with min/max date, format, and type (past/future/between) optionsUsernameFaker: Generate anonymized usernames with length, prefix, suffix, and number optionsUrlFaker: Generate anonymized URLs with scheme, domain, and path optionsCompanyFaker: Generate anonymized company names with type (corporation/llc/inc) and suffix optionsMaskingFaker: Partial masking of sensitive data with preserve_start, preserve_end, mask_char options- All new fakers registered in FakerType enum and FakerFactory
- Total fakers available: 14 (8 original + 6 new)
-
Demo Enhancements: Added 4 new entities and fixtures
Productentity: Demonstrates name, url, date fakers (10 products)Orderentity: Demonstrates service, address, date, email fakers with patterns (13 orders)Invoiceentity: Demonstrates masking, company, iban, service fakers (8 invoices)Employeeentity: Demonstrates username, date, company fakers with exclusion patterns (12 employees)- All entities include
AnonymizableTraitfor anonymization tracking - Comprehensive fixtures with realistic test data
-
Custom Service Faker: Added example service in demos
CustomReferenceFaker: Example service implementing FakerInterface- Demonstrates how to create custom anonymizers
- Used in Customer and Order entities
- Available in all demo projects (Symfony 6, 7, 8)
- Demo Projects: Synchronized all demo projects (Symfony 6, 7, 8)
- Expanded fixtures: 20 users and 25 customers in all demos
- Added 4 new entities (Product, Order, Invoice, Employee) with fixtures
- Updated controllers to use SchemaService for anonymized column detection
- Updated templates with anonymized column alerts and conditional display
- Added underscore naming strategy to Doctrine configuration
- Updated bundle version to v0.0.11 in all demos
- Added complete CRUD interfaces for all entities (Product, Order, Invoice, Employee)
- Updated navigation menu with all entities organized by categories
- Added anonymization field alerts in all entity list views
- Consistent functionality across all Symfony versions
- Total entities in demos: 6 (User, Customer, Product, Order, Invoice, Employee)
- Total fixtures in demos: 6 (UserFixtures, CustomerFixtures, ProductFixtures, OrderFixtures, InvoiceFixtures, EmployeeFixtures)
- Doctrine DBAL Compatibility: Replaced deprecated
quoteIdentifier()withquoteSingleIdentifier()- Updated
AnonymizeServiceto usequoteSingleIdentifier()(4 occurrences) - Updated
GenerateAnonymizedColumnCommandto usequoteSingleIdentifier()(2 occurrences) - Updated demo controllers to use
quoteSingleIdentifier()(4 occurrences) - Fixes deprecation warnings in Doctrine DBAL 3.x
- Maintains backward compatibility with Doctrine DBAL 2.x
- Updated
-
AnonymizeService: Fixed quote() method to handle integer values
- Convert values to string before quoting in UPDATE queries
- Fixes error when anonymizing entities with integer IDs
- Handles both ID columns and update values correctly
-
Demo PostgreSQL Compatibility: Fixed column name issues
- Added explicit column names for PostgreSQL compatibility
- Added underscore naming strategy to Doctrine configuration
- Ensures consistent column naming across MySQL and PostgreSQL
- Demo Fixtures: Expanded demo data for better testing
- UserFixtures: Increased from 5 to 20 users
- CustomerFixtures: Increased from 8 to 25 customers
- Added edge cases: null optional fields, age limits (18, 100)
- Better demonstration of inclusion/exclusion patterns
- More diverse data scenarios for comprehensive testing
- GitHub Release Workflow: Fixed release creation to mark as latest
- Added
make_latest: !isPrereleaseparameter tocreateReleasecall - New releases are now automatically marked as latest
- Ensures consistency between release creation and update workflows
- Added
- Documentation: Enhanced upgrade guide
- Added complete upgrade instructions for v0.0.7
- Updated compatibility table with all versions
- Improved documentation consistency
- SchemaService: New service for checking database schema information
hasAnonymizedColumn()method to check if anonymized column existshasColumn()generic method to check any column existence- Service is autowired and available for dependency injection
- Comprehensive test coverage with 8 test cases
- Demo Controllers: Refactored to use SchemaService
- Removed duplicate
hasAnonymizedColumn()method from controllers - Controllers now inject SchemaService via dependency injection
- Improved code organization and reusability
- Removed duplicate
- Demo Templates: All texts translated to English
- Alert messages now in English
- Consistent language across all demo templates
- Documentation: Enhanced demo README with anonymized column tracking
- Added information about
AnonymizableTrait - Added instructions for generating migrations
- Complete documentation of anonymized column feature
- Added information about
- Symfony 8 Compatibility: Fixed doctrine-bundle version constraint
- Updated
doctrine/doctrine-bundleconstraint from^2.8to^2.8 || ^3.0 - Symfony 8 requires doctrine-bundle 3.x
- Maintains backward compatibility with Symfony 6/7 (doctrine-bundle 2.x)
- Demo projects updated to handle missing
anonymizedcolumn gracefully - Controllers now check column existence before using it to prevent SQL errors
- Updated
-
Doctrine Bundle Compatibility: Improved compatibility with Symfony 8
- Updated
doctrine/doctrine-bundleconstraint from^2.15to^2.8 - Allows broader compatibility across Symfony 6, 7, and 8
- Symfony Flex can now resolve compatible versions automatically
- Updated
-
Demo Projects: Updated demo configurations
- Symfony 8 demo now uses
dev-mainfor bundle development - Improved dependency resolution for Symfony 8 compatibility
- Removed explicit constraints that conflicted with Symfony 8
- Symfony 8 demo now uses
- Anonymized Column Tracking: Added functionality to track anonymization status in database
AnonymizableTrait: Trait that adds ananonymizedboolean field to entitiesnowo:anonymize:generate-column-migrationcommand: Generates SQL migrations to add theanonymizedcolumnAnonymizeService: Automatically setsanonymized = truewhen a record is anonymized- Automatic column detection: Checks if the
anonymizedcolumn exists before updating - Demo examples: All demo entities (User, Customer) now use
AnonymizableTrait
- AnonymizeService: Enhanced to detect and update
anonymizedcolumn- Checks if entity uses
AnonymizableTraitbefore setting the flag - Verifies column existence in database schema before updating
- Sets
anonymized = trueautomatically during anonymization process
- Checks if entity uses
-
Comprehensive Test Suite: Added unit tests for all Faker classes and services
- Tests for EmailFaker, NameFaker, SurnameFaker, PhoneFaker, IbanFaker, CreditCardFaker
- Tests for FakerFactory with all faker types
- Tests for ServiceFaker with different service implementations
- Comprehensive tests for PatternMatcher with all operators
- Total: 51 tests with 119 assertions
-
Faker Services: Registered all fakers as Symfony services
- All fakers are now singleton services with locale injection
- Fakers can be injected directly where needed
- Better integration with Symfony dependency injection
-
Service Aliases: Added
#[AsAlias]attributes to all faker classes- Modern Symfony 6.3+ approach for service aliases
- Aliases defined directly in classes
- Cleaner services.yaml configuration
-
Demo Projects: Added WebProfilerBundle to all demo projects
- Symfony WebProfilerBundle for development debugging
- Available in dev and test environments
-
ContainerInterface Usage: Unified to PSR-11 standard
- All services now use
Psr\Container\ContainerInterface - Removed Symfony-specific ContainerInterface usage
- More portable and standard-compliant
- All services now use
-
FakerFactory: Updated to use services from container
- Tries to get fakers from service container first
- Falls back to direct instantiation if container is not available
- Uses alias IDs defined via
#[AsAlias]attributes
- ServiceFaker Autowiring: Fixed autowiring error for ServiceFaker
- Added
#[Exclude]attribute to prevent automatic service registration - ServiceFaker is created dynamically by FakerFactory
- Excluded from services.yaml resource registration
- Added
- Autowiring Configuration: Fixed ContainerInterface autowiring issue
- Added alias for
Symfony\Component\DependencyInjection\ContainerInterfaceto@service_container - Added alias for
Psr\Container\ContainerInterfaceto@service_container - Optimized services configuration to use autowiring whenever possible
- Removed manual service configuration in favor of autowiring
- Added alias for
- Services Configuration: Optimized
services.yamlto maximize autowiring- Simplified service definitions
- Removed unnecessary manual configurations
- All services now use autowiring by default
-
Initial Release: Complete database anonymization functionality for Symfony
- Attribute-based entity and property configuration (
#[Anonymize]and#[AnonymizeProperty]) - Automatic entity discovery across multiple Doctrine connections
- Support for multiple database types (MySQL, PostgreSQL)
- Comprehensive Faker integration with custom types
- Weight-based processing order
- Pattern matching for selective anonymization
- Statistics collection and reporting
- Dry-run mode for safe testing
- Development-only bundle with built-in environment protection
- Attribute-based entity and property configuration (
-
Bundle Structure:
Nowo\AnonymizeBundlenamespace- Dependency injection configuration
- Service definitions with autowiring
- Console command for anonymization
- Symfony Flex recipe for automatic setup
-
Attributes:
#[Anonymize]- Mark entities for anonymization#[AnonymizeProperty]- Configure property anonymization with type, weight, and patterns
-
Faker Types:
EmailFaker- Generate anonymized email addressesNameFaker- Generate anonymized first namesSurnameFaker- Generate anonymized last namesAgeFaker- Generate anonymized ages with configurable rangesPhoneFaker- Generate anonymized phone numbersIbanFaker- Generate anonymized IBAN codesCreditCardFaker- Generate anonymized credit card numbersServiceFaker- Use custom services for anonymization
-
Services:
AnonymizeService- Core anonymization logicPatternMatcher- Pattern matching for inclusion/exclusionFakerFactory- Factory for creating faker instancesAnonymizeStatistics- Statistics collection and reporting
-
Commands:
nowo:anonymize:run- Main anonymization command with options:--connection- Process specific connections--dry-run- Test mode without making changes--batch-size- Configure batch processing size--locale- Set Faker locale--stats-json- Export statistics to JSON--stats-only- Show only statistics summary
-
Security Features:
- Built-in environment validation (dev/test only)
- Automatic command failure in production environments
- Configuration file created in
config/packages/dev/by default
-
Demo Projects: Created three independent demo projects for different Symfony versions
symfony6- Demo with Symfony 6.1+, MySQL and PostgreSQL connectionssymfony7- Demo with Symfony 7.0, MySQL and PostgreSQL connectionssymfony8- Demo with Symfony 8.0, MySQL and PostgreSQL connections- Each demo includes:
- Docker Compose with both database types (MySQL and PostgreSQL)
- Complete Symfony setup with Nginx and PHP-FPM
- Example entities (User, Customer) with anonymization attributes
- CRUD interfaces for managing entities
- DoctrineFixturesBundle for loading sample data
- phpMyAdmin and pgAdmin for database visualization
- Makefile for easy management
- Comprehensive documentation
-
Development Tools:
- Docker setup for development
- Makefile with common development commands
- PHP-CS-Fixer configuration (PSR-12)
- PHPUnit configuration with coverage
- GitHub Actions CI/CD workflows (ci.yml, release.yml, sync-releases.yml)
-
Documentation:
- Comprehensive README.md with usage examples
- INSTALLATION.md guide
- CONFIGURATION.md guide
- CHANGELOG.md (this file)
- UPGRADING.md guide
- PHP Doc comments in English for all classes, methods, and properties
- Demo project documentation
- N/A - Initial release
- N/A - Initial release
- N/A - Initial release
- N/A - Initial release
- Development-Only Bundle: Bundle is restricted to dev/test environments only
- Command automatically fails if executed in production
- Bundle registration restricted to dev/test in Symfony Flex recipe
- Configuration file created in
config/packages/dev/by default - All documentation includes security warnings