{"id":21890900,"url":"https://github.com/statikbe/laravel-surveyhero","last_synced_at":"2025-04-15T13:39:23.141Z","repository":{"id":51608857,"uuid":"520514925","full_name":"statikbe/laravel-surveyhero","owner":"statikbe","description":"Import Surveyhero questions, answers and responses into a Laravel database, https://www.surveyhero.com/","archived":false,"fork":false,"pushed_at":"2025-02-03T03:42:40.000Z","size":300,"stargazers_count":13,"open_issues_count":3,"forks_count":0,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-04-09T03:36:22.933Z","etag":null,"topics":["laravel","laravel-package","questionnaire","survey","surveyhero"],"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/statikbe.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"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,"publiccode":null,"codemeta":null}},"created_at":"2022-08-02T13:43:43.000Z","updated_at":"2024-11-26T20:54:11.000Z","dependencies_parsed_at":"2024-03-14T16:28:10.433Z","dependency_job_id":"0760b736-f52b-400d-9a2e-47747996d65c","html_url":"https://github.com/statikbe/laravel-surveyhero","commit_stats":null,"previous_names":[],"tags_count":31,"template":false,"template_full_name":"spatie/package-skeleton-laravel","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/statikbe%2Flaravel-surveyhero","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/statikbe%2Flaravel-surveyhero/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/statikbe%2Flaravel-surveyhero/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/statikbe%2Flaravel-surveyhero/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/statikbe","download_url":"https://codeload.github.com/statikbe/laravel-surveyhero/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249081516,"owners_count":21209712,"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":["laravel","laravel-package","questionnaire","survey","surveyhero"],"created_at":"2024-11-28T12:18:08.498Z","updated_at":"2025-04-15T13:39:23.124Z","avatar_url":"https://github.com/statikbe.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp style=\"text-align: center;\"\u003e\u003cimg src=\"documentation/img/banner-laravel-surveyhero.png\" alt=\"Laravel Surveyhero\"\u003e\u003c/p\u003e\n\n# Import Surveyhero responses into the Laravel database\n\n[![Latest Version on Packagist](https://img.shields.io/packagist/v/statikbe/laravel-surveyhero.svg?style=flat-square)](https://packagist.org/packages/statikbe/laravel-surveyhero)\n[![GitHub Tests Action Status](https://img.shields.io/github/actions/workflow/status/statikbe/laravel-surveyhero/.github/workflows/run-tests.yml?branch=main)](https://github.com/statikbe/laravel-surveyhero/actions?query=workflow%3Arun-tests+branch%3Amain)\n[![GitHub Code Style Action Status](https://img.shields.io/github/actions/workflow/status/statikbe/laravel-surveyhero/.github/workflows/fix-php-code-style-issues.yml?branch=main)](https://github.com/statikbe/laravel-surveyhero/actions?query=workflow%3A\"Fix+PHP+code+style+issues\"+branch%3Amain)\n[![Total Downloads](https://img.shields.io/packagist/dt/statikbe/laravel-surveyhero.svg?style=flat-square)](https://packagist.org/packages/statikbe/laravel-surveyhero)\n\nThis package allows you to import [Surveyhero](https://www.surveyhero.com) survey responses. \n\n## Installation\n\nYou can install the package via composer:\n\n```bash\ncomposer require statikbe/laravel-surveyhero\n```\n\nPlease publish the config file with:\n\n```bash\nphp artisan vendor:publish --tag=\"surveyhero-config\"\n```\n\nCheck the [configuration options](#configuration) first, in case you want to customise your data model.\n\nPlease publish and run the migrations with:\n\n```bash\nphp artisan vendor:publish --tag=\"surveyhero-migrations\"\nphp artisan migrate\n```\n\n**NB:** If you want to customise the default data model, first edit the configuration file, see the \n[Data Model Customisation section](#data-model-customisation).\n\n## Upgrading to V2\n\nThe data model changed in v2, so [an upgrade guide](UPGRADING.md) is available.\n\n## Data model\n\n``` mermaid\nerDiagram\nSURVEY {\n    num id\n    num surveyhero_id\n    string name\n    json collector_ids\n    json question_mapping\n    datetime survey_last_imported\n    boolean use_resume_link\n}\n\nSURVEY_QUESTIONS {\n    num id\t\t\n    num survey_id FK\n    num surveyhero_element_id\n    num surveyhero_question_id\n    string field\t\t\t\n    json label\t\t\n}\n\nSURVEY_ANSWERS {\n    num id\t\t\n    num survey_question_id FK\n    num surveyhero_answer_id\t\t\t\n    string converted_string_value\t\t\t\n    num converted_int_value\t\t\t\n    json label\t\t\t\n}\n\nSURVEY_RESPONSE {\n    num id\n    num surveyhero_id\n    datetime survey_start_date\n    datetime survey_last_updated\n    string survey_language\n    bool survey_completed\n    json surveyhero_link_parameters\n    string resume_link\n    num survey_id FK\n}\nSURVEY_QUESTION_RESPONSE {\t\n    num id\n    num surveyhero_question_id FK\n    num survey_answer_id FK\n    num survey_response_id FK\n}\nSURVEY ||--o{ SURVEY_QUESTIONS : contains\nSURVEY ||--o{ SURVEY_RESPONSE : contains\nSURVEY_QUESTIONS ||--o{ SURVEY_ANSWERS : contains\nSURVEY_QUESTION_RESPONSE ||--o{ SURVEY_ANSWERS : has\nSURVEY_QUESTION_RESPONSE ||--o{ SURVEY_RESPONSE : has\n```\n\nWhen a user fills out a survey on Surveyhero, a survey response is available in the API, which contains all question \nanswers. The relational data model implements the same logic. To start importing Surveyhero responses, you should \ncreate a Survey record with the survey ID from Surveyhero. The questions and answers (i.e. for multiple choice) with \ntheir translated labels can be imported.\n\nEach response contains metadata about the submission and link parameters are stored in JSON but can be [mapped to custom\ndata columns](#link-parameters-mapping). If the response is marked as completed by Surveyhero, we will skip the import.\n\nFor each answer, the surveyhero question and answer ID's are stored. The field column is used to store a question \nidentifier to be able to more easily query the answers, e.g. to produce statistics. The answer can be converted to a\nnew value. For instance, this is handy for Likert scales or dropdowns to map to a numeric value or standardised string \nconstants, to make postprocessing easier. Since most surveys are used to run statistics on, we have implemented 2 \ndifferent column types for now: `integer` and `string` to be able to easily run SQL aggregates. \n\n## Configuration\n\nCreate an API user and password [on Surveyhero](https://developer.surveyhero.com/api/#authentication) and set this in the\n`.env` file:\n\n```\nSURVEYHERO_API_USERNAME=1234567890\nSURVEYHERO_API_PASSWORD=qwertyuiopasdfghjklzxcvbnm\n```\n\nYou can overwrite the default table names and Eloquent model classes, if needed check the \n[Data Model Customisation section](#data-model-customisation).\n\n## Import surveys\n\nThis command imports the survey for a given survey ID, the survey IDs in the configuration file or all surveys.\n\n```shell\nphp artisan surveyhero:import-surveys\n```\n\nYou can import a specific survey with the flag `--survey=1234567`.\n\nOr you can configure survey IDs in the `question_mapping` in the `surveyhero.php` configuration file.\n```php\n'question_mapping' =\u003e [\n    [\n        'survey_id' =\u003e 1234567,\n    ],\n    [\n        'survey_id' =\u003e 4897492,\n    ],\n    ...\n];\n```\n\nIf you want to import all, add the flag `--all`.\n\nIf you want to reimport all surveys you can wipe them by using the flag `--fresh`.\n\n## Question and collector mapping\n\nIn order to start importing our survey questions, answers and responses, we need to set up a mapping between the API and our application. The mapping is generated from the Surveyhero API data. When you want to rename questions, answers and convert responses, you can customise this mapping. To make this more flexible, we store this mapping in the Survey data model in the database. You can then change this mapping in the database or you can overwrite the mapping (or only specific questions) by adding the mapping to the configuration file of the question mappings that need to be altered. \n\nThis mechanism merges the configuration file mapping into the mapping stored in the database. This allows you to more easily change the survey on Surveyhero and just reimport the mapping without having to change the configuration and have to redeploy your application.\n\n### Generate mapping\nTo automatically generate the mapping using the API, run the following command:\n\n```shell\nphp artisan surveyhero:map --updateDatabase\n```\n\nThis will generate a default question mapping for your questions and collectors and save them to the surveys data model in the database. The configured collectors on Surveyhero will also be copied to the database and can be changed to your preference.\n\n**You should run this command everytime changes are made to questions/answers/collectors in SurveyHero!**\n\n### Customise mapping\n#### Customise collectors\nThis is useful when you only want to retrieve responses from a certain collector. For example when you have separate collectors set up for your environments.\ne.g. by creating a collector per environment you can maintain 1 survey for your local development environment and production deployment.\nIn that case you might add environment vars for the collector ID's in the `.env` file to ease configuration.\n\nIf there are collectors configured in the configuration file, they will be used and will overrule the collectors stored in the survey model.\n\n```php\n'question_mapping' =\u003e [\n    [\n        'survey_id' =\u003e 1234567,\n        'collectors' =\u003e [986362,524948],\n    ],\n    [\n        'survey_id' =\u003e 4897492,\n        'collectors' =\u003e env('COLLECTOR_IDS'),\n    ],\n    ...\n];\n```\n\nCollectors in the config file will overwrite the ones automatically imported in the database. When no collectors key is present, we will default to the value in de database.\n\n#### Customise questions/answers\nCustomizing the mapping can be useful to decide on your own question identifiers and answer values.\nTo do this, add `questions` to the question_mapping in your config file and include the questions you want to set up a custom mapping for:\n\n```php\n'question_mapping' =\u003e [\n    [\n        'survey_id' =\u003e 1234567,\n        'collectors' =\u003e [986362,524948],\n        'use_resume_link' =\u003e true,\n        'questions' =\u003e [\n            #example numeric input\n            1000005 =\u003e [\n                'question_id' =\u003e 1000005,\n                'type' =\u003e 'text',\n                'field' =\u003e 'custom_question_field_name',\n            ],\n            #example choice list\n            1000002 =\u003e [\n                'question_id' =\u003e 1000002,\n                'type' =\u003e 'choices',\n                'field' =\u003e 'another_custom_question_field_name',\n                'answer_mapping' =\u003e [\n                    13509166 =\u003e 10,\n                    13509167 =\u003e 1000,\n                    13509168 =\u003e 1337,\n                ],\n                'mapped_data_type' =\u003e 'int',\n            ],\n        ]\n    ],\n    ...\n];\n```\n\nEach question type has different specifications, so the mapping data structure is slightly different:\n\nYou can generate the complete `question_mapping` that you can copy-paste from into your configuration file and further\nadjust there. Following command generates `surveyhero_mapping.php`in the project root. This file contains the PHP array. Run:\n\n```shell\nphp artisan surveyhero:map --generateConfig\n ```\n\n#### Summary of currently supported question types and their mapping structure:\n\n#### Text input\n\n```php\n1000005 =\u003e [\n    'question_id' =\u003e 1000005,\n    'type' =\u003e 'text',\n    'field' =\u003e 'question_5',\n],\n```\n\nThe field is the identifier in your database to be able to more easily query the responses for a question.\n\n#### Numeric input\n\n```php\n1000006 =\u003e [\n    'question_id' =\u003e 1000006,\n    'type' =\u003e 'number',\n    'field' =\u003e 'age',\n    'mapped_data_type' =\u003e 'int',\n],\n```\n\nCurrently, only integer support is implemented.\n\n#### Choice list\n\n```php\n1000002 =\u003e [\n    'question_id' =\u003e 1000002,\n    'type' =\u003e 'choices',\n    'field' =\u003e 'question_4',\n    'answer_mapping' =\u003e [\n        13509166 =\u003e 1,\n        13509167 =\u003e 2,\n        13509168 =\u003e 3,\n    ],\n    'mapped_data_type' =\u003e 'int',\n],\n```\n\nA choice list requires an `answer_mapping`, where you can map the Surveyhero choice ID's to the converted values that\nyou want to use in your statistics. You should also set `mapped_data_type` to `int` or `string` depending on the values\ndata type of `answer_mapping`.\n\n#### Choice table\n\n```php\n1000001 =\u003e [\n    'question_id' =\u003e 1000001,\n    'type' =\u003e 'choice_table',\n    'subquestion_mapping' =\u003e [\n        13509163 =\u003e [\n            'question_id' =\u003e 13509163,\n            'field' =\u003e 'question_1',\n        ],\n        13509164 =\u003e [\n            'question_id' =\u003e 13509164,\n            'field' =\u003e 'question_2',\n        ],\n        13509165 =\u003e [\n            'question_id' =\u003e 13509165,\n            'field' =\u003e 'question_3',\n            'answer_mapping' =\u003e [\n                13509163 =\u003e 3,\n                13509164 =\u003e 2,\n                13509165 =\u003e 1,\n            ],\n        ],\n    ],\n    'answer_mapping' =\u003e [\n        13509163 =\u003e 1,\n        13509164 =\u003e 2,\n        13509165 =\u003e 3,\n    ],\n    'mapped_data_type' =\u003e 'int', //can also be string if the values are strings in answer_mapping\n]\n```\n\nA choice table is a Likert scale type of question with a set of rows or subquestions. You need to map each row to a\nsubquestion with its own `question_id` and `field`. So each subquestion will become a `SurveyQuestionResponse` record.\nThe `answer_mapping` operates identically to [Choice List](#choice-list). You can also specify an `answer_mapping` for\na specific question, in case the mapping differs for that question, see `question_id` 13509165.\n\n### Import questions and answers\n\nThis command imports all survey questions and answers associated with their (translated) label for a given survey ID or all surveys. You can schedule this for continuous\nupdates.\n\n```shell\nphp artisan surveyhero:import-questions-and-answers\n```\n\nYou can configure a specific survey with the flag `--survey=22333`.\nIf you want to reimport all survey responses you can wipe the SurveyQuestions and SurveyAnswers by using the\nflag `--fresh`.\n\n### Import responses\n\nThis command imports all survey responses for a given survey ID or all surveys. You can schedule this for continuous\nupdates.\nFirst you need to create at least one `Survey` record with a Surveyhero ID.\n\n```shell\nphp artisan surveyhero:import-responses\n```\n\nYou can configure a specific survey with the flag `--survey=22333`.\nIf you want to reimport all survey responses you can wipe the SurveyResponses and SurveyQuestionResponses by using the\nflag `--fresh`.\n\n### Link parameters mapping\n\nSurveyhero allows to pass parameters in the query string of the share URL, see \n[docs](https://help.surveyhero.com/manual/collect-responses/how-to-add-parameters-to-your-online-survey-link/).\n\nThese parameters are often used to send the same survey URL to different types or participants that you want to be \nable to identify in your survey responses. Surveyhero returns these parameters as `link-parameters` through the response\nAPI. By default, the library stores the link parameters as JSON in the `surveyhero_link_parameters` column.\n\nThe library also allows you to map these link parameters to variables on the `SurveyReponse` model. To do this you need \nto create a new migration in your project to add the new columns to the `survey_response` table, and then configure\n`surveyhero_link_parameters_mapping` in the configuration file.\n\n```php \n'surveyhero_link_parameters_mapping' =\u003e [\n     'username' =\u003e [\n         'name' =\u003e 'user_name'                        (the target column name on the survey_response table)\n     ],\n     'user_uuid' =\u003e [\n         'name' =\u003e 'user_id',                         (the target column name on the survey_response table)\n         'entity' =\u003e \\App\\Models\\User::class,         (the model to query)\n         'value' =\u003e 'uuid',                           (the column on the entity to query)\n         'field' =\u003e 'id',                             (the column on the entity to select)\n     ],\n],\n```\nThere are 2 options to map link parameters.\n\n#### Option 1: Map directly to a database column\n\nThe key is the name of the Surveyhero link parameter\n - `name` represents the column in the survey_response table to which we save the field\n \n#### Option 2: Map to the foreign key of a model\n\nFollowing parameters are optional in case you want to evaluate the link_parameters value on the database\n - `entity` represents the model you're querying on\n - `value` represents the field you're comparing on your model\n - `field` represents the field from your model to store in de database\n\n## Data Model Customisation\n\nIf you want to add extra variables, functions or relationships to the Eloquent models of this package, you might want \nto extend the model classes or implement your own. \n\n**Note:** If you implement your own data models without subclassing the default\nmodels, you need to implement the Contract interfaces in `Statikbe\\Surveyhero\\Contracts`. The package expects\ncertain column names (check the migrations and contracts for details), however you can configure the table names and \nforeign keys in the configuration, see below.\n\n### Customising the Eloquent models\n\nYou can set your own Eloquent models in the configuration file under the variable `models`.\n\n```php \n'models' =\u003e [\n    'survey' =\u003e Statikbe\\Surveyhero\\Models\\Survey::class,\n    'survey_question' =\u003e Statikbe\\Surveyhero\\Models\\SurveyQuestion::class,\n    'survey_answer' =\u003e Statikbe\\Surveyhero\\Models\\SurveyAnswer::class,\n    'survey_response' =\u003e Statikbe\\Surveyhero\\Models\\SurveyResponse::class,\n    'survey_question_response' =\u003e Statikbe\\Surveyhero\\Models\\SurveyQuestionResponse::class,\n],\n```\n\n### Customising the table names\n\nYou can change the table names by editing the `table_names` variable in the config file:\n\n```php \n'table_names' =\u003e [\n    'surveys' =\u003e [\n        'name' =\u003e 'surveys',\n        'foreign_key' =\u003e 'survey_id',\n    ],\n    'survey_questions' =\u003e [\n        'name' =\u003e 'survey_questions',\n        'foreign_key' =\u003e 'survey_question_id',\n    ],\n    'survey_answers' =\u003e [\n        'name' =\u003e 'survey_answers',\n        'foreign_key' =\u003e 'survey_answer_id',\n    ],\n    'survey_responses' =\u003e [\n        'name' =\u003e 'survey_responses',\n        'foreign_key' =\u003e 'survey_response_id',\n    ],\n    'survey_question_responses' =\u003e [\n        'name' =\u003e 'survey_question_responses',\n        'foreign_key' =\u003e 'survey_question_response_id',\n    ],\n],\n```\n\nThe `foreign_key` is the column name of the foreign keys used to refer the table name.\n\n## Surveyhero webhooks\n\nWe have implemented part of the [Surveyhero webhook](https://developer.surveyhero.com/api/#webhooks-api) options into this package.\n\n### Create a webhook\n\nWith the command below you can add a webhook to your Survey:\n\n```shell \nphp artisan surveyhero:add-webhooks --eventType=response.completed --url=https://webhook.site/complete-response\n```\n\n### List webhooks\n\nWith the command below you can list all the webhooks of your Survey:\n\n```shell \nphp artisan surveyhero:list-webhooks --survey=12345\n```\n\n### Delete a webhook\n\nWith the command below you can delete a webhook from your Survey:\n\n```shell \nphp artisan surveyhero:delete-webhook --survey=12345 --webhook=2553\n```\n\n### Webhook handlers\n\nWe have also implemented a default controller (`SurveyheroWebhookController.php`) to handle the webhook responses. Currently, it only supports the \n`response.completed` [type](https://developer.surveyhero.com/api/#webhooks-event-types).\n\nYou can add this in a route to your `api.php` file, like so:\n\n```php \nuse Statikbe\\Surveyhero\\Http\\Controllers\\Api\\SurveyheroWebhookController;\n\nRoute::post('/process-surveyhero-response-completed', [SurveyheroWebhookController::class, 'handleResponseCompletedWebhook'])\n    -\u003ename('surveyhero_response_webhook');\n```\n\nThere is also a convenience function on the facade so you can also just include this in your `api.php`:\n\n```php \nuse Statikbe\\Surveyhero\\Facades\\Surveyhero;\n\nSurveyhero::webhookRoutes();\n```\n\n## Data export\n\nYou can export the responses to a spreadsheet with questions, answers and responses worksheets by default.\nFor example, you can execute:\n\n```shell\n php artisan surveyhero:responses-export --survey=1451654 --linkParameter=organisation --extraResponseCol=survey_completed --extraResponseCol=survey_start_date\n```\n\nYou can pass the survey to be exported and then customise the export by adding columns to the responses sheet, from\nthe link parameters that were passed to Surveyhero or extra columns from the survey responses table.\n\n### Customisation\n\nYou can extend `SurveyExportService`, `SurveyExport` and the sheet implementations.\n\nIn the `SurveyExportService` you can change the `createSurveyExport()` function to change the `SurveyExport` implementation.\nIf you want to add more sheets, you can set the sheets by setting `setSheets()` on `SurveyExport`. \nIf you want to change the work sheets, you can change the queries in `query()`, the title in `setTitle()`, etc.  \n\n## Events\n\nThe following events are implemented:\n\n- __SurveyResponseImported:__ dispatched when a survey response is imported successfully. \n- __SurveyResponseIncompletelyImported:__ dispatched when a survey response is imported successfully but the data was incomplete.\n\n## Ideas for future improvements\n\n- ~~Add more commands to manage webhooks~~\n- Add more default indices to the migration.\n- Support more Surveyhero question types.\n- Support more converted value data types, e.g. double.\n- A command to check the `question_mapping` configuration to validate if:\n  - there are no double field names\n  - there are no double question IDs.\n  - there are no double answer IDs.\n  - the data format for a question time is ok, i.e. are all fields there and are they the right type.\n  - ~~all questions and answers are mapped by doing an API request.~~\n- Statistics calculator service to quickly query aggregates of responses of questions.\n\n## Testing\n\nCurrently, no tests are implemented :-(.\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\nYou can post an issue and provide a pull request. Thanks!\n\n## Credits\n\n- [Sten Govaerts](https://github.com/sten)\n- [Robbe Reygel](https://github.com/RobbeStatik)\n- [Marie Drieghe](https://github.com/madriegh)\n- [All Contributors](https://github.com/statikbe/laravel-surveyhero/graphs/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%2Fstatikbe%2Flaravel-surveyhero","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstatikbe%2Flaravel-surveyhero","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstatikbe%2Flaravel-surveyhero/lists"}