{"id":18773110,"url":"https://github.com/webfactory/webfactorynewsletterregistrationbundle","last_synced_at":"2025-04-13T09:07:00.338Z","repository":{"id":44872394,"uuid":"287051549","full_name":"webfactory/WebfactoryNewsletterRegistrationBundle","owner":"webfactory","description":null,"archived":false,"fork":false,"pushed_at":"2025-01-27T12:07:12.000Z","size":162,"stargazers_count":3,"open_issues_count":2,"forks_count":1,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-04-13T09:06:47.130Z","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/webfactory.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-08-12T15:35:58.000Z","updated_at":"2025-01-27T12:07:16.000Z","dependencies_parsed_at":"2024-08-26T11:14:02.342Z","dependency_job_id":"5006dde1-a1bc-4ea1-bd10-002784e90297","html_url":"https://github.com/webfactory/WebfactoryNewsletterRegistrationBundle","commit_stats":{"total_commits":101,"total_committers":7,"mean_commits":"14.428571428571429","dds":"0.18811881188118806","last_synced_commit":"ca7652e27854f725e602f7a108522e7bd5a7790b"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webfactory%2FWebfactoryNewsletterRegistrationBundle","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webfactory%2FWebfactoryNewsletterRegistrationBundle/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webfactory%2FWebfactoryNewsletterRegistrationBundle/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webfactory%2FWebfactoryNewsletterRegistrationBundle/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/webfactory","download_url":"https://codeload.github.com/webfactory/WebfactoryNewsletterRegistrationBundle/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248688569,"owners_count":21145766,"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-07T19:32:48.228Z","updated_at":"2025-04-13T09:07:00.320Z","avatar_url":"https://github.com/webfactory.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"WebfactoryNewsletterRegistrationBundle\n======================================\n\n![](https://github.com/webfactory/WebfactoryNewsletterRegistrationBundle/workflows/Tests/badge.svg)\n![](https://github.com/webfactory/WebfactoryNewsletterRegistrationBundle/workflows/Dependencies/badge.svg)\n![](https://github.com/webfactory/WebfactoryNewsletterRegistrationBundle/workflows/Coding%20Standards/badge.svg)\n\nThis Symfony bundle features a newsletter registration template with attention to data avoidance for privacy\nprotection:\n\n- Sign up with email address only (which is also a low barrier for a better interaction rate)\n- No personal data (like the email address) is saved until the newsletter recipient verifies their email address (double opt in)\n- Pending opt in processes get deleted after a configurable amount of time (default: 72 hours)\n- Intentionally vague messages to prevent leaking user meta information (e.g. if some email address is registered)\n\nTo reduce the amount of unwanted emails, the following ideas are implemented:\n\n- The registration form has a simple honeypot field\n- Opt in emails contain no data entered in the registration form to make them unattractive for spammers\n- Opt in emails can be sent only once in a configurable time interval (default: 1 hour)\n- Opt in emails contain a \"block this email address\" link (default: for 30 days)\n\nFinally, the bundle tries to be developer friendly:\n\n- Registration can be embedded as a page on it's own as well as a partial view\n- Depending on the number of different newsletters, the registration and edit forms feature a newsletter selection or\n  no disturbing element (a checkbox for a single newsletter would be silly) \n- It's highly customizable due to small interfaces, Doctrine interface mapping and service replacements\n\n\nInstallation\n------------\n\n    composer req webfactory/newsletter-registration-bundle\n    \nactivate in `src/bundles.php`:\n\n```php\n\u003c?php\n\nreturn [\n    // ...\n    Webfactory\\NewsletterRegistrationBundle\\WebfactoryNewsletterRegistrationBundle::class =\u003e ['all' =\u003e true],\n];\n```\n\nImplement all `src/Entity/*Interface.php` in your project. The easiest way, if you don't mind the biased namespaces, is\nto copy the templates:\n\n    mkdir src/AppBundle/Newsletter\n    cp vendor/webfactory/newsletter-registration-bundle/app-class-templates/* src/AppBundle/Newsletter/*\n\nIf you want to implement the interfaces by yourself, you could extend the corresponding abstract classes like in the\ntemplates above and add class level Doctrine ORM annotations (find template for them in the abstract classes). For\ncustomizing, see the \"Customizing\" section below.\n\nIn either case, configure Doctrine's interface mapping to deal with your custom entity class:\n\n```yaml\n// config.yml\n\ndoctrine:\n    orm:\n        resolve_target_entities:\n            \\Webfactory\\NewsletterRegistrationBundle\\Entity\\NewsletterInterface: '\\AppBundle\\Entity\\Newsletter'\n```\n\nSide node: The templates and example above assume that you want to keep your Newsletter classes inside a Newsletter\ndirectory in your AppBundle. If you choose to do so, you might need to configure Doctrine to load the entities: \n\n```yaml\n// config.yml\n\ndoctrine:\n    orm:\n        entity_managers:\n            default:\n                mappings:\n                    NewsletterRegistrationBundle:\n                        type: annotation\n                        prefix: AppBundle\\Newsletter\\Entity\\\n                        dir: \"%kernel.root_dir%/AppBundle/Newsletter/Entity/\"\n                        is_bundle: false\n```\n\nUpdate your database schema, e.g. with a migration.\n\nConfigure the bundle:\n\n```yaml\n// config.yml\n\nparameters:\n  webfactory.newsletter_registration.email_sender_address: 'newsletter@example.com'\n  webfactory.newsletter_registration.secret: 'your-secret' # do not use Symfony's %secret%!\n  webfactory.newsletter_registration.time_limit_for_opt_in_in_hours: 72 # default value\n  webfactory.newsletter_registration.minimal_interval_between_op_in_emails_in_hours: 1 # default value\n  webfactory.newsletter_registration.block_email_address_duration_in_days: 30 # default value\n```\n\nInclude the RegistrationController in your routing:\n\n```yaml\n// routing.yml\n\nnewsletter:\n    prefix: /newsletter\n    type: annotation\n    resource: '@WebfactoryNewsletterRegistrationBundle/Controller/RegistrationController.php'\n```\n \nThe RegistrationController gets some Interfaces injected in its constructor. Alias these interfaces with your own\nimplementations: \n\n```yaml\n// src/services.yml\n\nservices:\n  AppBundle\\Newsletter\\Entity\\NewsletterRepository:\n    factory:\n      - '@doctrine.orm.entity_manager'\n      - 'getRepository'\n    arguments:\n      - 'AppBundle\\Entity\\Newsletter'\n\n  Webfactory\\NewsletterRegistrationBundle\\Entity\\NewsletterRepositoryInterface:\n    alias: 'AppBundle\\Newsletter\\Entity\\NewsletterRepository'\n\n  AppBundle\\Newsletter\\Entity\\PendingOptInRepository:\n    factory:\n      - '@doctrine.orm.entity_manager'\n      - 'getRepository'\n    arguments:\n      - 'AppBundle\\Entity\\PendingOptIn'\n\n  Webfactory\\NewsletterRegistrationBundle\\Entity\\PendingOptInRepositoryInterface:\n    alias: 'AppBundle\\Newsletter\\Entity\\PendingOptInRepository'\n\n  AppBundle\\Newsletter\\Entity\\RecipientRepository:\n    factory:\n      - '@doctrine.orm.entity_manager'\n      - 'getRepository'\n    arguments:\n      - 'AppBundle\\Entity\\Recipient'\n\n  Webfactory\\NewsletterRegistrationBundle\\Entity\\RecipientRepositoryInterface:\n    alias: 'AppBundle\\Newsletter\\Entity\\RecipientRepository'\n```\n\n\nDelete outdated data\n--------------------\n\n    bin/console newsletter-registration:delete-outdated-pending-opt-ins\n    bin/console newsletter-registration:delete-outdated-blocked-email-addresses\n\n\nCustomization\n-------------\n\n### Views\n\nUse [the regular symfony mechanism for overriding templates](https://symfony.com/doc/4.4/bundles/override.html#templates).\n\nStart with:\n\n    mkdir src/Resources/WebfactoryNewsletterRegistrationBundle -p\n    cp -r vendor/webfactory/newsletter-registration-bundle/src/Resources/views src/Resources/WebfactoryNewsletterRegistrationBundle \n\n\n### Translations\n\nUse the [translation component's overwrite mechanism](https://symfony.com/doc/4.4/translation.html#translation-resource-file-names-and-locations).\n\nIf you add new languages or fix mistakes, please consider contributing via pull request. \n\n\n### Adding fields\n\n- Extend the StartRegistration Type with a [Form Type Extension](https://symfony.com/doc/4.4/form/create_form_type_extension.html).\n- Add the new fields to your entities (`AppBundle\\Entity\\PendingOptIn` and `AppBundle\\Entity\\Recipient` in the example\n  above). Maybe you want to extends their respective Repositories, too.\n- Implement `Webfactory\\NewsletterRegistrationBundle\\Entity\\PendingOptInFactoryInterface` and `Webfactory\\NewsletterRegistrationBundle\\Entity\\RecpientFactoryInterface`,\n  as they are responsible for creating your entities from the corresponding form data. Alias the interfaces to your\n  implementations, e.g.\n  ```yaml\n  // services.yml\n  services:\n    Webfactory\\NewsletterRegistrationBundle\\Entity\\PendingOptInFactoryInterface:\n        alias: 'App\\Newsletter\\Entity\\PendingOptInFactory'\n  ```\n\n### Logic\n\nIf you can pin down your modifications to the `StartRegistration`, `ConfirmRegistration`, `EditRegistration` or\n`DeleteRegistration` tasks, you are probably better off implementing your own versions of the respective interface\n(maybe extending the task class) and aliasing the interface service to them.\n\nFor greater flexibility, you can replace the RegistrationController with your own, e.g.:\n\n```php\n\u003c?php\n\nnamespace AppBundle\\Newsletter;\n\nclass Controller extends \\Webfactory\\NewsletterRegistrationBundle\\Controller\\Controller\n{\n    // ...\n}\n```\n\nDon't forget to configure your routing and services accordingly.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwebfactory%2Fwebfactorynewsletterregistrationbundle","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwebfactory%2Fwebfactorynewsletterregistrationbundle","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwebfactory%2Fwebfactorynewsletterregistrationbundle/lists"}