{"id":21236035,"url":"https://github.com/nette-examples/di-example-newsletter","last_synced_at":"2025-07-10T17:31:57.891Z","repository":{"id":28440912,"uuid":"31956134","full_name":"nette-examples/di-example-newsletter","owner":"nette-examples","description":"Dependency Injection Container example","archived":false,"fork":false,"pushed_at":"2024-02-12T19:32:45.000Z","size":7,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-05T15:51:10.444Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nette-examples.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-03-10T12:28:30.000Z","updated_at":"2023-10-14T08:30:13.000Z","dependencies_parsed_at":"2022-07-16T17:46:48.977Z","dependency_job_id":null,"html_url":"https://github.com/nette-examples/di-example-newsletter","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/nette-examples/di-example-newsletter","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nette-examples%2Fdi-example-newsletter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nette-examples%2Fdi-example-newsletter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nette-examples%2Fdi-example-newsletter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nette-examples%2Fdi-example-newsletter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nette-examples","download_url":"https://codeload.github.com/nette-examples/di-example-newsletter/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nette-examples%2Fdi-example-newsletter/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264619136,"owners_count":23638414,"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":[],"created_at":"2024-11-21T00:05:54.359Z","updated_at":"2025-07-10T17:31:55.785Z","avatar_url":"https://github.com/nette-examples.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"Example of using Nette DI Container\n===================================\n\nThe essence of Dependency Injection (DI) is to unburden classes from creating objects they rely on. Such objects are termed **services**. Further details can be found on the [official website](https://doc.nette.org/dependency-injection).\n\n\nInstallation\n------------\n\nTo get started:\n\n```shell\ngit clone https://github.com/nette-examples/di-example-newsletter\ncd di-example-newsletter\ncomposer install\n```\n\nRun the Demo\n------------\n\nExecute the demo via:\n\n```shell\nphp example.php\n```\n\nPHP Requirements\n----------------\n\nEnsure your environment runs PHP version 8.1.\n\n\nUsing the Application\n---------------------\n\nConsider an application designed for newsletter distribution:\n\nThe `Mail` class represents an email:\n\n```php\nclass Mail\n{\n\tpublic string $subject;\n\tpublic string $message;\n}\n```\n\nThe `Mailer` interface defines email sending:\n\n```php\ninterface Mailer\n{\n\tfunction send(Mail $mail, string $to): void;\n}\n```\n\nThe `Logger` interface provides logging capabilities:\n\n```php\ninterface Logger\n{\n\tfunction log(string $message): void;\n}\n```\n\nThe `NewsletterManager` class manages newsletter distribution:\n\n```php\nclass NewsletterManager\n{\n\tprivate Mailer $mailer;\n\tprivate Logger $logger;\n\n\tpublic function __construct(Mailer $mailer, Logger $logger)\n\t{\n\t\t$this-\u003emailer = $mailer;\n\t\t$this-\u003elogger = $logger;\n\t}\n\n\tpublic function distribute(array $recipients): void\n\t{\n\t\t$mail = new Mail;\n\t\t$mail-\u003esubject = '...';\n\t\t$mail-\u003emessage = '...';\n\n\t\tforeach ($recipients as $recipient) {\n\t\t\t$this-\u003emailer-\u003esend($mail, $recipient);\n\t\t}\n\t\t$this-\u003elogger-\u003elog('...');\n\t}\n}\n```\n\nThe code respects Dependency Injection, ie. **each object uses only variables which we had passed into it.**\n\nAlso, we have a ability to implement own `Logger` or `Mailer`, like this:\n\n```php\nclass SendMailMailer implements Mailer\n{\n\tpublic function send(Mail $mail, string $to): void\n\t{\n\t\tmail($to, $mail-\u003esubject, $mail-\u003emessage);\n\t}\n}\n\nclass FileLogger implements Logger\n{\n\tprivate string $file;\n\n\tpublic function __construct(string $file)\n\t{\n\t\t$this-\u003efile = $file;\n\t}\n\n\tpublic function log(string $message): void\n\t{\n\t\tfile_put_contents($this-\u003efile, $message . \"\\n\", FILE_APPEND);\n\t}\n}\n```\n\n**DI container is the central orchestrator** that can instantiate individual objects (referred to as services in DI terminology) and configure them as required.\n\nAn example container for our application:\n\n```php\nclass Container\n{\n\tprivate ?Logger $logger;\n\tprivate ?Mailer $mailer;\n\n\tpublic function getLogger(): Logger\n\t{\n\t\tif (!isset($this-\u003elogger)) {\n\t\t\t$this-\u003elogger = new FileLogger('log.txt');\n\t\t}\n\t\treturn $this-\u003elogger;\n\t}\n\n\tpublic function getMailer(): Mailer\n\t{\n\t\tif (!isset($this-\u003emailer)) {\n\t\t\t$this-\u003emailer = new SendMailMailer;\n\t\t}\n\t\treturn $this-\u003emailer;\n\t}\n\n\tpublic function createNewsletterManager(): NewsletterManager\n\t{\n\t\treturn new NewsletterManager($this-\u003egetMailer(), $this-\u003egetLogger());\n\t}\n}\n```\n\nThe key advantage of DI is that no class is directly dependent on the container, enabling easy substitution with another container, like one generated by Nette DI.\n\nLet's instantiate `Container`, let it create manager and we can start spamming users with newsletters :-)\n\n```php\n$container = new Container;\n$manager = $container-\u003ecreateNewsletterManager();\n$manager-\u003edistribute(...);\n```\n\nSignificant to Dependency Injection is that no class depends on the container. Thus it can be easily replaced with another one. For example with the container generated by Nette DI.\n\n\nIntroduction to Nette DI\n------------------------\n\nNette DI acts as a dynamic container generator, primarily utilizing configuration files to shape its behavior. The configuration shown below exemplifies a structure similar to the manually defined `Container` class:\n\n```neon\nservices:\n\t- FileLogger( log.txt )\n\t- SendMailMailer\n\t- NewsletterManager\n```\n\nA standout feature of Nette DI is the succinctness of its configuration syntax.\n\nOne of the pivotal aspects of Nette DI is its ability to generate the actual PHP code for the container. This ensures not just high performance but also transparency, allowing developers to delve into the generated code for clarity and debugging purposes.\n\nSetting up and using Nette DI is intuitive:\n\n```php\n$loader = new Nette\\DI\\ContainerLoader(__DIR__ . '/temp');\n$class = $loader-\u003eload(function($compiler) {\n    $compiler-\u003eloadConfig(__DIR__ . '/config.neon');\n});\n$container = new $class;\n```\n\nOnce the container is set up, it's easy to instantiate services like the `NewsletterManager` and perform actions, such as sending out emails:\n\n```php\n$manager = $container-\u003egetByType(NewsletterManager::class);\n$manager-\u003edistribute(['john@example.com', ...]);\n```\n\nFor efficiency, the container is generated just once, with the resultant code cached in the specified directory (`__DIR__ . '/temp'`). The configuration file is thus loaded inside the closure passed to `$loader-\u003eload()`, ensuring it's invoked a singular time.\n\nTo enhance the development experience, Nette DI offers an auto-refresh mode. When enabled, it detects and incorporates changes from any modified class or configuration file. This feature can be activated by passing `true` as the second argument during `ContainerLoader` instantiation:\n\n```php\n$loader = new Nette\\DI\\ContainerLoader(__DIR__ . '/temp', autoRebuild: true);\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnette-examples%2Fdi-example-newsletter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnette-examples%2Fdi-example-newsletter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnette-examples%2Fdi-example-newsletter/lists"}