{"id":23590936,"url":"https://github.com/cmatosbc/ananke","last_synced_at":"2025-05-07T16:20:58.534Z","repository":{"id":269344587,"uuid":"907119524","full_name":"cmatosbc/ananke","owner":"cmatosbc","description":"A flexible PHP service container that supports conditional service instantiation, relying on PHP 8+ match expression and generators.","archived":false,"fork":false,"pushed_at":"2025-01-02T11:22:29.000Z","size":69,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-31T11:51:08.253Z","etag":null,"topics":["php-conditional-instances","php-containers","php-custom","php-design-patterns","php-generators","php-library","php-match","php-modern","php-service-container","php8","singleton-pattern"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cmatosbc.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-12-22T21:28:55.000Z","updated_at":"2025-01-05T20:39:59.000Z","dependencies_parsed_at":"2024-12-22T22:24:36.406Z","dependency_job_id":"34430c3f-4dc9-4aa1-b324-f5dee3da812e","html_url":"https://github.com/cmatosbc/ananke","commit_stats":null,"previous_names":["cmatosbc/ananke"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cmatosbc%2Fananke","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cmatosbc%2Fananke/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cmatosbc%2Fananke/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cmatosbc%2Fananke/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cmatosbc","download_url":"https://codeload.github.com/cmatosbc/ananke/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252913052,"owners_count":21824092,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["php-conditional-instances","php-containers","php-custom","php-design-patterns","php-generators","php-library","php-match","php-modern","php-service-container","php8","singleton-pattern"],"created_at":"2024-12-27T07:17:01.459Z","updated_at":"2025-05-07T16:20:58.523Z","avatar_url":"https://github.com/cmatosbc.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Ananke\n\n[![PHP Lint](https://github.com/cmatosbc/ananke/actions/workflows/lint.yml/badge.svg)](https://github.com/cmatosbc/ananke/actions/workflows/lint.yml) [![PHPUnit Tests](https://github.com/cmatosbc/ananke/actions/workflows/phpunit.yml/badge.svg)](https://github.com/cmatosbc/ananke/actions/workflows/phpunit.yml) [![PHP Composer](https://github.com/cmatosbc/ananke/actions/workflows/composer.yml/badge.svg)](https://github.com/cmatosbc/ananke/actions/workflows/composer.yml) [![Latest Stable Version](https://poser.pugx.org/cmatosbc/ananke/v)](https://packagist.org/packages/cmatosbc/ananke) [![License](https://poser.pugx.org/cmatosbc/ananke/license)](https://packagist.org/packages/cmatosbc/ananke)\n\nA flexible PHP 8+ service container that supports conditional service instantiation. This package allows you to register services with multiple conditions that must be met before the service can be instantiated.\n\n## Requirements\n\n- PHP 8.0 or higher\n\n## Features\n\n- Register services with their class names and constructor parameters\n- Define conditions as callable functions\n- Associate multiple conditions with services\n- Dynamic service instantiation based on condition evaluation\n- Clear error handling with specific exceptions\n\n## Installation\n\n```bash\ncomposer require cmatosbc/ananke\n```\n\n## Basic Usage\n\n```php\nuse Ananke\\ServiceFactory;\n\n$factory = new ServiceFactory();\n\n// Register a service with constructor parameters\n$factory-\u003eregister('logger', Logger::class, ['debug']);\n\n// Register conditions\n$factory-\u003eregisterCondition('is-development', fn() =\u003e getenv('APP_ENV') === 'development');\n$factory-\u003eregisterCondition('has-permissions', fn() =\u003e is_writable('/var/log'));\n\n// Associate multiple conditions with service\n$factory-\u003eassociateCondition('logger', 'is-development');\n$factory-\u003eassociateCondition('logger', 'has-permissions');\n\n// Create service (only works if ALL conditions are met)\nif ($factory-\u003ehas('logger')) {\n    $logger = $factory-\u003ecreate('logger');\n}\n```\n\n## Multiple Conditions\n\nServices can have multiple conditions that must ALL be satisfied before instantiation:\n\n```php\n// Premium feature example\n$factory-\u003eregister('premium.feature', PremiumFeature::class);\n\n// Register all required conditions\n$factory-\u003eregisterCondition('is-premium-user', fn() =\u003e $user-\u003ehasPremiumSubscription());\n$factory-\u003eregisterCondition('feature-enabled', fn() =\u003e $featureFlags-\u003eisEnabled('new-feature'));\n$factory-\u003eregisterCondition('has-valid-license', fn() =\u003e $license-\u003eisValid());\n\n// Associate ALL conditions with the service\n$factory-\u003eassociateCondition('premium.feature', 'is-premium-user');\n$factory-\u003eassociateCondition('premium.feature', 'feature-enabled');\n$factory-\u003eassociateCondition('premium.feature', 'has-valid-license');\n\n// Service will only be created if ALL conditions are met\nif ($factory-\u003ehas('premium.feature')) {\n    $feature = $factory-\u003ecreate('premium.feature');\n}\n```\n\n## Condition Decorators\n\nAnanke provides a powerful set of condition decorators that allow you to compose complex condition logic:\n\n### Not Condition\n\nNegate any condition:\n\n```php\nuse Ananke\\Conditions\\{NotCondition, CallableCondition};\n\n// Basic condition\n$factory-\u003eregisterCondition('is-maintenance', \n    new CallableCondition('is-maintenance', fn() =\u003e $maintenance-\u003eisActive()));\n\n// Negate it\n$factory-\u003eregisterCondition('not-maintenance',\n    new NotCondition($factory-\u003egetCondition('is-maintenance')));\n\n// Use in service\n$factory-\u003eregister('api', APIService::class);\n$factory-\u003eassociateCondition('api', 'not-maintenance');\n```\n\n### Cached Condition\n\nCache expensive condition evaluations:\n\n```php\nuse Ananke\\Conditions\\CachedCondition;\n\n// Cache an expensive API check for 1 hour\n$factory-\u003eregisterCondition('api-status',\n    new CachedCondition(\n        new CallableCondition('api-check', fn() =\u003e $api-\u003echeckStatus()),\n        3600 // Cache for 1 hour\n    ));\n```\n\n### AND/OR Conditions\n\nCombine multiple conditions with logical operators:\n\n```php\nuse Ananke\\Conditions\\{AndCondition, OrCondition};\n\n// Premium access: User must be premium OR have a trial subscription\n$factory-\u003eregisterCondition('can-access-premium',\n    new OrCondition([\n        new CallableCondition('is-premium', fn() =\u003e $user-\u003eisPremium()),\n        new CallableCondition('has-trial', fn() =\u003e $user-\u003ehasTrial())\n    ]));\n\n// Database write: Need both connection AND proper permissions\n$factory-\u003eregisterCondition('can-write-db',\n    new AndCondition([\n        new CallableCondition('is-connected', fn() =\u003e $db-\u003eisConnected()),\n        new CallableCondition('has-permissions', fn() =\u003e $user-\u003ecanWrite())\n    ]));\n```\n\n### XOR/NOR Conditions\n\nFor more complex logical operations, you can use XOR (exclusive OR) and NOR conditions:\n\n```php\nuse Ananke\\Conditions\\{XorCondition, NorCondition};\n\n// XOR: Feature must be enabled in EXACTLY one environment (dev XOR prod)\n$factory-\u003eregisterCondition('feature-enabled-single-env',\n    new XorCondition([\n        new CallableCondition('dev-enabled', fn() =\u003e $featureFlags-\u003eisEnabled('dev')),\n        new CallableCondition('prod-enabled', fn() =\u003e $featureFlags-\u003eisEnabled('prod'))\n    ]));\n\n// NOR: Service is available only when NONE of the maintenance modes are active\n$factory-\u003eregisterCondition('all-systems-available',\n    new NorCondition([\n        new CallableCondition('db-maintenance', fn() =\u003e $maintenance-\u003eisDatabaseMaintenance()),\n        new CallableCondition('api-maintenance', fn() =\u003e $maintenance-\u003eisApiMaintenance()),\n        new CallableCondition('ui-maintenance', fn() =\u003e $maintenance-\u003eisUiMaintenance())\n    ]));\n```\n\n### Complex Condition Compositions\n\nCombine decorators for complex logic:\n\n```php\n// ((isPremium OR hasTrial) AND notMaintenance) AND (hasQuota OR isUnlimited)\n$factory-\u003eregisterCondition('can-use-service',\n    new AndCondition([\n        // Premium access check\n        new OrCondition([\n            new CallableCondition('premium', fn() =\u003e $user-\u003eisPremium()),\n            new CallableCondition('trial', fn() =\u003e $user-\u003ehasTrial())\n        ]),\n        // Not in maintenance\n        new NotCondition(\n            new CallableCondition('maintenance', fn() =\u003e $maintenance-\u003eisActive())\n        ),\n        // Resource availability\n        new OrCondition([\n            new CallableCondition('has-quota', fn() =\u003e $user-\u003ehasQuota()),\n            new CallableCondition('unlimited', fn() =\u003e $user-\u003eisUnlimited())\n        ])\n    ])\n);\n\n// Cache the entire complex condition\n$factory-\u003eregisterCondition('cached-access-check',\n    new CachedCondition(\n        $factory-\u003egetCondition('can-use-service'),\n        300 // Cache for 5 minutes\n    )\n);\n```\n\n## Service Types\n\nAnanke supports two types of service instantiation: Singleton and Prototype.\n\n### Singleton Services\n\nSingleton services are instantiated only once and the same instance is returned for subsequent requests. This is useful for services that maintain state or are resource-intensive to create.\n\n```php\nuse Ananke\\ServiceFactory;\n\n$factory = new ServiceFactory();\n\n// Register a service as singleton\n$factory-\u003eregister('database', DatabaseConnection::class);\n$factory-\u003eregisterAsSingleton('database');\n\n// Both variables will reference the same instance\n$db1 = $factory-\u003ecreate('database');\n$db2 = $factory-\u003ecreate('database');\n\nassert($db1 === $db2); // true\n```\n\nYou can also clear singleton instances when needed:\n\n```php\n// Clear all singleton instances\n$factory-\u003eclearSingletons();\n\n// Now you'll get a new instance\n$db3 = $factory-\u003ecreate('database');\nassert($db3 !== $db1); // true\n```\n\n### Prototype Services\n\nPrototype services create a new instance every time they are requested. This is the default behavior and is ideal for services that should not share state.\n\n```php\nuse Ananke\\ServiceFactory;\n\n$factory = new ServiceFactory();\n\n// Register a service (prototype by default)\n$factory-\u003eregister('transaction', Transaction::class);\n\n// Or explicitly register as prototype\n$factory-\u003eregisterAsPrototype('transaction');\n\n// Each call creates a new instance\n$tx1 = $factory-\u003ecreate('transaction');\n$tx2 = $factory-\u003ecreate('transaction');\n\nassert($tx1 !== $tx2); // true\n```\n\n### Changing Service Types\n\nYou can change a service's type after registration:\n\n```php\nuse Ananke\\ServiceFactory;\n\n$factory = new ServiceFactory();\n$factory-\u003eregister('cache', CacheService::class);\n\n// Start as singleton\n$factory-\u003echangeServiceType('cache', 'singleton');\n$cache1 = $factory-\u003ecreate('cache');\n$cache2 = $factory-\u003ecreate('cache');\nassert($cache1 === $cache2); // true\n\n// Switch to prototype\n$factory-\u003echangeServiceType('cache', 'prototype');\n$cache3 = $factory-\u003ecreate('cache');\n$cache4 = $factory-\u003ecreate('cache');\nassert($cache3 !== $cache4); // true\n```\n\n## Best Practices\n\n1. **Caching**: Use `CachedCondition` for:\n   - External API calls\n   - Database queries\n   - File system checks\n   - Any expensive operations\n\n2. **Composition**: Build complex conditions gradually:\n   - Start with simple conditions\n   - Combine them using AND/OR\n   - Add negation where needed\n   - Cache at appropriate levels\n\n3. **Naming**: Use clear, descriptive names:\n   - Negated: prefix with 'not-'\n   - Cached: prefix with 'cached-'\n   - Combined: use descriptive action names\n\n4. **Testing**: Test complex conditions thoroughly:\n   - Verify each sub-condition\n   - Test boundary cases\n   - Ensure proper short-circuit evaluation\n   - Validate cache behavior\n\n## Real-World Use Cases\n\n### 1. Environment-Specific Services\n\nControl debug tools based on environment:\n\n```php\n$factory-\u003eregister('debugger', Debugger::class);\n$factory-\u003eregisterCondition('is-development', fn() =\u003e getenv('APP_ENV') === 'development');\n$factory-\u003eregisterCondition('debug-enabled', fn() =\u003e getenv('APP_DEBUG') === 'true');\n$factory-\u003eassociateCondition('debugger', 'is-development');\n$factory-\u003eassociateCondition('debugger', 'debug-enabled');\n```\n\n### 2. Feature Flags and A/B Testing\n\nImplement feature toggles with multiple conditions:\n\n```php\n$factory-\u003eregister('new.ui', NewUIComponent::class);\n$factory-\u003eregisterCondition('feature-enabled', fn() =\u003e $featureFlags-\u003eisEnabled('new-ui'));\n$factory-\u003eregisterCondition('in-test-group', fn() =\u003e $abTest-\u003eisInGroup('new-ui-test'));\n$factory-\u003eregisterCondition('supported-browser', fn() =\u003e $browser-\u003esupportsFeature('grid-layout'));\n$factory-\u003eassociateCondition('new.ui', 'feature-enabled');\n$factory-\u003eassociateCondition('new.ui', 'in-test-group');\n$factory-\u003eassociateCondition('new.ui', 'supported-browser');\n```\n\n### 3. Database Connection Management\n\nSafe handling of database-dependent services:\n\n```php\n$factory-\u003eregister('user.repository', UserRepository::class);\n$factory-\u003eregisterCondition('db-connected', fn() =\u003e $database-\u003eisConnected());\n$factory-\u003eregisterCondition('db-migrated', fn() =\u003e $database-\u003eisMigrated());\n$factory-\u003eregisterCondition('has-permissions', fn() =\u003e $database-\u003ehasPermissions('users'));\n$factory-\u003eassociateCondition('user.repository', 'db-connected');\n$factory-\u003eassociateCondition('user.repository', 'db-migrated');\n$factory-\u003eassociateCondition('user.repository', 'has-permissions');\n```\n\n### 4. License-Based Feature Access\n\nControl access to premium features:\n\n```php\n$factory-\u003eregister('premium.api', PremiumAPIClient::class);\n$factory-\u003eregisterCondition('has-license', fn() =\u003e $license-\u003eisValid());\n$factory-\u003eregisterCondition('within-quota', fn() =\u003e $usage-\u003eisWithinQuota());\n$factory-\u003eregisterCondition('api-available', fn() =\u003e $api-\u003eisAvailable());\n$factory-\u003eassociateCondition('premium.api', 'has-license');\n$factory-\u003eassociateCondition('premium.api', 'within-quota');\n$factory-\u003eassociateCondition('premium.api', 'api-available');\n```\n\n## Error Handling\n\nThe service container throws specific exceptions:\n\n- `ServiceNotFoundException`: When trying to create a non-registered service\n- `ClassNotFoundException`: When registering a service with a non-existent class\n- `InvalidArgumentException`: When a condition is not met or invalid\n\n## Testing\n\nRun the test suite:\n\n```bash\ncomposer test\n```\n\nThe tests provide detailed output showing the state of conditions and service creation:\n\n```\n🧪 Test: Multiple Conditions\n    ✅ Registered premium feature service\n    ✅ Registered all conditions\n    \n    📊 Current State:\n       • Premium Status: ✅\n       • Feature Flag: ✅\n       • Valid License: ❌\n    ℹ️  Testing with incomplete conditions\n    ✅ Verified feature is not available\n```\n\n## Contributing\n\nContributions are welcome! Please feel free to submit a Pull Request.\n\n## License\n\nThis project is licensed under the GPL-3.0-or-later License - see the LICENSE file for details.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcmatosbc%2Fananke","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcmatosbc%2Fananke","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcmatosbc%2Fananke/lists"}