{"id":32610534,"url":"https://github.com/maize-tech/laravel-nps","last_synced_at":"2025-10-30T13:50:17.400Z","repository":{"id":43330882,"uuid":"437059392","full_name":"maize-tech/laravel-nps","owner":"maize-tech","description":"Easily integrate custom-made NPS (Net Promoter Score) into your application","archived":false,"fork":false,"pushed_at":"2025-08-12T08:22:00.000Z","size":344,"stargazers_count":55,"open_issues_count":2,"forks_count":6,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-09-28T19:58:56.090Z","etag":null,"topics":["api","laravel","netpromoterscore","nps","php"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/maize-tech.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE.md","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},"funding":{"github":"maize-tech"}},"created_at":"2021-12-10T17:22:37.000Z","updated_at":"2025-04-17T19:03:59.000Z","dependencies_parsed_at":"2024-04-19T15:05:04.731Z","dependency_job_id":null,"html_url":"https://github.com/maize-tech/laravel-nps","commit_stats":{"total_commits":16,"total_committers":4,"mean_commits":4.0,"dds":0.5,"last_synced_commit":"891084bd7b3b193fc8d30a34a91384d0a4499c21"},"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/maize-tech/laravel-nps","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maize-tech%2Flaravel-nps","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maize-tech%2Flaravel-nps/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maize-tech%2Flaravel-nps/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maize-tech%2Flaravel-nps/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/maize-tech","download_url":"https://codeload.github.com/maize-tech/laravel-nps/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maize-tech%2Flaravel-nps/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":281818074,"owners_count":26566858,"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","status":"online","status_checked_at":"2025-10-30T02:00:06.501Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["api","laravel","netpromoterscore","nps","php"],"created_at":"2025-10-30T13:50:16.337Z","updated_at":"2025-10-30T13:50:17.389Z","avatar_url":"https://github.com/maize-tech.png","language":"PHP","funding_links":["https://github.com/sponsors/maize-tech"],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n\u003cpicture\u003e\n  \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"/art/socialcard-dark.png\"\u003e\n  \u003csource media=\"(prefers-color-scheme: light)\" srcset=\"/art/socialcard-light.png\"\u003e\n  \u003cimg src=\"/art/socialcard-light.png\" alt=\"Social Card of Laravel NPS\"\u003e\n\u003c/picture\u003e\n\u003c/p\u003e\n\n# Laravel NPS\n\n[![Latest Version on Packagist](https://img.shields.io/packagist/v/maize-tech/laravel-nps.svg?style=flat-square)](https://packagist.org/packages/maize-tech/laravel-nps)\n[![GitHub Tests Action Status](https://img.shields.io/github/actions/workflow/status/maize-tech/laravel-nps/run-tests.yml?branch=main\u0026label=tests\u0026style=flat-square)](https://github.com/maize-tech/laravel-nps/actions?query=workflow%3Arun-tests+branch%3Amain)\n[![GitHub Code Style Action Status](https://img.shields.io/github/actions/workflow/status/maize-tech/laravel-nps/php-cs-fixer.yml?branch=main\u0026label=code%20style\u0026style=flat-square)](https://github.com/maize-tech/laravel-nps/actions?query=workflow%3A\"Check+%26+fix+styling\"+branch%3Amain)\n[![Total Downloads](https://img.shields.io/packagist/dt/maize-tech/laravel-nps.svg?style=flat-square)](https://packagist.org/packages/maize-tech/laravel-nps)\n\nEasily integrate custom-made NPS (Net Promoter Score) to your application.\n\n## Installation\n\nYou can install the package via composer:\n\n```bash\ncomposer require maize-tech/laravel-nps\n```\n\nYou can publish and run the migrations with:\n\n```bash\nphp artisan vendor:publish --tag=\"nps-migrations\"\nphp artisan migrate\n```\n\nYou can publish the config file with:\n```bash\nphp artisan vendor:publish --tag=\"nps-config\"\n```\n\nThis is the contents of the published config file:\n\n```php\n\u003c?php\n\nreturn [\n    /*\n    |--------------------------------------------------------------------------\n    | Nps model\n    |--------------------------------------------------------------------------\n    |\n    | Here you may specify the fully qualified class name of the nps model class.\n    |\n    */\n\n    'nps_model' =\u003e Maize\\Nps\\Models\\Nps::class,\n\n    /*\n    |--------------------------------------------------------------------------\n    | Nps answer model\n    |--------------------------------------------------------------------------\n    |\n    | Here you may specify the fully qualified class name of the nps answer\n    | model class.\n    |\n    */\n\n    'nps_answer_model' =\u003e Maize\\Nps\\Models\\NpsAnswer::class,\n\n    /*\n    |--------------------------------------------------------------------------\n    | Nps finder\n    |--------------------------------------------------------------------------\n    |\n    | Here you may specify the fully qualified class name of the nps finder class.\n    |\n    */\n\n    'nps_finder' =\u003e Maize\\Nps\\DefaultNpsFinder::class,\n\n    /*\n    |--------------------------------------------------------------------------\n    | Nps visibility\n    |--------------------------------------------------------------------------\n    |\n    | Here you may associate a custom visibility class to a name, which is then\n    | used as a reference in the nps model.\n    |\n    */\n\n    'visibility' =\u003e [\n        'default' =\u003e Maize\\Nps\\DefaultNpsVisibility::class,\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Nps range\n    |--------------------------------------------------------------------------\n    |\n    | Here you may associate a custom range class to a name, which is then\n    | used as a reference in the nps model.\n    |\n    */\n\n    'range' =\u003e [\n        'default' =\u003e Maize\\Nps\\DefaultNpsRange::class,\n        'minimal' =\u003e Maize\\Nps\\MinimalNpsRange::class,\n        'emoji' =\u003e Maize\\Nps\\EmojiNpsRange::class,\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Route configurations\n    |--------------------------------------------------------------------------\n    |\n    | Here you may specify whether routes should be enabled or not.\n    | You can also customize the routes prefix and middlewares.\n    |\n    */\n\n    'routes' =\u003e [\n        'enabled' =\u003e true,\n        'prefix' =\u003e '',\n        'name' =\u003e 'nps',\n        'middleware' =\u003e ['auth:api'],\n        'endpoints' =\u003e [\n            'show' =\u003e [\n                'middleware' =\u003e [],\n            ],\n            'answer' =\u003e [\n                'middleware' =\u003e [],\n            ],\n            'delay' =\u003e [\n                'middleware' =\u003e [],\n            ],\n        ],\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Cache\n    |--------------------------------------------------------------------------\n    |\n    | Here you may specify the amount of time, in seconds, where each nps\n    | is cached to avoid multiple database queries.\n    |\n    */\n\n    'cache' =\u003e [\n        'nps_ttl' =\u003e 3600,\n        'nps_answer_ttl' =\u003e 3600,\n    ],\n];\n```\n\n## Usage\n\n### Basic\n\nTo use the package, add the `Maize\\Nps\\CanAnswerNps` trait to the User model.\n\nHere's an example model including the `CanAnswerNps` trait:\n\n``` php\n\u003c?php\n\nnamespace App\\Models;\n\nuse Maize\\Nps\\CanAnswerNps;\n\nclass User extends Model\n{\n    use CanAnswerNps;\n\n    protected $fillable = [\n        'fist_name',\n        'last_name',\n        'email',\n    ];\n}\n```\n\nYou can then create one or multiple NPS from the DB or, if you wish, you could handle the creation with a CMS.\n\nHere are the fields who should be filled:\n- **question**: the question that identifies the NPS\n- **starts_at**: the start date of the NPS\n- **ends_at**: the end date of the NPS\n- **range**: the value ranges accepted for the given NPS. This value must be equal to one of the keys defined in the `range` list from `config/nps.php`. Defaults to `default`.\n- **visibility**: the visibility for the given NPS. This value must be equal to one of the keys defined in the `visibility` list from `config/nps.php`. Defaults to `default`.\n\nLet's say we create a NPS which starts on 2021-01-01 and ends after a week: here's the model entity we would have:\n\n``` php\n$nps = [\n    \"id\" =\u003e 1,\n    \"question\" =\u003e \"How would you rate our platform?\",\n    \"starts_at\" =\u003e \"2021-01-01\",\n    \"ends_at\" =\u003e \"2021-01-31\",\n    \"range\" =\u003e \"default\", // default range is 1-5\n    \"visibility\" =\u003e \"default\", // by default a NPS is always visible\n    \"updated_at\" =\u003e \"2021-01-01\",\n    \"created_at\" =\u003e \"2021-01-01\",\n];\n```\n\nYou can now call the custom API to retrieve, reply or delay the current NPS, which can be customized in `config/nps.php`:\n\n#### GET - **/nps**\n\nThis endpoint retrieves the current NPS using the given criteria:\n- the `starts_at` date must be earlier than `now()`\n- the `ends_at` date must be older than `now()`\n- the NPS must be visible (defaults to `true`)\n\nThe NPS entries are then filtered by their ends_at date in order to pick the first one expiring.\n\nThe response contains the NPS id (used for the POST route), the question, and the accepted values.\nHere is a sample response body:\n\n``` json\n{\n    \"data\": {\n        \"id\": 1,\n        \"values\": [\n            1,\n            2,\n            3,\n            4,\n            5\n        ],\n        \"question\": \"How would you rate our platform?\"\n    }\n}\n```\n\n#### POST - **/nps/{id}**\n\nThis endpoint stores the answer for the given NPS from the currently authenticated user. The request requires the following attributes:\n- **value**: the value chose by the user\n- **answer**: the (optional) answer written by the user\n\nThere are some basic validation rules applied to the request:\n- the **value** attribute must be an integer\n- the **value** attribute should be between the range defined in the given NPS model\n- a user should not be able to submit the answer if **value** is `null`\n- a user should be able to decline their submission for the NPS. In this case, both **value** and **answer** attributes should be `null`\n\n#### POST - **/nps/{id}/delay**\n\nThis endpoint marks the NPS answered in cache for the currently authenticated user, but only for a limited time.\n\nThis way, the `hasAnsweredCurrentNps` and `hasAnsweredNps` methods will return `true` even if the answer is not stored in the database.\n\nThe user will then be able to see again the NPS only after that amount of time has expired.\n\nThe amount of time (in seconds) can be configured in the `nps_answer_ttl` attribute from `config/nps.php`.\n\n### Custom range class\n\nIf you wish to define a custom range of values for a NPS, you can define a new class which extends the NpsRange abstract class and contains a `$values` array.\n\n``` php\nclass MyCustomNpsRange extends NpsRange\n{\n    protected static array $values = [2, 4, 6, 8, 10];\n}\n```\n\nYou can then associate the class with a name used as identified for the `range` attribute of the NPS model.\nThis can be easily done by adding the key-value pair in the `range` list from `config/nps.php`:\n\n``` php\n'range' =\u003e [\n    'default' =\u003e Maize\\Nps\\DefaultNpsRange::class,\n    'minimal' =\u003e Maize\\Nps\\MinimalNpsRange::class,\n    'emoji' =\u003e Maize\\Nps\\EmojiNpsRange::class,\n    'custom' =\u003e Path\\To\\MyCustomNpsRange::class,\n]\n```\n\nYou can also define an associative array in case you want the values to be an array of strings.\nIn this case, the key should contain the string, whereas the value is the associated integer which should be sent from the POST endpoint.\n\n``` php\nclass EmojiNpsRange extends NpsRange\n{\n    protected static array $values = [\n        '😡' =\u003e 1,\n        '🙁' =\u003e 2,\n        '😐' =\u003e 3,\n        '😉' =\u003e 4,\n        '😍' =\u003e 5,\n    ];\n}\n\n```\n\n### Custom visibility class\n\nIf you wish to define a custom visibility for a NPS, you can define a new class which extends the NpsVisibility abstract class and implement the `__invoke` abstract method.\n\nFor example, let's say we want a NPS to be visible for a user when they performed at least 5 logins.\nHere is the custom visibility class we should have:\n\n``` php\nclass MinLoginsVisibility extends NpsVisibility\n{\n    public function __invoke(Nps $nps): bool\n    {\n        return auth()-\u003euser()-\u003eaccessLogs()-\u003ecount() \u003e= 5;\n    }\n}\n```\n\nYou can then associate the class with a name used as identified for the `visibility` attribute of the NPS model.\nThis can be easily done by adding the key-value pair in the `visibility` list from `config/nps.php`:\n\n``` php\n'visibility' =\u003e [\n    'default' =\u003e Maize\\Nps\\DefaultNpsVisibility::class,\n    'min_logins' =\u003e Path\\To\\MinLoginsVisibility::class,\n]\n```\n\n## Testing\n\n```bash\ncomposer test\n```\n\n## Changelog\n\nPlease see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.\n\n## Contributing\n\nPlease see [CONTRIBUTING](https://github.com/maize-tech/.github/blob/main/CONTRIBUTING.md) for details.\n\n## Security Vulnerabilities\n\nPlease review [our security policy](https://github.com/maize-tech/.github/security/policy) on how to report security vulnerabilities.\n\n## Credits\n\n- [Enrico De Lazzari](https://github.com/enricodelazzari)\n- [Riccardo Dalla Via](https://github.com/riccardodallavia)\n- [All Contributors](../../contributors)\n\n## License\n\nThe MIT License (MIT). Please see [License File](LICENSE.md) for more information.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaize-tech%2Flaravel-nps","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmaize-tech%2Flaravel-nps","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaize-tech%2Flaravel-nps/lists"}