From 3d34db3827479bfbd7b8ff25f2190f0d02b65ebe Mon Sep 17 00:00:00 2001 From: Sebastian Fix Date: Fri, 17 Oct 2025 15:57:49 +0200 Subject: [PATCH 01/30] Fixed #197 --- .../General/UserManagement/GetUsers/OutOfOffice.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/DTO/General/UserManagement/GetUsers/OutOfOffice.php b/src/DTO/General/UserManagement/GetUsers/OutOfOffice.php index 802e4cf8..2a5a356f 100644 --- a/src/DTO/General/UserManagement/GetUsers/OutOfOffice.php +++ b/src/DTO/General/UserManagement/GetUsers/OutOfOffice.php @@ -12,12 +12,16 @@ public static function fromJson(array $data): self { if ($startDateTime = Arr::get($data, 'StartDateTime')) { $startDateTime = Str::of($startDateTime)->after('(')->before(')'); - $startDateTime = Carbon::createFromTimestamp($startDateTime); + // Extract milliseconds part (ignore optional timezone offset like +0000) + $milliseconds = (int) (string) $startDateTime; + $startDateTime = Carbon::createFromTimestampMs($milliseconds, 'UTC'); } if ($endDateTime = Arr::get($data, 'EndDateTime')) { $endDateTime = Str::of($endDateTime)->after('(')->before(')'); - $endDateTime = Carbon::createFromTimestamp($endDateTime); + // Extract milliseconds part (ignore optional timezone offset like +0000) + $milliseconds = (int) (string) $endDateTime; + $endDateTime = Carbon::createFromTimestampMs($milliseconds, 'UTC'); } return new self( @@ -25,7 +29,7 @@ public static function fromJson(array $data): self startDateTime: $startDateTime, startDateTimeSpecified: Arr::get($data, 'StartDateTimeSpecified'), endDateTime: $endDateTime, - endDateTimeSpecified: Arr::get($data, 'EndDateTimeSpecified'), + endDateTimeSpecified: Arr::get($data, key: 'EndDateTimeSpecified'), ); } From 6087c046c1bf7ea2b798d7ebe97dbe11b8878ffe Mon Sep 17 00:00:00 2001 From: Sebastian Fix Date: Fri, 17 Oct 2025 16:02:52 +0200 Subject: [PATCH 02/30] Resolved #189, updated Docs and Tests for Enums --- .phpunit.cache/test-results | 2 +- README.md | 46 ++++++++++++++ src/Enums/DocuWareFieldTypeEnum.php | 13 ++++ tests/Unit/Enums/ConnectionEnumTest.php | 37 +++++++++++ tests/Unit/Enums/DialogTypeTest.php | 46 ++++++++++++++ .../Unit/Enums/DocuWareFieldTypeEnumTest.php | 61 +++++++++++++++++++ 6 files changed, 204 insertions(+), 1 deletion(-) create mode 100644 src/Enums/DocuWareFieldTypeEnum.php create mode 100644 tests/Unit/Enums/ConnectionEnumTest.php create mode 100644 tests/Unit/Enums/DialogTypeTest.php create mode 100644 tests/Unit/Enums/DocuWareFieldTypeEnumTest.php diff --git a/.phpunit.cache/test-results b/.phpunit.cache/test-results index 865937dc..7c94d9dd 100644 --- a/.phpunit.cache/test-results +++ b/.phpunit.cache/test-results @@ -1 +1 @@ -{"version":"pest_3.8.2","defects":{"P\\Tests\\Feature\\Requests\\Workflow\\GetDocumentWorkflowHistoryTest::__pest_evaluable_it_can_get_document_workflow_history":1,"P\\Tests\\Feature\\SleepTest::__pest_evaluable_sleep":1,"P\\Tests\\Feature\\Laravel12CacheCompatibilityTest::__pest_evaluable_cache_configuration_uses_CACHE__STORE_in_Laravel_12":8,"P\\Tests\\Feature\\Laravel12CacheCompatibilityTest::__pest_evaluable_cache_configuration_uses_DOCUWARE__CACHE__DRIVER_when_explicitly_set":7,"P\\Tests\\Feature\\Requests\\Workflow\\GetDocumentWorkflowHistoryStepsTest::__pest_evaluable_it_can_get_document_workflow_history":1,"P\\Tests\\Feature\\Requests\\FileCabinets\\Upload\\AppendFilesToADataRecordTest::__pest_evaluable_it_can_attach_files_to_a_data_record":1,"Tests\\Unit\\DTO\\TextshotPageTest::test_it_can_create_textshot_page_with_null_language":7,"Tests\\Unit\\DTO\\TextshotPageTest::test_it_can_create_textshot_page_with_string_language":7,"P\\Tests\\Feature\\Laravel12CacheCompatibilityTest::__pest_evaluable_cache_configuration_uses_default_file_driver_when_no_configuration_is_set":8,"P\\Tests\\Feature\\Laravel12CacheCompatibilityTest::__pest_evaluable_cache_configuration_respects_the_new_CACHE__STORE_fallback_chain":8,"P\\Tests\\Feature\\Laravel12CacheCompatibilityTest::__pest_evaluable_environment_variable_fallback_chain_works_correctly":7,"P\\Tests\\Feature\\Laravel12CacheCompatibilityTest::__pest_evaluable_CACHE__STORE_takes_precedence_over_CACHE__DRIVER_when_DOCUWARE__CACHE__DRIVER_is_not_set":7,"P\\Tests\\Feature\\Laravel12CacheCompatibilityTest::__pest_evaluable_cache_configuration_can_be_overridden":8,"P\\Tests\\Feature\\Laravel12CacheCompatibilityTest::__pest_evaluable_cache_configuration_fallback_chain_is_properly_configured":8},"times":{"P\\Tests\\Feature\\Requests\\Documents\\Sections\\GetTextshotTest::__pest_evaluable_it_get_textshot_for_a_specific_section":1.669,"P\\Tests\\Feature\\Requests\\Documents\\DocumentsTrashBin\\DeleteDocumentsFromTrashBinTest::__pest_evaluable_it_can_delete_documents_in_trash":1.262,"P\\Tests\\Feature\\Requests\\Documents\\Sections\\GetAllSectionsFromADocumentTest::__pest_evaluable_it_can_get_all_sections_from_a_document":1.1,"P\\Tests\\Feature\\Requests\\Documents\\ClipUnclipStapleUnstaple\\UnstapleTest::__pest_evaluable_it_can_unstaple_a_document":13.455,"P\\Tests\\Feature\\Requests\\Documents\\ApplicationProperties\\ApplicationPropertiesTest::__pest_evaluable_it_can_add_get_update_delete_application_properties_to_a_document":1.042,"P\\Tests\\Feature\\Requests\\General\\UserManagement\\GetUsers\\GetUsersTest::__pest_evaluable_it_can_list_users":0.746,"P\\Tests\\Feature\\Requests\\Organization\\GetOrganizationsRequestTest::__pest_evaluable_it_can_list_organizations":0.504,"P\\Tests\\Feature\\Requests\\Fields\\GetFieldsRequestTest::__pest_evaluable_it_can_list_fields_for_a_file_cabinet":0.53,"P\\Tests\\Feature\\Requests\\Search\\GetSearchRequestTest::__pest_evaluable_it_can_override_search_documents_dates_filter_by_using_equal_operator":0.766,"P\\Tests\\Feature\\Requests\\Search\\GetSearchRequestTest::__pest_evaluable_it_can_search_documents_dates_filter_in_past":0.661,"P\\Tests\\Feature\\Requests\\Search\\GetSearchRequestTest::__pest_evaluable_it_can_search_documents":0.58,"P\\Tests\\Feature\\Requests\\Search\\GetSearchRequestTest::__pest_evaluable_it_can_search_documents_with_multiple_values":1.078,"P\\Tests\\Feature\\Requests\\Search\\GetSearchRequestTest::__pest_evaluable_it_can_search_documents_with_null_values":0.495,"P\\Tests\\Feature\\Requests\\Search\\GetSearchRequestTest::__pest_evaluable_it_can_override_search_documents_dates_filter_by_using_same_operator":0.617,"P\\Tests\\Feature\\Requests\\Search\\GetSearchRequestTest::__pest_evaluable_it_can_t_search_documents_by_more_than_two_dates":0.371,"P\\Tests\\Feature\\Requests\\Search\\GetSearchRequestTest::__pest_evaluable_it_can_search_documents_dates_filter_in_future":0.645,"P\\Tests\\Feature\\Requests\\Search\\GetSearchRequestTest::__pest_evaluable_it_can_t_search_documents_by_diverged_date_range":0.364,"P\\Tests\\Feature\\DocuWareTest::__pest_evaluable_it_can_create_encrypted_url_for_a_document_in_a_file_cabinet":0.424,"P\\Tests\\Feature\\DocuWareTest::__pest_evaluable_it_can_create_encrypted_url_for_a_document_in_a_basket":0.369,"P\\Tests\\Feature\\Requests\\General\\UserManagement\\GetModifyGroups\\GetAllGroupsForASpecificUserTest::__pest_evaluable_it_can_list_groups_for_a_specific_user":0.884,"P\\Tests\\Feature\\Requests\\FileCabinets\\Dialogs\\GetASpecificDialogTest::__pest_evaluable_it_can_get_a_dialog":0.555,"P\\Tests\\Feature\\Requests\\FileCabinets\\General\\GetFileCabinetInformationTest::__pest_evaluable_it_can_get_file_cabinet_information":0.63,"P\\Tests\\Feature\\DTOTest::__pest_evaluable_it_create_a_fake_organization_index":0.395,"P\\Tests\\Feature\\DTOTest::__pest_evaluable_it_create_a_fake_document":0.351,"P\\Tests\\Feature\\DTOTest::__pest_evaluable_it_create_a_fake_dialog":0.405,"P\\Tests\\Feature\\DTOTest::__pest_evaluable_it_create_a_fake_file_cabinet":0.352,"P\\Tests\\Feature\\DTOTest::__pest_evaluable_it_create_a_fake_field":0.336,"P\\Tests\\Feature\\DTOTest::__pest_evaluable_it_create_a_fake_document_field":0.34,"P\\Tests\\Feature\\DTOTest::__pest_evaluable_it_create_a_fake_table_row":0.352,"P\\Tests\\Feature\\DTOTest::__pest_evaluable_it_create_a_fake_suggestion_field":0.361,"P\\Tests\\Feature\\DTOTest::__pest_evaluable_it_create_a_fake_document_paginator":0.361,"P\\Tests\\Feature\\DTOTest::__pest_evaluable_it_create_a_fake_organization":0.346,"P\\Tests\\Unit\\DTO\\DocumentIndex\\IndexDateDTOTest::__pest_evaluable_it_create_index_date_dto":0.002,"P\\Tests\\Feature\\Requests\\General\\UserManagement\\GetModifyRoles\\GetRolesTest::__pest_evaluable_it_can_list_groups":0.494,"P\\Tests\\Feature\\Requests\\FileCabinets\\Search\\GetASpecificDocumentFromAFileCabinetTest::__pest_evaluable_it_can_show_a_document":0.666,"P\\Tests\\Feature\\Requests\\Documents\\DocumentsTrashBin\\RestoreDocumentsFromTrashBinTest::__pest_evaluable_it_can_restore_documents_in_trash":1.184,"P\\Tests\\Feature\\Requests\\Documents\\DocumentsTrashBin\\GetDocumentsFromTrashBinTest::__pest_evaluable_it_can_search_documents_dates_filter_in_past_in_trash":0.518,"P\\Tests\\Feature\\Requests\\Documents\\DocumentsTrashBin\\GetDocumentsFromTrashBinTest::__pest_evaluable_it_can_t_search_documents_by_more_than_two_dates_in_trash":0.331,"P\\Tests\\Feature\\Requests\\Documents\\DocumentsTrashBin\\GetDocumentsFromTrashBinTest::__pest_evaluable_it_can_override_search_documents_dates_filter_by_using_same_operator_in_trash":0.565,"P\\Tests\\Feature\\Requests\\Documents\\DocumentsTrashBin\\GetDocumentsFromTrashBinTest::__pest_evaluable_it_can_override_search_documents_dates_filter_by_using_equal_operator_in_trash":0.56,"P\\Tests\\Feature\\Requests\\Documents\\DocumentsTrashBin\\GetDocumentsFromTrashBinTest::__pest_evaluable_it_can_search_documents_in_trash":0.532,"P\\Tests\\Feature\\Requests\\Documents\\DocumentsTrashBin\\GetDocumentsFromTrashBinTest::__pest_evaluable_it_can_search_documents_with_null_values_in_trash":0.568,"P\\Tests\\Feature\\Requests\\Documents\\DocumentsTrashBin\\GetDocumentsFromTrashBinTest::__pest_evaluable_it_can_t_search_documents_by_diverged_date_range":0.364,"P\\Tests\\Feature\\Requests\\Documents\\DocumentsTrashBin\\GetDocumentsFromTrashBinTest::__pest_evaluable_it_can_search_documents_dates_filter_in_future_in_trash":0.51,"P\\Tests\\Feature\\Requests\\FileCabinets\\Upload\\ReplaceAPDFDocumentSectionTest::__pest_evaluable_it_can_replace_a_pdf_document_section":1.084,"P\\Tests\\Unit\\DTO\\DocumentIndex\\IndexKeywordDTOTest::__pest_evaluable_it_create_prepare_index_keyword_dto":0.001,"P\\Tests\\Feature\\Requests\\General\\UserManagement\\GetUsers\\GetUsersOfARoleTest::__pest_evaluable_it_can_list_users_of_a_role":0.649,"P\\Tests\\Feature\\DocuWareAuthenticationTest::__pest_evaluable_it_can_get_oath_responsible_identity_service":0.497,"P\\Tests\\Feature\\DocuWareAuthenticationTest::__pest_evaluable_it_throws_an_error_if_credentials_are_wrong":0.839,"P\\Tests\\Feature\\DocuWareAuthenticationTest::__pest_evaluable_it_can_authenticate_with_DocuWare_Credentials":0.48,"P\\Tests\\Feature\\DocuWareAuthenticationTest::__pest_evaluable_it_can_get_oath_identity_service_configuration":0.701,"P\\Tests\\Unit\\DTO\\DocumentIndex\\PrepareDTOTest::__pest_evaluable_it_create_prepare_makeContent_dto":0,"P\\Tests\\Feature\\Requests\\Documents\\Download\\DownloadThumbnailTest::__pest_evaluable_it_can_download_a_thumbnail":0.814,"P\\Tests\\Feature\\Requests\\Documents\\ClipUnclipStapleUnstaple\\StapleTest::__pest_evaluable_it_can_staple_2_documents":12.323,"P\\Tests\\Unit\\DTO\\DocumentIndex\\IndexDecimalDTOTest::__pest_evaluable_it_create_index_numeric_dto":0.001,"P\\Tests\\Feature\\Requests\\General\\UserManagement\\GetUsers\\GetUserByIdTest::__pest_evaluable_it_can_get_user_by_id":0.763,"P\\Tests\\Feature\\Requests\\General\\UserManagement\\GetModifyGroups\\GetGroupsTest::__pest_evaluable_it_can_list_groups":0.548,"P\\Tests\\Feature\\Requests\\Workflow\\GetDocumentWorkflowHistoryTest::__pest_evaluable_it_can_get_document_workflow_history":0.359,"P\\Tests\\Feature\\Requests\\General\\UserManagement\\GetModifyGroups\\AddRemoveUserToAGroupTest::__pest_evaluable_it_can_add_groups_to_a_user":7.947,"P\\Tests\\Feature\\Requests\\General\\UserManagement\\GetModifyGroups\\AddRemoveUserToAGroupTest::__pest_evaluable_it_can_remove_groups_to_a_user":5.958,"P\\Tests\\Feature\\Requests\\Documents\\PostDocumentRequestTest::__pest_evaluable_it_can_upload_document_without_file_name_and_file_content_and_delete_it":0.565,"P\\Tests\\Feature\\Requests\\Documents\\PostDocumentRequestTest::__pest_evaluable_it_can_upload_document_with_index_values_and_delete_it":0.633,"P\\Tests\\Unit\\DTO\\DocumentIndex\\IndexDateTimeDTOTest::__pest_evaluable_it_create_index_date_time_dto":0.001,"P\\Tests\\Core\\ArchTest::__pest_evaluable_it_will_not_use_any_debug_function":0.231,"P\\Tests\\Feature\\Requests\\Documents\\GetDocumentPreviewRequestTest::__pest_evaluable_it_can_preview_a_document_image":0.941,"P\\Tests\\Feature\\Requests\\Documents\\PutDocumentFieldsRequestTest::__pest_evaluable_it_can_update_a_document_value":0.679,"P\\Tests\\Feature\\Requests\\Documents\\PutDocumentFieldsRequestTest::__pest_evaluable_it_can_update_multiple_document_values":0.803,"P\\Tests\\Feature\\SleepTest::__pest_evaluable_sleep":0.339,"P\\Tests\\Feature\\Requests\\Documents\\ClipUnclipStapleUnstaple\\ClipTest::__pest_evaluable_it_can_clip_2_documents":6.624,"P\\Tests\\Feature\\Laravel12CacheCompatibilityTest::__pest_evaluable_cache_configuration_uses_CACHE__STORE_in_Laravel_12":0.003,"P\\Tests\\Feature\\Laravel12CacheCompatibilityTest::__pest_evaluable_cache_configuration_falls_back_to_CACHE__DRIVER_when_CACHE__STORE_is_not_set":0.425,"P\\Tests\\Feature\\Laravel12CacheCompatibilityTest::__pest_evaluable_cache_configuration_uses_DOCUWARE__CACHE__DRIVER_when_explicitly_set":0.876,"P\\Tests\\Feature\\Requests\\Documents\\Download\\DownloadDocumentTest::__pest_evaluable_it_can_download_a_document":0.705,"P\\Tests\\Feature\\Requests\\FileCabinets\\Upload\\AppendASinglePDFToADocumentTest::__pest_evaluable_it_can_replace_a_pdf_document_section":0.87,"P\\Tests\\Feature\\Requests\\General\\UserManagement\\CreateUpdateUsers\\CreateUpdateUserTest::__pest_evaluable_it_can_create_users":1.781,"P\\Tests\\Feature\\Requests\\General\\UserManagement\\CreateUpdateUsers\\CreateUpdateUserTest::__pest_evaluable_it_can_update_users":6.156,"P\\Tests\\Feature\\Requests\\FileCabinets\\Dialogs\\GetDialogsOfASpecificTypeTest::__pest_evaluable_it_can_list_dialogs_for_a_file_cabinet":0.523,"P\\Tests\\Feature\\Requests\\Documents\\ClipUnclipStapleUnstaple\\UnclipTest::__pest_evaluable_it_can_unclip_2_documents":12.165,"P\\Tests\\Feature\\Requests\\General\\UserManagement\\GetUsers\\GetUsersOfAGroupTest::__pest_evaluable_it_can_list_users_of_a_group":0.729,"P\\Tests\\Feature\\Requests\\Workflow\\GetDocumentWorkflowHistoryStepsTest::__pest_evaluable_it_can_get_document_workflow_history":0.354,"P\\Tests\\Feature\\Requests\\FileCabinets\\Search\\GetDocumentsFromAFileCabinetTest::__pest_evaluable_it_can_get_all_documents":0.876,"P\\Tests\\Feature\\Requests\\Documents\\Sections\\DeleteSectionTest::__pest_evaluable_it_can_delete_a_specific_section":0.825,"P\\Tests\\Feature\\Requests\\FileCabinets\\Upload\\AppendFilesToADataRecordTest::__pest_evaluable_it_can_attach_a_file_to_a_data_record":0.8,"P\\Tests\\Feature\\Requests\\FileCabinets\\Upload\\AppendFilesToADataRecordTest::__pest_evaluable_it_can_attach_files_to_a_data_record":0.353,"P\\Tests\\Feature\\Requests\\General\\UserManagement\\GetModifyRoles\\GetAllRolesForASpecificUserTest::__pest_evaluable_it_can_list_groups":0.78,"P\\Tests\\Feature\\Requests\\Documents\\Sections\\GetASpecificSectionTest::__pest_evaluable_it_can_get_a_specific_section":0.76,"P\\Tests\\Feature\\Requests\\Documents\\Thumbnail\\GetDocumentDownloadThumbnailRequestTest::__pest_evaluable_it_can_download_a_document_thumbnail":0.847,"P\\Tests\\Unit\\DTO\\DocumentIndex\\IndexNumericDTOTest::__pest_evaluable_it_create_index_numeric_dto":0,"P\\Tests\\Feature\\Requests\\General\\UserManagement\\GetModifyRoles\\AddRemoveUserToARoleTest::__pest_evaluable_it_can_add_roles_to_a_user":6.818,"P\\Tests\\Feature\\Requests\\General\\UserManagement\\GetModifyRoles\\AddRemoveUserToARoleTest::__pest_evaluable_it_can_remove_roles_to_a_user":5.917,"P\\Tests\\Feature\\Requests\\Documents\\Download\\DownloadSectionTest::__pest_evaluable_it_can_download_a_section":0.849,"P\\Tests\\Unit\\DTO\\DocumentIndex\\IndexTableDTOTest::__pest_evaluable_it_create_prepare_index_text_dto_using_dto":0.001,"P\\Tests\\Unit\\DTO\\DocumentIndex\\IndexTextDTOTest::__pest_evaluable_it_create_prepare_index_text_dto":0,"P\\Tests\\Unit\\DTO\\DocumentIndex\\IndexMemoDTOTest::__pest_evaluable_it_create_prepare_index_memo_dto":0,"P\\Tests\\Feature\\Requests\\Documents\\GetDocumentCountRequestTest::__pest_evaluable_it_can_get_a_total_count_of_documents":0.879,"Tests\\Unit\\DTO\\TextshotPageTest::test_it_can_create_textshot_page_with_null_language":0,"Tests\\Unit\\DTO\\TextshotPageTest::test_it_can_create_textshot_page_with_string_language":0.006,"Tests\\Unit\\DTO\\TextshotPageTest::test_it_can_create_textshot_page_with_empty_content":0,"P\\Tests\\Feature\\Laravel12CacheCompatibilityTest::__pest_evaluable_cache_configuration_uses_default_file_driver_when_no_configuration_is_set":0.361,"P\\Tests\\Feature\\Laravel12CacheCompatibilityTest::__pest_evaluable_cache_configuration_respects_the_new_CACHE__STORE_fallback_chain":0.008,"P\\Tests\\Feature\\Laravel12CacheCompatibilityTest::__pest_evaluable_environment_variable_fallback_chain_works_correctly":0.384,"P\\Tests\\Feature\\Laravel12CacheCompatibilityTest::__pest_evaluable_CACHE__STORE_takes_precedence_over_CACHE__DRIVER_when_DOCUWARE__CACHE__DRIVER_is_not_set":0.376,"P\\Tests\\Feature\\Laravel12CacheCompatibilityTest::__pest_evaluable_cache_configuration_can_be_overridden":0.037,"P\\Tests\\Feature\\Laravel12CacheCompatibilityTest::__pest_evaluable_cache_configuration_properly_loads_from_config":0.412,"P\\Tests\\Feature\\Laravel12CacheCompatibilityTest::__pest_evaluable_cache_configuration_fallback_chain_is_properly_configured":0.385}} \ No newline at end of file +{"version":"pest_3.8.4","defects":[],"times":{"P\\Tests\\Unit\\Enums\\DialogTypeTest::__pest_evaluable_it_can_try_to_create_enum_from_string_value":0.02,"P\\Tests\\Unit\\Enums\\DialogTypeTest::__pest_evaluable_it_throws_exception_for_invalid_enum_value":0,"P\\Tests\\Unit\\Enums\\DialogTypeTest::__pest_evaluable_it_can_create_enum_from_string_value":0,"P\\Tests\\Unit\\Enums\\DialogTypeTest::__pest_evaluable_it_can_get_string_value_from_enum":0,"P\\Tests\\Unit\\Enums\\DialogTypeTest::__pest_evaluable_it_has_all_expected_dialog_type_enum_cases":0,"P\\Tests\\Unit\\Enums\\ConnectionEnumTest::__pest_evaluable_it_throws_exception_for_invalid_enum_value":0,"P\\Tests\\Unit\\Enums\\ConnectionEnumTest::__pest_evaluable_it_has_all_expected_connection_enum_cases":0,"P\\Tests\\Unit\\Enums\\ConnectionEnumTest::__pest_evaluable_it_can_create_enum_from_string_value":0,"P\\Tests\\Unit\\Enums\\ConnectionEnumTest::__pest_evaluable_it_can_get_string_value_from_enum":0,"P\\Tests\\Unit\\Enums\\ConnectionEnumTest::__pest_evaluable_it_can_try_to_create_enum_from_string_value":0,"P\\Tests\\Unit\\Enums\\DocuWareFieldTypeEnumTest::__pest_evaluable_it_throws_exception_for_invalid_enum_value":0,"P\\Tests\\Unit\\Enums\\DocuWareFieldTypeEnumTest::__pest_evaluable_it_can_try_to_create_enum_from_string_value":0,"P\\Tests\\Unit\\Enums\\DocuWareFieldTypeEnumTest::__pest_evaluable_it_can_be_used_in_switch_statements":0,"P\\Tests\\Unit\\Enums\\DocuWareFieldTypeEnumTest::__pest_evaluable_it_can_create_enum_from_string_value":0,"P\\Tests\\Unit\\Enums\\DocuWareFieldTypeEnumTest::__pest_evaluable_it_can_get_string_value_from_enum":0,"P\\Tests\\Unit\\Enums\\DocuWareFieldTypeEnumTest::__pest_evaluable_it_has_all_expected_field_type_enum_cases":0}} \ No newline at end of file diff --git a/README.md b/README.md index 5e866513..a5440133 100644 --- a/README.md +++ b/README.md @@ -315,6 +315,52 @@ $connector = new DocuWareConnector( ); ``` +### Enums + +The package provides several enums to ensure type safety and consistency when working with DocuWare API values. + +#### ConnectionEnum + +Represents different connection types for DocuWare authentication: + +```php +use CodebarAg\DocuWare\Enums\ConnectionEnum; + +ConnectionEnum::WITHOUT_COOKIE; +ConnectionEnum::STATIC_COOKIE; +ConnectionEnum::DYNAMIC_COOKIE; +``` + +#### DialogType + +Represents different types of dialogs in DocuWare: + +```php +use CodebarAg\DocuWare\Enums\DialogType; + +DialogType::SEARCH; +DialogType::STORE; +DialogType::RESULT; +DialogType::INDEX; +DialogType::LIST; +DialogType::FOLDERS; +``` + +#### DocuWareFieldTypeEnum + +Represents different field types used in DocuWare document indexing: + +```php +use CodebarAg\DocuWare\Enums\DocuWareFieldTypeEnum; + +DocuWareFieldTypeEnum::STRING; +DocuWareFieldTypeEnum::INT; +DocuWareFieldTypeEnum::DECIMAL; +DocuWareFieldTypeEnum::DATE; +DocuWareFieldTypeEnum::DATETIME; +DocuWareFieldTypeEnum::TABLE; +``` + ### Available Requests The following sections provide examples for each available request type. All functionality is documented inline below with code examples. diff --git a/src/Enums/DocuWareFieldTypeEnum.php b/src/Enums/DocuWareFieldTypeEnum.php new file mode 100644 index 00000000..e3370d77 --- /dev/null +++ b/src/Enums/DocuWareFieldTypeEnum.php @@ -0,0 +1,13 @@ + $case->value, ConnectionEnum::cases()); + + expect($actualCases)->toBe($expectedCases); +}); + +it('can get string value from enum', function () { + expect(ConnectionEnum::WITHOUT_COOKIE->value)->toBe('WITHOUT_COOKIE'); + expect(ConnectionEnum::STATIC_COOKIE->value)->toBe('STATIC_COOKIE'); + expect(ConnectionEnum::DYNAMIC_COOKIE->value)->toBe('DYNAMIC_COOKIE'); +}); + +it('can create enum from string value', function () { + expect(ConnectionEnum::from('WITHOUT_COOKIE'))->toBe(ConnectionEnum::WITHOUT_COOKIE); + expect(ConnectionEnum::from('STATIC_COOKIE'))->toBe(ConnectionEnum::STATIC_COOKIE); + expect(ConnectionEnum::from('DYNAMIC_COOKIE'))->toBe(ConnectionEnum::DYNAMIC_COOKIE); +}); + +it('throws exception for invalid enum value', function () { + expect(fn () => ConnectionEnum::from('INVALID_VALUE')) + ->toThrow(ValueError::class); +}); + +it('can try to create enum from string value', function () { + expect(ConnectionEnum::tryFrom('WITHOUT_COOKIE'))->toBe(ConnectionEnum::WITHOUT_COOKIE); + expect(ConnectionEnum::tryFrom('INVALID_VALUE'))->toBeNull(); +}); diff --git a/tests/Unit/Enums/DialogTypeTest.php b/tests/Unit/Enums/DialogTypeTest.php new file mode 100644 index 00000000..7f5008b5 --- /dev/null +++ b/tests/Unit/Enums/DialogTypeTest.php @@ -0,0 +1,46 @@ + $case->value, DialogType::cases()); + + expect($actualCases)->toBe($expectedCases); +}); + +it('can get string value from enum', function () { + expect(DialogType::SEARCH->value)->toBe('Search'); + expect(DialogType::STORE->value)->toBe('Store'); + expect(DialogType::RESULT->value)->toBe('Result'); + expect(DialogType::INDEX->value)->toBe('Index'); + expect(DialogType::LIST->value)->toBe('List'); + expect(DialogType::FOLDERS->value)->toBe('Folders'); +}); + +it('can create enum from string value', function () { + expect(DialogType::from('Search'))->toBe(DialogType::SEARCH); + expect(DialogType::from('Store'))->toBe(DialogType::STORE); + expect(DialogType::from('Result'))->toBe(DialogType::RESULT); + expect(DialogType::from('Index'))->toBe(DialogType::INDEX); + expect(DialogType::from('List'))->toBe(DialogType::LIST); + expect(DialogType::from('Folders'))->toBe(DialogType::FOLDERS); +}); + +it('throws exception for invalid enum value', function () { + expect(fn () => DialogType::from('InvalidType')) + ->toThrow(ValueError::class); +}); + +it('can try to create enum from string value', function () { + expect(DialogType::tryFrom('Search'))->toBe(DialogType::SEARCH); + expect(DialogType::tryFrom('InvalidType'))->toBeNull(); +}); diff --git a/tests/Unit/Enums/DocuWareFieldTypeEnumTest.php b/tests/Unit/Enums/DocuWareFieldTypeEnumTest.php new file mode 100644 index 00000000..cadd5f2c --- /dev/null +++ b/tests/Unit/Enums/DocuWareFieldTypeEnumTest.php @@ -0,0 +1,61 @@ + $case->value, DocuWareFieldTypeEnum::cases()); + + expect($actualCases)->toBe($expectedCases); +}); + +it('can get string value from enum', function () { + expect(DocuWareFieldTypeEnum::STRING->value)->toBe('String'); + expect(DocuWareFieldTypeEnum::INT->value)->toBe('Int'); + expect(DocuWareFieldTypeEnum::DECIMAL->value)->toBe('Decimal'); + expect(DocuWareFieldTypeEnum::DATE->value)->toBe('Date'); + expect(DocuWareFieldTypeEnum::DATETIME->value)->toBe('DateTime'); + expect(DocuWareFieldTypeEnum::TABLE->value)->toBe('Table'); +}); + +it('can create enum from string value', function () { + expect(DocuWareFieldTypeEnum::from('String'))->toBe(DocuWareFieldTypeEnum::STRING); + expect(DocuWareFieldTypeEnum::from('Int'))->toBe(DocuWareFieldTypeEnum::INT); + expect(DocuWareFieldTypeEnum::from('Decimal'))->toBe(DocuWareFieldTypeEnum::DECIMAL); + expect(DocuWareFieldTypeEnum::from('Date'))->toBe(DocuWareFieldTypeEnum::DATE); + expect(DocuWareFieldTypeEnum::from('DateTime'))->toBe(DocuWareFieldTypeEnum::DATETIME); + expect(DocuWareFieldTypeEnum::from('Table'))->toBe(DocuWareFieldTypeEnum::TABLE); +}); + +it('throws exception for invalid enum value', function () { + expect(fn () => DocuWareFieldTypeEnum::from('InvalidType')) + ->toThrow(ValueError::class); +}); + +it('can try to create enum from string value', function () { + expect(DocuWareFieldTypeEnum::tryFrom('String'))->toBe(DocuWareFieldTypeEnum::STRING); + expect(DocuWareFieldTypeEnum::tryFrom('InvalidType'))->toBeNull(); +}); + +it('can be used in switch statements', function () { + $fieldType = DocuWareFieldTypeEnum::STRING; + + $result = match ($fieldType) { + DocuWareFieldTypeEnum::STRING => 'text field', + DocuWareFieldTypeEnum::INT => 'numeric field', + DocuWareFieldTypeEnum::DECIMAL => 'decimal field', + DocuWareFieldTypeEnum::DATE => 'date field', + DocuWareFieldTypeEnum::DATETIME => 'datetime field', + DocuWareFieldTypeEnum::TABLE => 'table field', + }; + + expect($result)->toBe('text field'); +}); From b96f386aefa8b73d390f79986f5f3c50439223e1 Mon Sep 17 00:00:00 2001 From: Sebastian Fix Date: Fri, 17 Oct 2025 16:03:58 +0200 Subject: [PATCH 03/30] Removed phpunit cache --- .gitignore | 1 + .phpunit.cache/test-results | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 .phpunit.cache/test-results diff --git a/.gitignore b/.gitignore index 2536343a..0d3a8e74 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ vendor node_modules .phpactor.json build +.phpunit.cache ## Annotations src/DTO/Documents/AnnotationsStamps/* diff --git a/.phpunit.cache/test-results b/.phpunit.cache/test-results deleted file mode 100644 index 7c94d9dd..00000000 --- a/.phpunit.cache/test-results +++ /dev/null @@ -1 +0,0 @@ -{"version":"pest_3.8.4","defects":[],"times":{"P\\Tests\\Unit\\Enums\\DialogTypeTest::__pest_evaluable_it_can_try_to_create_enum_from_string_value":0.02,"P\\Tests\\Unit\\Enums\\DialogTypeTest::__pest_evaluable_it_throws_exception_for_invalid_enum_value":0,"P\\Tests\\Unit\\Enums\\DialogTypeTest::__pest_evaluable_it_can_create_enum_from_string_value":0,"P\\Tests\\Unit\\Enums\\DialogTypeTest::__pest_evaluable_it_can_get_string_value_from_enum":0,"P\\Tests\\Unit\\Enums\\DialogTypeTest::__pest_evaluable_it_has_all_expected_dialog_type_enum_cases":0,"P\\Tests\\Unit\\Enums\\ConnectionEnumTest::__pest_evaluable_it_throws_exception_for_invalid_enum_value":0,"P\\Tests\\Unit\\Enums\\ConnectionEnumTest::__pest_evaluable_it_has_all_expected_connection_enum_cases":0,"P\\Tests\\Unit\\Enums\\ConnectionEnumTest::__pest_evaluable_it_can_create_enum_from_string_value":0,"P\\Tests\\Unit\\Enums\\ConnectionEnumTest::__pest_evaluable_it_can_get_string_value_from_enum":0,"P\\Tests\\Unit\\Enums\\ConnectionEnumTest::__pest_evaluable_it_can_try_to_create_enum_from_string_value":0,"P\\Tests\\Unit\\Enums\\DocuWareFieldTypeEnumTest::__pest_evaluable_it_throws_exception_for_invalid_enum_value":0,"P\\Tests\\Unit\\Enums\\DocuWareFieldTypeEnumTest::__pest_evaluable_it_can_try_to_create_enum_from_string_value":0,"P\\Tests\\Unit\\Enums\\DocuWareFieldTypeEnumTest::__pest_evaluable_it_can_be_used_in_switch_statements":0,"P\\Tests\\Unit\\Enums\\DocuWareFieldTypeEnumTest::__pest_evaluable_it_can_create_enum_from_string_value":0,"P\\Tests\\Unit\\Enums\\DocuWareFieldTypeEnumTest::__pest_evaluable_it_can_get_string_value_from_enum":0,"P\\Tests\\Unit\\Enums\\DocuWareFieldTypeEnumTest::__pest_evaluable_it_has_all_expected_field_type_enum_cases":0}} \ No newline at end of file From 30b8d829046fac0d438d8ebd3137dec39a909bfb Mon Sep 17 00:00:00 2001 From: Sebastian Fix Date: Fri, 17 Oct 2025 16:08:23 +0200 Subject: [PATCH 04/30] Resolved #188 --- .../UserManagement/GetUsers/OutOfOffice.php | 2 -- .../ModifyDocuments/TransferDocument.php | 31 ++++++++++++++----- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/DTO/General/UserManagement/GetUsers/OutOfOffice.php b/src/DTO/General/UserManagement/GetUsers/OutOfOffice.php index 2a5a356f..eab35494 100644 --- a/src/DTO/General/UserManagement/GetUsers/OutOfOffice.php +++ b/src/DTO/General/UserManagement/GetUsers/OutOfOffice.php @@ -12,14 +12,12 @@ public static function fromJson(array $data): self { if ($startDateTime = Arr::get($data, 'StartDateTime')) { $startDateTime = Str::of($startDateTime)->after('(')->before(')'); - // Extract milliseconds part (ignore optional timezone offset like +0000) $milliseconds = (int) (string) $startDateTime; $startDateTime = Carbon::createFromTimestampMs($milliseconds, 'UTC'); } if ($endDateTime = Arr::get($data, 'EndDateTime')) { $endDateTime = Str::of($endDateTime)->after('(')->before(')'); - // Extract milliseconds part (ignore optional timezone offset like +0000) $milliseconds = (int) (string) $endDateTime; $endDateTime = Carbon::createFromTimestampMs($milliseconds, 'UTC'); } diff --git a/src/Requests/Documents/ModifyDocuments/TransferDocument.php b/src/Requests/Documents/ModifyDocuments/TransferDocument.php index 3431ec5d..2ead5f51 100644 --- a/src/Requests/Documents/ModifyDocuments/TransferDocument.php +++ b/src/Requests/Documents/ModifyDocuments/TransferDocument.php @@ -2,7 +2,9 @@ namespace CodebarAg\DocuWare\Requests\Documents\ModifyDocuments; +use CodebarAg\DocuWare\DTO\Documents\DocumentIndex\PrepareDTO; use CodebarAg\DocuWare\Responses\Documents\ModifyDocuments\TransferDocumentResponse; +use Illuminate\Support\Collection; use Saloon\Contracts\Body\HasBody; use Saloon\Enums\Method; use Saloon\Http\Request; @@ -18,9 +20,12 @@ class TransferDocument extends Request implements HasBody public function __construct( protected readonly string $fileCabinetId, protected readonly string $destinationFileCabinetId, - protected readonly string $storeDialogId, protected readonly string $documentId, - protected readonly array $fields = [], + protected readonly ?string $storeDialogId = null, + protected readonly ?Collection $fields = null, + protected readonly bool $keepSource = false, + protected readonly bool $fillIntellix = false, + protected readonly bool $useDefaultDialog = false, ) {} public function resolveEndpoint(): string @@ -39,18 +44,30 @@ protected function defaultHeaders(): array protected function defaultBody(): array { - return [ + $body = [ 'SourceFileCabinetId' => $this->fileCabinetId, 'Documents' => [ [ 'Id' => $this->documentId, - 'Fields' => $this->fields, ], ], - 'KeepSource' => false, - 'FillIntellix' => false, - 'UseDefaultDialog' => false, + 'KeepSource' => $this->keepSource, + 'FillIntellix' => $this->fillIntellix, + 'UseDefaultDialog' => $this->useDefaultDialog, ]; + + // Add storeDialogId if provided + if ($this->storeDialogId) { + $body['StoreDialogId'] = $this->storeDialogId; + } + + // Add fields if provided + if ($this->fields) { + $fieldData = PrepareDTO::makeField($this->fields); + $body['Documents'][0]['Fields'] = $fieldData['Field']; + } + + return $body; } public function createDtoFromResponse(Response $response): bool From fd4e1cfa35d6e3ef16d5c8e747ff5fc3434601d1 Mon Sep 17 00:00:00 2001 From: Sebastian Fix Date: Fri, 17 Oct 2025 16:09:00 +0200 Subject: [PATCH 05/30] wip --- src/Requests/Documents/ModifyDocuments/TransferDocument.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Requests/Documents/ModifyDocuments/TransferDocument.php b/src/Requests/Documents/ModifyDocuments/TransferDocument.php index 2ead5f51..4ac99aec 100644 --- a/src/Requests/Documents/ModifyDocuments/TransferDocument.php +++ b/src/Requests/Documents/ModifyDocuments/TransferDocument.php @@ -56,12 +56,10 @@ protected function defaultBody(): array 'UseDefaultDialog' => $this->useDefaultDialog, ]; - // Add storeDialogId if provided if ($this->storeDialogId) { $body['StoreDialogId'] = $this->storeDialogId; } - // Add fields if provided if ($this->fields) { $fieldData = PrepareDTO::makeField($this->fields); $body['Documents'][0]['Fields'] = $fieldData['Field']; From d8c2a1af7e5b6342a7df169c38e1637fa67255fa Mon Sep 17 00:00:00 2001 From: Sebastian Fix Date: Fri, 17 Oct 2025 16:10:29 +0200 Subject: [PATCH 06/30] Minor code improvements --- src/DTO/General/UserManagement/GetUsers/OutOfOffice.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/DTO/General/UserManagement/GetUsers/OutOfOffice.php b/src/DTO/General/UserManagement/GetUsers/OutOfOffice.php index eab35494..282ae282 100644 --- a/src/DTO/General/UserManagement/GetUsers/OutOfOffice.php +++ b/src/DTO/General/UserManagement/GetUsers/OutOfOffice.php @@ -10,13 +10,17 @@ final class OutOfOffice { public static function fromJson(array $data): self { - if ($startDateTime = Arr::get($data, 'StartDateTime')) { + $startDateTime = Arr::get($data, 'StartDateTime'); + + if (filled($startDateTime)) { $startDateTime = Str::of($startDateTime)->after('(')->before(')'); $milliseconds = (int) (string) $startDateTime; $startDateTime = Carbon::createFromTimestampMs($milliseconds, 'UTC'); } - if ($endDateTime = Arr::get($data, 'EndDateTime')) { + $endDateTime = Arr::get($data, 'EndDateTime'); + + if (filled($endDateTime)) { $endDateTime = Str::of($endDateTime)->after('(')->before(')'); $milliseconds = (int) (string) $endDateTime; $endDateTime = Carbon::createFromTimestampMs($milliseconds, 'UTC'); From 56b872e7bca4849ba3e590384c2c7fcd1e1cc60e Mon Sep 17 00:00:00 2001 From: Sebastian Fix Date: Fri, 17 Oct 2025 16:17:28 +0200 Subject: [PATCH 07/30] Improved TransferDocument Request --- .../UserManagement/GetUsers/OutOfOffice.php | 8 +++++--- .../ModifyDocuments/TransferDocument.php | 19 +++++++++---------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/DTO/General/UserManagement/GetUsers/OutOfOffice.php b/src/DTO/General/UserManagement/GetUsers/OutOfOffice.php index 282ae282..8aeb77a4 100644 --- a/src/DTO/General/UserManagement/GetUsers/OutOfOffice.php +++ b/src/DTO/General/UserManagement/GetUsers/OutOfOffice.php @@ -12,10 +12,12 @@ public static function fromJson(array $data): self { $startDateTime = Arr::get($data, 'StartDateTime'); + $timeZone = config('app.timezone', 'UTC'); + if (filled($startDateTime)) { $startDateTime = Str::of($startDateTime)->after('(')->before(')'); $milliseconds = (int) (string) $startDateTime; - $startDateTime = Carbon::createFromTimestampMs($milliseconds, 'UTC'); + $startDateTime = Carbon::createFromTimestampMs($milliseconds, $timeZone); } $endDateTime = Arr::get($data, 'EndDateTime'); @@ -23,7 +25,7 @@ public static function fromJson(array $data): self if (filled($endDateTime)) { $endDateTime = Str::of($endDateTime)->after('(')->before(')'); $milliseconds = (int) (string) $endDateTime; - $endDateTime = Carbon::createFromTimestampMs($milliseconds, 'UTC'); + $endDateTime = Carbon::createFromTimestampMs($milliseconds, $timeZone); } return new self( @@ -31,7 +33,7 @@ public static function fromJson(array $data): self startDateTime: $startDateTime, startDateTimeSpecified: Arr::get($data, 'StartDateTimeSpecified'), endDateTime: $endDateTime, - endDateTimeSpecified: Arr::get($data, key: 'EndDateTimeSpecified'), + endDateTimeSpecified: Arr::get($data, 'EndDateTimeSpecified'), ); } diff --git a/src/Requests/Documents/ModifyDocuments/TransferDocument.php b/src/Requests/Documents/ModifyDocuments/TransferDocument.php index 4ac99aec..b80a2a96 100644 --- a/src/Requests/Documents/ModifyDocuments/TransferDocument.php +++ b/src/Requests/Documents/ModifyDocuments/TransferDocument.php @@ -2,6 +2,7 @@ namespace CodebarAg\DocuWare\Requests\Documents\ModifyDocuments; +use Arr; use CodebarAg\DocuWare\DTO\Documents\DocumentIndex\PrepareDTO; use CodebarAg\DocuWare\Responses\Documents\ModifyDocuments\TransferDocumentResponse; use Illuminate\Support\Collection; @@ -30,7 +31,13 @@ public function __construct( public function resolveEndpoint(): string { - return '/FileCabinets/'.$this->destinationFileCabinetId.'/Task/Transfer'; + $endpoint = '/FileCabinets/'.$this->destinationFileCabinetId.'/Task/Transfer'; + + if ($this->storeDialogId) { + $endpoint .= '?StoreDialogId='.$this->storeDialogId; + } + + return $endpoint; } protected function defaultHeaders(): array @@ -49,6 +56,7 @@ protected function defaultBody(): array 'Documents' => [ [ 'Id' => $this->documentId, + 'Fields' => $this->fields ? Arr::get(PrepareDTO::makeField($this->fields), 'Field') : null, ], ], 'KeepSource' => $this->keepSource, @@ -56,15 +64,6 @@ protected function defaultBody(): array 'UseDefaultDialog' => $this->useDefaultDialog, ]; - if ($this->storeDialogId) { - $body['StoreDialogId'] = $this->storeDialogId; - } - - if ($this->fields) { - $fieldData = PrepareDTO::makeField($this->fields); - $body['Documents'][0]['Fields'] = $fieldData['Field']; - } - return $body; } From 9de480befc4c7f45be8c9bf4edfd812033e413a5 Mon Sep 17 00:00:00 2001 From: Sebastian Fix Date: Fri, 20 Mar 2026 06:58:06 +0100 Subject: [PATCH 08/30] Security updates --- .github/dependabot.yml | 40 ++++++++++++++++++++++++------ CONTRIBUTING.md | 55 ++++++++++++++++++++++++++++++++++++++++++ SECURITY.md | 3 +++ 3 files changed, 91 insertions(+), 7 deletions(-) create mode 100644 CONTRIBUTING.md create mode 100644 SECURITY.md diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 30c8a493..9ac6a658 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,12 +1,38 @@ -# Please see the documentation for all configuration options: -# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates - version: 2 updates: - - package-ecosystem: "github-actions" directory: "/" schedule: - interval: "weekly" - labels: - - "dependencies" \ No newline at end of file + interval: "daily" + ignore: + - dependency-name: "*" + update-types: [ "version-update:semver-major" ] + groups: + minor-and-patch: + update-types: [ "minor", "patch" ] + + - package-ecosystem: "npm" + directory: "/" + schedule: + interval: "daily" + allow: + - dependency-type: "direct" + ignore: + - dependency-name: "*" + update-types: [ "version-update:semver-major" ] + groups: + minor-and-patch: + update-types: [ "minor", "patch" ] + + - package-ecosystem: "composer" + directory: "/" + schedule: + interval: "daily" + allow: + - dependency-type: "direct" + ignore: + - dependency-name: "*" + update-types: [ "version-update:semver-major" ] + groups: + minor-and-patch: + update-types: [ "minor", "patch" ] diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..b4ae1c4a --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,55 @@ +# Contributing + +Contributions are **welcome** and will be fully **credited**. + +Please read and understand the contribution guide before creating an issue or pull request. + +## Etiquette + +This project is open source, and as such, the maintainers give their free time to build and maintain the source code +held within. They make the code freely available in the hope that it will be of use to other developers. It would be +extremely unfair for them to suffer abuse or anger for their hard work. + +Please be considerate towards maintainers when raising issues or presenting pull requests. Let's show the +world that developers are civilized and selfless people. + +It's the duty of the maintainer to ensure that all submissions to the project are of sufficient +quality to benefit the project. Many developers have different skillsets, strengths, and weaknesses. Respect the maintainer's decision, and do not be upset or abusive if your submission is not used. + +## Viability + +When requesting or submitting new features, first consider whether it might be useful to others. Open +source projects are used by many developers, who may have entirely different needs to your own. Think about +whether or not your feature is likely to be used by other users of the project. + +## Procedure + +Before filing an issue: + +- Attempt to replicate the problem, to ensure that it wasn't a coincidental incident. +- Check to make sure your feature suggestion isn't already present within the project. +- Check the pull requests tab to ensure that the bug doesn't have a fix in progress. +- Check the pull requests tab to ensure that the feature isn't already in progress. + +Before submitting a pull request: + +- Check the codebase to ensure that your feature doesn't already exist. +- Check the pull requests to ensure that another person hasn't already submitted the feature or fix. + +## Requirements + +If the project maintainer has any additional requirements, you will find them listed here. + +- **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - The easiest way to apply the conventions is to install [PHP Code Sniffer](https://pear.php.net/package/PHP_CodeSniffer). + +- **Add tests!** - Your patch won't be accepted if it doesn't have tests. + +- **Document any change in behaviour** - Make sure the `README.md` and any other relevant documentation are kept up-to-date. + +- **Consider our release cycle** - We try to follow [SemVer v2.0.0](https://semver.org/). Randomly breaking public APIs is not an option. + +- **One pull request per feature** - If you want to do more than one thing, send multiple pull requests. + +- **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please [squash them](https://www.git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Changing-Multiple-Commit-Messages) before submitting. + +**Happy coding**! diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..dd923a21 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,3 @@ +# Security Policy + +If you discover any security related issues, please email info@codebar.ch instead of using the issue tracker. From ddae347c38ccd4dd7dd76ed68fb4ced7669c8657 Mon Sep 17 00:00:00 2001 From: Sebastian Fix Date: Fri, 20 Mar 2026 07:39:21 +0100 Subject: [PATCH 09/30] Optimized Repository Skeleton --- .github/workflows/dependabot-auto-merge.yml | 2 +- .github/workflows/dependency-review.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/dependabot-auto-merge.yml b/.github/workflows/dependabot-auto-merge.yml index a3368d2d..5bfa1ad9 100644 --- a/.github/workflows/dependabot-auto-merge.yml +++ b/.github/workflows/dependabot-auto-merge.yml @@ -13,7 +13,7 @@ jobs: - name: Dependabot metadata id: metadata - uses: dependabot/fetch-metadata@v2.4.0 + uses: dependabot/fetch-metadata@v2.5.0 with: github-token: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index 046e9c88..3ea91b44 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -15,6 +15,6 @@ jobs: runs-on: ubuntu-latest steps: - name: 'Checkout Repository' - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: 'Dependency Review' uses: actions/dependency-review-action@v4 From 72a9de08f2637f057b1b680fee7a5e5310dba2ab Mon Sep 17 00:00:00 2001 From: Sebastian Fix Date: Fri, 20 Mar 2026 08:23:42 +0100 Subject: [PATCH 10/30] chore: sync Laravel Pint workflow from template --- .github/workflows/fix-php-code-style-issues.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/fix-php-code-style-issues.yml b/.github/workflows/fix-php-code-style-issues.yml index 768197d9..9ed9047d 100644 --- a/.github/workflows/fix-php-code-style-issues.yml +++ b/.github/workflows/fix-php-code-style-issues.yml @@ -2,20 +2,21 @@ name: Fix PHP code style issues on: [push] +permissions: + contents: write + jobs: php-code-styling: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v5 - with: - ref: ${{ github.head_ref }} + uses: actions/checkout@v6.0.2 - name: Fix PHP code style issues uses: aglipanci/laravel-pint-action@2.6 - name: Commit changes - uses: stefanzweifel/git-auto-commit-action@v7 + uses: stefanzweifel/git-auto-commit-action@v6.0.1 with: commit_message: Fix styling From 81ff18048a9549404209964d4f2063a371815acc Mon Sep 17 00:00:00 2001 From: Sebastian Fix Date: Fri, 20 Mar 2026 08:34:56 +0100 Subject: [PATCH 11/30] chore: sync CONTRIBUTING.md from template --- .github/CONTRIBUTING.md | 2 +- CONTRIBUTING.md | 55 ----------------------------------------- 2 files changed, 1 insertion(+), 56 deletions(-) delete mode 100644 CONTRIBUTING.md diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index b4ae1c4a..3f687e93 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -40,7 +40,7 @@ Before submitting a pull request: If the project maintainer has any additional requirements, you will find them listed here. -- **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - The easiest way to apply the conventions is to install [PHP Code Sniffer](https://pear.php.net/package/PHP_CodeSniffer). +- **[Laravel Pint](https://github.com/laravel/pint)** - PHP style is enforced with Pint (PSR-12–oriented, via PHP-CS-Fixer). Run `composer install`, then `./vendor/bin/pint` before pushing (`composer run format` instead if your package defines that script). The **Fix PHP code style issues** GitHub Action also runs on push and may commit formatting fixes. - **Add tests!** - Your patch won't be accepted if it doesn't have tests. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index b4ae1c4a..00000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,55 +0,0 @@ -# Contributing - -Contributions are **welcome** and will be fully **credited**. - -Please read and understand the contribution guide before creating an issue or pull request. - -## Etiquette - -This project is open source, and as such, the maintainers give their free time to build and maintain the source code -held within. They make the code freely available in the hope that it will be of use to other developers. It would be -extremely unfair for them to suffer abuse or anger for their hard work. - -Please be considerate towards maintainers when raising issues or presenting pull requests. Let's show the -world that developers are civilized and selfless people. - -It's the duty of the maintainer to ensure that all submissions to the project are of sufficient -quality to benefit the project. Many developers have different skillsets, strengths, and weaknesses. Respect the maintainer's decision, and do not be upset or abusive if your submission is not used. - -## Viability - -When requesting or submitting new features, first consider whether it might be useful to others. Open -source projects are used by many developers, who may have entirely different needs to your own. Think about -whether or not your feature is likely to be used by other users of the project. - -## Procedure - -Before filing an issue: - -- Attempt to replicate the problem, to ensure that it wasn't a coincidental incident. -- Check to make sure your feature suggestion isn't already present within the project. -- Check the pull requests tab to ensure that the bug doesn't have a fix in progress. -- Check the pull requests tab to ensure that the feature isn't already in progress. - -Before submitting a pull request: - -- Check the codebase to ensure that your feature doesn't already exist. -- Check the pull requests to ensure that another person hasn't already submitted the feature or fix. - -## Requirements - -If the project maintainer has any additional requirements, you will find them listed here. - -- **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - The easiest way to apply the conventions is to install [PHP Code Sniffer](https://pear.php.net/package/PHP_CodeSniffer). - -- **Add tests!** - Your patch won't be accepted if it doesn't have tests. - -- **Document any change in behaviour** - Make sure the `README.md` and any other relevant documentation are kept up-to-date. - -- **Consider our release cycle** - We try to follow [SemVer v2.0.0](https://semver.org/). Randomly breaking public APIs is not an option. - -- **One pull request per feature** - If you want to do more than one thing, send multiple pull requests. - -- **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please [squash them](https://www.git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Changing-Multiple-Commit-Messages) before submitting. - -**Happy coding**! From 928c56ccdb568fe2f47c4e99b90651d44579257c Mon Sep 17 00:00:00 2001 From: Sebastian Fix Date: Fri, 20 Mar 2026 08:34:57 +0100 Subject: [PATCH 12/30] chore: sync security policy from template --- SECURITY.md | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md deleted file mode 100644 index dd923a21..00000000 --- a/SECURITY.md +++ /dev/null @@ -1,3 +0,0 @@ -# Security Policy - -If you discover any security related issues, please email info@codebar.ch instead of using the issue tracker. From 61ccea0207fe090ab89e964675e6c0a9e2e4187c Mon Sep 17 00:00:00 2001 From: Sebastian Fix Date: Sat, 21 Mar 2026 07:58:03 +0100 Subject: [PATCH 13/30] chore: sync PHPStan workflow from template --- .github/workflows/phpstan.yml | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml index 4fcc1697..10e8b37c 100644 --- a/.github/workflows/phpstan.yml +++ b/.github/workflows/phpstan.yml @@ -1,13 +1,33 @@ name: PHPStan -on: [push] +on: + push: + paths: + - '**/*.php' + - 'phpstan.neon.dist' + - 'phpstan-baseline.neon' + - 'composer.json' + - 'composer.lock' + pull_request: + paths: + - '**/*.php' + - 'phpstan.neon.dist' + - 'phpstan-baseline.neon' + - 'composer.json' + - 'composer.lock' + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: phpstan: name: phpstan runs-on: ubuntu-latest + timeout-minutes: 5 steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6.0.2 - name: Setup PHP uses: shivammathur/setup-php@v2 @@ -16,7 +36,7 @@ jobs: coverage: none - name: Install composer dependencies - uses: ramsey/composer-install@v3 + uses: ramsey/composer-install@v4 - name: Run PHPStan run: ./vendor/bin/phpstan --error-format=github From 6661fd2bfb4d3972ada5f8cc473613a43faf445e Mon Sep 17 00:00:00 2001 From: Sebastian Fix Date: Sat, 21 Mar 2026 08:07:15 +0100 Subject: [PATCH 14/30] chore: sync Laravel Pint workflow from template --- .github/workflows/fix-php-code-style-issues.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/fix-php-code-style-issues.yml b/.github/workflows/fix-php-code-style-issues.yml index 9ed9047d..1c4e562f 100644 --- a/.github/workflows/fix-php-code-style-issues.yml +++ b/.github/workflows/fix-php-code-style-issues.yml @@ -17,6 +17,6 @@ jobs: uses: aglipanci/laravel-pint-action@2.6 - name: Commit changes - uses: stefanzweifel/git-auto-commit-action@v6.0.1 + uses: stefanzweifel/git-auto-commit-action@v7 with: commit_message: Fix styling From 8720eafb1c408f09e8a8b56bd911ebb31bf118ba Mon Sep 17 00:00:00 2001 From: Sebastian Fix Date: Sat, 21 Mar 2026 08:09:44 +0100 Subject: [PATCH 15/30] chore: sync Dependabot config and workflows from template --- .github/workflows/dependency-review.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index 3ea91b44..b45940f0 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -15,6 +15,6 @@ jobs: runs-on: ubuntu-latest steps: - name: 'Checkout Repository' - uses: actions/checkout@v6 + uses: actions/checkout@v6.0.2 - name: 'Dependency Review' - uses: actions/dependency-review-action@v4 + uses: actions/dependency-review-action@v4.9.0 From 6ca012bfcdd8bb3f6de665834c826bf2793c8c28 Mon Sep 17 00:00:00 2001 From: Sebastian Fix Date: Sat, 21 Mar 2026 08:09:47 +0100 Subject: [PATCH 16/30] chore: sync Laravel Pint workflow from template --- .github/workflows/fix-php-code-style-issues.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/fix-php-code-style-issues.yml b/.github/workflows/fix-php-code-style-issues.yml index 1c4e562f..41e61934 100644 --- a/.github/workflows/fix-php-code-style-issues.yml +++ b/.github/workflows/fix-php-code-style-issues.yml @@ -17,6 +17,6 @@ jobs: uses: aglipanci/laravel-pint-action@2.6 - name: Commit changes - uses: stefanzweifel/git-auto-commit-action@v7 + uses: stefanzweifel/git-auto-commit-action@v7.1.0 with: commit_message: Fix styling From 8a79d8b0cf4da4dd699363ba2175176f3ec4955e Mon Sep 17 00:00:00 2001 From: Sebastian Fix Date: Sat, 21 Mar 2026 08:09:54 +0100 Subject: [PATCH 17/30] chore: sync PHPStan workflow from template --- .github/workflows/phpstan.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml index 10e8b37c..18023123 100644 --- a/.github/workflows/phpstan.yml +++ b/.github/workflows/phpstan.yml @@ -30,13 +30,13 @@ jobs: - uses: actions/checkout@v6.0.2 - name: Setup PHP - uses: shivammathur/setup-php@v2 + uses: shivammathur/setup-php@2.37.0 with: php-version: '8.4' coverage: none - name: Install composer dependencies - uses: ramsey/composer-install@v4 + uses: ramsey/composer-install@4.0.0 - name: Run PHPStan run: ./vendor/bin/phpstan --error-format=github From b5271921a9184a74ddf64c8a49f9e7e6bbb919dc Mon Sep 17 00:00:00 2001 From: Sebastian Fix Date: Sat, 21 Mar 2026 08:09:55 +0100 Subject: [PATCH 18/30] chore: sync release workflow from template --- .github/workflows/release.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a4b057b7..c95e4148 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -10,12 +10,13 @@ jobs: release: name: Release runs-on: ubuntu-latest + timeout-minutes: 10 steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6.0.2 with: fetch-depth: '0' - name: Bump version and push tag - uses: anothrNick/github-tag-action@master + uses: anothrNick/github-tag-action@1.75.0 env: GITHUB_TOKEN: ${{ secrets.MY_GITHUB_TOKEN }} WITH_V: true From aff5617532fcc1e036d680c2465f9327fc73e937 Mon Sep 17 00:00:00 2001 From: Sebastian Fix Date: Sat, 21 Mar 2026 08:50:33 +0100 Subject: [PATCH 19/30] chore: sync CONTRIBUTING.md from template --- CONTRIBUTING.md | 55 ------------------------------------------------- 1 file changed, 55 deletions(-) delete mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index b4ae1c4a..00000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,55 +0,0 @@ -# Contributing - -Contributions are **welcome** and will be fully **credited**. - -Please read and understand the contribution guide before creating an issue or pull request. - -## Etiquette - -This project is open source, and as such, the maintainers give their free time to build and maintain the source code -held within. They make the code freely available in the hope that it will be of use to other developers. It would be -extremely unfair for them to suffer abuse or anger for their hard work. - -Please be considerate towards maintainers when raising issues or presenting pull requests. Let's show the -world that developers are civilized and selfless people. - -It's the duty of the maintainer to ensure that all submissions to the project are of sufficient -quality to benefit the project. Many developers have different skillsets, strengths, and weaknesses. Respect the maintainer's decision, and do not be upset or abusive if your submission is not used. - -## Viability - -When requesting or submitting new features, first consider whether it might be useful to others. Open -source projects are used by many developers, who may have entirely different needs to your own. Think about -whether or not your feature is likely to be used by other users of the project. - -## Procedure - -Before filing an issue: - -- Attempt to replicate the problem, to ensure that it wasn't a coincidental incident. -- Check to make sure your feature suggestion isn't already present within the project. -- Check the pull requests tab to ensure that the bug doesn't have a fix in progress. -- Check the pull requests tab to ensure that the feature isn't already in progress. - -Before submitting a pull request: - -- Check the codebase to ensure that your feature doesn't already exist. -- Check the pull requests to ensure that another person hasn't already submitted the feature or fix. - -## Requirements - -If the project maintainer has any additional requirements, you will find them listed here. - -- **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - The easiest way to apply the conventions is to install [PHP Code Sniffer](https://pear.php.net/package/PHP_CodeSniffer). - -- **Add tests!** - Your patch won't be accepted if it doesn't have tests. - -- **Document any change in behaviour** - Make sure the `README.md` and any other relevant documentation are kept up-to-date. - -- **Consider our release cycle** - We try to follow [SemVer v2.0.0](https://semver.org/). Randomly breaking public APIs is not an option. - -- **One pull request per feature** - If you want to do more than one thing, send multiple pull requests. - -- **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please [squash them](https://www.git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Changing-Multiple-Commit-Messages) before submitting. - -**Happy coding**! From 4fe66131d239c78955313dd37b46339571f8a47c Mon Sep 17 00:00:00 2001 From: Sebastian Fix Date: Sat, 21 Mar 2026 08:50:34 +0100 Subject: [PATCH 20/30] chore: sync security policy from template --- SECURITY.md | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md deleted file mode 100644 index dd923a21..00000000 --- a/SECURITY.md +++ /dev/null @@ -1,3 +0,0 @@ -# Security Policy - -If you discover any security related issues, please email info@codebar.ch instead of using the issue tracker. From 43984b58f12f571b412d5100186d7c62adbe4ff2 Mon Sep 17 00:00:00 2001 From: Sebastian Fix Date: Thu, 26 Mar 2026 06:59:25 +0100 Subject: [PATCH 21/30] Optimized Repository Skeleton --- composer.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/composer.json b/composer.json index 9aa3cd0b..c637e7ce 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,7 @@ "authors": [ { "name": "Sebastian Bürgin-Fix", - "email": "sebastian.buergin@buergin.ch", + "email": "helpdesk@codebar.ch", "homepage": "https://www.codebar.ch", "role": "Software-Engineer" } @@ -25,9 +25,9 @@ "guzzlehttp/guzzle": "^7.8", "illuminate/contracts": "^12.0", "nesbot/carbon": "^3.8", - "saloonphp/cache-plugin": "^3.0", - "saloonphp/laravel-plugin": "^3.5", - "saloonphp/saloon": "^3.10.1", + "saloonphp/cache-plugin": "^3.1", + "saloonphp/laravel-plugin": "^4.0", + "saloonphp/saloon": "^4.0", "spatie/laravel-package-tools": "^1.19" }, "require-dev": { From a9fbe3128f04b19fd2597b22212a660496ea3fe2 Mon Sep 17 00:00:00 2001 From: Sebastian Fix Date: Thu, 26 Mar 2026 07:56:45 +0100 Subject: [PATCH 22/30] Optimized Repository Skeleton --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index c637e7ce..409fc869 100644 --- a/composer.json +++ b/composer.json @@ -26,8 +26,8 @@ "illuminate/contracts": "^12.0", "nesbot/carbon": "^3.8", "saloonphp/cache-plugin": "^3.1", - "saloonphp/laravel-plugin": "^4.0", - "saloonphp/saloon": "^4.0", + "saloonphp/laravel-plugin": "^3.0|^4.0", + "saloonphp/saloon": "^3.0|^4.0", "spatie/laravel-package-tools": "^1.19" }, "require-dev": { From 74c8e09df0de4057b611bcdbeeedddd7e01c2e7d Mon Sep 17 00:00:00 2001 From: Sebastian Fix Date: Thu, 26 Mar 2026 08:13:26 +0100 Subject: [PATCH 23/30] chore: sync dependency audit workflows from template --- .github/workflows/composer-audit.yml | 37 ++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 .github/workflows/composer-audit.yml diff --git a/.github/workflows/composer-audit.yml b/.github/workflows/composer-audit.yml new file mode 100644 index 00000000..ed5c5478 --- /dev/null +++ b/.github/workflows/composer-audit.yml @@ -0,0 +1,37 @@ +name: Composer audit + +on: + push: + paths: + - 'composer.json' + - 'composer.lock' + pull_request: + paths: + - 'composer.json' + - 'composer.lock' + schedule: + - cron: '0 6 * * 1' + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + composer-audit: + name: composer audit + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: actions/checkout@v6.0.2 + + - name: Setup PHP + uses: shivammathur/setup-php@2.37.0 + with: + php-version: '8.4' + coverage: none + + - name: Resolve dependencies and audit + run: | + composer update --no-interaction --no-ansi + composer audit From 62b59c311faa94e608acf62a375812e544385d4a Mon Sep 17 00:00:00 2001 From: Sebastian Fix Date: Fri, 3 Apr 2026 15:11:35 +0200 Subject: [PATCH 24/30] chore: sync GitHub issue templates --- .github/ISSUE_TEMPLATE/bug_report.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index bc5e177e..c8596fba 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -29,8 +29,8 @@ We're sorry to hear you have a problem. Can you help us solve it by providing th attributes: label: PHP Version description: What version of PHP are you running? Please be as specific as possible - placeholder: "8.4.0" - value: "8.4.0" + placeholder: "8.5.0" + value: "8.5.0" validations: required: true - type: input @@ -38,8 +38,8 @@ We're sorry to hear you have a problem. Can you help us solve it by providing th attributes: label: Laravel Version description: What version of Laravel are you running? Please be as specific as possible - placeholder: "12.0.0" - value: "12.0.0" + placeholder: "13.0.0" + value: "13.0.0" validations: required: true - type: dropdown From 7209cf881777dd40fb40f6e23ea3d65a4c91a493 Mon Sep 17 00:00:00 2001 From: Sebastian Fix Date: Fri, 3 Apr 2026 15:11:38 +0200 Subject: [PATCH 25/30] chore: sync Laravel Pint workflow from template --- .github/workflows/fix-php-code-style-issues.yml | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/.github/workflows/fix-php-code-style-issues.yml b/.github/workflows/fix-php-code-style-issues.yml index 41e61934..14165467 100644 --- a/.github/workflows/fix-php-code-style-issues.yml +++ b/.github/workflows/fix-php-code-style-issues.yml @@ -13,8 +13,17 @@ jobs: - name: Checkout code uses: actions/checkout@v6.0.2 - - name: Fix PHP code style issues - uses: aglipanci/laravel-pint-action@2.6 + - name: Setup PHP + uses: shivammathur/setup-php@2.37.0 + with: + php-version: '8.5' + coverage: none + + - name: Install composer dependencies + uses: ramsey/composer-install@4.0.0 + + - name: Run Laravel Pint + run: vendor/bin/pint - name: Commit changes uses: stefanzweifel/git-auto-commit-action@v7.1.0 From e7a27df4763953fad69dbe24b597e64bfb457f85 Mon Sep 17 00:00:00 2001 From: Sebastian Fix Date: Fri, 3 Apr 2026 15:11:44 +0200 Subject: [PATCH 26/30] chore: sync PHPStan workflow from template --- .github/workflows/phpstan.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml index 18023123..5bbb64c8 100644 --- a/.github/workflows/phpstan.yml +++ b/.github/workflows/phpstan.yml @@ -32,7 +32,7 @@ jobs: - name: Setup PHP uses: shivammathur/setup-php@2.37.0 with: - php-version: '8.4' + php-version: '8.5' coverage: none - name: Install composer dependencies From 9a02f11bf3b1afc80b90d2c9a97f00a47d6b1f86 Mon Sep 17 00:00:00 2001 From: Sebastian Fix Date: Fri, 3 Apr 2026 15:11:45 +0200 Subject: [PATCH 27/30] chore: sync dependency audit workflows from template --- .github/workflows/composer-audit.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/composer-audit.yml b/.github/workflows/composer-audit.yml index ed5c5478..72698cfa 100644 --- a/.github/workflows/composer-audit.yml +++ b/.github/workflows/composer-audit.yml @@ -28,7 +28,7 @@ jobs: - name: Setup PHP uses: shivammathur/setup-php@2.37.0 with: - php-version: '8.4' + php-version: '8.5' coverage: none - name: Resolve dependencies and audit From d843cfce2aefa3941ddffabc6a801c83795bc866 Mon Sep 17 00:00:00 2001 From: Sebastian Fix Date: Sat, 4 Apr 2026 00:10:04 +0200 Subject: [PATCH 28/30] chore: sync Dependabot config and workflows from template --- .github/workflows/dependabot-auto-merge.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/dependabot-auto-merge.yml b/.github/workflows/dependabot-auto-merge.yml index 5bfa1ad9..b8a14171 100644 --- a/.github/workflows/dependabot-auto-merge.yml +++ b/.github/workflows/dependabot-auto-merge.yml @@ -9,11 +9,13 @@ jobs: dependabot: runs-on: ubuntu-latest if: ${{ github.actor == 'dependabot[bot]' }} + env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true steps: - name: Dependabot metadata id: metadata - uses: dependabot/fetch-metadata@v2.5.0 + uses: dependabot/fetch-metadata@v3.0.0 with: github-token: "${{ secrets.GITHUB_TOKEN }}" From fec181b645904093a24b06ff10c92ed03c26da05 Mon Sep 17 00:00:00 2001 From: Sebastian Fix Date: Tue, 7 Apr 2026 16:04:05 +0200 Subject: [PATCH 29/30] Laravel 13 --- .github/workflows/run-tests.yml | 14 ++-- composer.json | 41 +++++----- phpstan.neon.dist | 2 +- phpunit.xml.dist | 2 +- src/Connectors/DocuWareConnector.php | 45 +++++------ .../OAuth/IdentityServiceConfiguration.php | 65 ++++++++++++--- src/DTO/Documents/Document.php | 73 ++++++++++++++++- src/DTO/Documents/DocumentField.php | 6 ++ .../Documents/DocumentIndex/IndexDateDTO.php | 5 +- .../DocumentIndex/IndexDateTimeDTO.php | 5 +- .../DocumentIndex/IndexDecimalDTO.php | 3 + .../DocumentIndex/IndexKeywordDTO.php | 3 + .../Documents/DocumentIndex/IndexMemoDTO.php | 3 + .../DocumentIndex/IndexNumericDTO.php | 3 + .../Documents/DocumentIndex/IndexTableDTO.php | 33 +++++++- .../Documents/DocumentIndex/IndexTextDTO.php | 3 + .../Documents/DocumentIndex/PrepareDTO.php | 8 ++ src/DTO/Documents/DocumentPaginator.php | 25 +++++- src/DTO/Documents/TableRow.php | 22 ++++- src/DTO/Documents/TrashDocumentPaginator.php | 47 +++++++++-- src/DTO/General/Organization/Organization.php | 11 +++ src/DTO/SuggestionField.php | 9 +++ src/DocuWareSearchRequestBuilder.php | 25 +++++- src/Facades/DocuWare.php | 18 ++--- .../UpdateIndexValuesResponse.php | 6 +- src/Responses/Fields/GetFieldsResponse.php | 9 ++- .../Dialogs/GetAllDialogsResponse.php | 9 ++- ...llFileCabinetsAndDocumentTraysResponse.php | 9 ++- .../Organization/GetOrganizationResponse.php | 9 ++- .../GetModifyGroups/GetGroupsResponse.php | 9 ++- .../GetModifyRoles/GetRolesResponse.php | 9 ++- .../GetUsers/GetUsersResponse.php | 9 ++- .../GetDocumentWorkflowHistoryResponse.php | 6 +- src/Support/Auth.php | 16 +++- src/Support/JsonArrays.php | 25 ++++++ src/Support/ParseValue.php | 44 ++++++++-- tests/Pest.php | 80 +++++++++++++------ tests/TestCase.php | 27 ------- 38 files changed, 554 insertions(+), 184 deletions(-) create mode 100644 src/Support/JsonArrays.php diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 69be47a6..0eb9ffb3 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -14,22 +14,22 @@ jobs: max-parallel: 1 matrix: os: [ ubuntu-latest ] - php: [ 8.2, 8.3, 8.4 ] - laravel: [ 12.* ] + php: [ 8.3, 8.4, 8.5 ] + laravel: [ 13.* ] stability: [ prefer-lowest, prefer-stable ] name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} - ${{ matrix.os }} steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Setup PHP uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php }} extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick, fileinfo - coverage: none + coverage: pcov - name: Setup problem matchers run: | @@ -41,10 +41,10 @@ jobs: composer require "laravel/framework:${{ matrix.laravel }}" --no-interaction --no-update composer update --${{ matrix.stability }} --prefer-dist --no-interaction - - name: Execute tests + - name: Copy PHPUnit configuration run: cp phpunit.xml.dist phpunit.xml - - name: Execute tests + - name: Run Pest tests run: vendor/bin/pest env: DOCUWARE_URL: ${{ secrets.DOCUWARE_URL }} @@ -54,7 +54,7 @@ jobs: - name: Store Log Artifacts if: failure() - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 with: name: Store report artifacts path: ./vendor/orchestra/testbench-core/laravel/storage/logs diff --git a/composer.json b/composer.json index 409fc869..52b90235 100644 --- a/composer.json +++ b/composer.json @@ -21,24 +21,27 @@ } ], "require": { - "php": "8.2.*|8.3.*|8.4.*", - "guzzlehttp/guzzle": "^7.8", - "illuminate/contracts": "^12.0", - "nesbot/carbon": "^3.8", + "php": "8.3.*|8.4.*|8.5.*", + "guzzlehttp/guzzle": "^7.9.2", + "illuminate/contracts": "^13.0", + "illuminate/support": "^13.0", + "nesbot/carbon": "^3.8.4", "saloonphp/cache-plugin": "^3.1", - "saloonphp/laravel-plugin": "^3.0|^4.0", - "saloonphp/saloon": "^3.0|^4.0", - "spatie/laravel-package-tools": "^1.19" + "saloonphp/laravel-plugin": "^4.0", + "saloonphp/saloon": "^4.0", + "spatie/laravel-package-tools": "^1.19.0" }, "require-dev": { - "laravel/pint": "^1.21", - "larastan/larastan": "^v3.1", - "orchestra/testbench": "^10.0", - "pestphp/pest": "^3.7", - "phpstan/extension-installer": "^1.4", - "phpstan/phpstan-deprecation-rules": "^2.0", - "phpstan/phpstan-phpunit": "^2.0", - "spatie/laravel-ray": "^1.39" + "laravel/pint": "^1.21.1", + "larastan/larastan": "^3.9.3", + "nunomaduro/collision": "^8.9", + "orchestra/testbench": "^11.0", + "pestphp/pest": "^4.4", + "phpdocumentor/reflection-docblock": "^5.6.1", + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan-deprecation-rules": "^2.0.1", + "phpstan/phpstan-phpunit": "^2.0.4", + "spatie/laravel-ray": "^1.40.0" }, "autoload": { "psr-4": { @@ -53,16 +56,16 @@ "scripts": { "post-autoload-dump": "@php ./vendor/bin/testbench package:discover --ansi", "analyse": "vendor/bin/phpstan analyse", - "test": "vendor/bin/pest", + "test": "vendor/bin/pest --no-coverage", "test-coverage": "vendor/bin/pest --coverage", "format": "vendor/bin/pint" }, "config": { "sort-packages": true, "allow-plugins": { - "composer/package-versions-deprecated": true, - "phpstan/extension-installer": true, - "pestphp/pest-plugin": true + "composer/package-versions-deprecated": false, + "pestphp/pest-plugin": true, + "phpstan/extension-installer": true } }, "extra": { diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 0cc2d040..3438d94e 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -2,7 +2,7 @@ includes: - phpstan-baseline.neon parameters: - level: 5 + level: 6 paths: - src - config diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 5d65eeb6..475320c8 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,6 +1,6 @@ diff --git a/src/Connectors/DocuWareConnector.php b/src/Connectors/DocuWareConnector.php index b36fa324..b3a44e0b 100644 --- a/src/Connectors/DocuWareConnector.php +++ b/src/Connectors/DocuWareConnector.php @@ -17,6 +17,7 @@ use Psr\SimpleCache\InvalidArgumentException; use Saloon\Http\Auth\TokenAuthenticator; use Saloon\Http\Connector; +use Saloon\Http\Response; class DocuWareConnector extends Connector { @@ -48,9 +49,13 @@ protected function defaultAuth(): TokenAuthenticator return new TokenAuthenticator($this->getOrCreateNewOAuthToken()); } + protected function oauthTokenCacheTtlSeconds(RequestTokenDto $token): int + { + return max(1, $token->expiresIn - 60); + } + /** * @throws InvalidArgumentException - * @throws \Exception */ protected function getOrCreateNewOAuthToken(): string { @@ -58,7 +63,6 @@ protected function getOrCreateNewOAuthToken(): string $cacheKey = 'docuware.oauth.'.$this->configuration->identifier; - // Check if the token exists in cache and return it if found if ($cache->has($cacheKey)) { $token = Crypt::decrypt($cache->get($cacheKey)); DocuWareOAuthLog::dispatch($this->configuration->url, $this->configuration->username, 'Token retrieved from cache'); @@ -66,24 +70,19 @@ protected function getOrCreateNewOAuthToken(): string return $token->accessToken; } - // Handle token retrieval for ConfigWithCredentials if ($this->configuration instanceof ConfigWithCredentials) { $token = $this->getNewOAuthTokenWithCredentials(); DocuWareOAuthLog::dispatch($this->configuration->url, $this->configuration->username, 'Token retrieved from API'); - $cache->put($cacheKey, Crypt::encrypt($token), $token->expiresIn - 60); + $cache->put($cacheKey, Crypt::encrypt($token), $this->oauthTokenCacheTtlSeconds($token)); return $token->accessToken; } - // Handle token retrieval for ConfigWithCredentialsTrustedUser - // @phpstan-ignore-next-line - if ($this->configuration instanceof ConfigWithCredentialsTrustedUser) { - $token = $this->getNewOAuthTokenWithCredentialsTrustedUser(); - DocuWareOAuthLog::dispatch($this->configuration->url, $this->configuration->username, 'Token retrieved from API'); - $cache->put($cacheKey, Crypt::encrypt($token), $token->expiresIn - 60); + $token = $this->getNewOAuthTokenWithCredentialsTrustedUser(); + DocuWareOAuthLog::dispatch($this->configuration->url, $this->configuration->username, 'Token retrieved from API'); + $cache->put($cacheKey, Crypt::encrypt($token), $this->oauthTokenCacheTtlSeconds($token)); - return $token->accessToken; - } + return $token->accessToken; } protected function getAuthenticationTokenEndpoint(): IdentityServiceConfiguration @@ -111,18 +110,7 @@ protected function getNewOAuthTokenWithCredentials(): RequestTokenDto password: $this->configuration->password, ))->send(); - throw_if( - $requestTokenResponse->failed(), - trim(preg_replace('/\s\s+/', ' ', Arr::get( - array: $requestTokenResponse->json(), - key: 'error_description', - default: $requestTokenResponse->body() - ))) - ); - - throw_if($requestTokenResponse->dto() == null, 'Token response is null'); - - return $requestTokenResponse->dto(); + return $this->ensureRequestTokenSuccess($requestTokenResponse); } /** @@ -140,6 +128,15 @@ protected function getNewOAuthTokenWithCredentialsTrustedUser(): RequestTokenDto impersonateName: $this->configuration->impersonatedUsername, ))->send(); + return $this->ensureRequestTokenSuccess($requestTokenResponse); + } + + /** + * @throws \Throwable + * @throws \JsonException + */ + protected function ensureRequestTokenSuccess(Response $requestTokenResponse): RequestTokenDto + { throw_if( $requestTokenResponse->failed(), trim(preg_replace('/\s\s+/', ' ', Arr::get( diff --git a/src/DTO/Authentication/OAuth/IdentityServiceConfiguration.php b/src/DTO/Authentication/OAuth/IdentityServiceConfiguration.php index 800c0824..8bd3b5de 100644 --- a/src/DTO/Authentication/OAuth/IdentityServiceConfiguration.php +++ b/src/DTO/Authentication/OAuth/IdentityServiceConfiguration.php @@ -6,6 +6,9 @@ final class IdentityServiceConfiguration { + /** + * @param array $data + */ public static function make(array $data): self { return new self( @@ -26,26 +29,41 @@ public static function make(array $data): self frontchannelLogoutSessionSupported: Arr::get($data, 'frontchannel_logout_session_supported'), backchannelLogoutSupported: Arr::get($data, 'backchannel_logout_supported'), backchannelLogoutSessionSupported: Arr::get($data, 'backchannel_logout_session_supported'), - scopesSupported: Arr::get($data, 'scopes_supported', []), - claimsSupported: Arr::get($data, 'claims_supported', []), - grantTypesSupported: Arr::get($data, 'grant_types_supported', []), - responseTypesSupported: Arr::get($data, 'response_types_supported', []), - responseModesSupported: Arr::get($data, 'response_modes_supported', []), - tokenEndpointAuthMethodsSupported: Arr::get($data, 'token_endpoint_auth_methods_supported', []), - idTokenSigningAlgValuesSupported: Arr::get($data, 'id_token_signing_alg_values_supported', []), - subjectTypesSupported: Arr::get($data, 'subject_types_supported', []), - codeChallengeMethodsSupported: Arr::get($data, 'code_challenge_methods_supported', []), + scopesSupported: self::stringList(Arr::get($data, 'scopes_supported', [])), + claimsSupported: self::stringList(Arr::get($data, 'claims_supported', [])), + grantTypesSupported: self::stringList(Arr::get($data, 'grant_types_supported', [])), + responseTypesSupported: self::stringList(Arr::get($data, 'response_types_supported', [])), + responseModesSupported: self::stringList(Arr::get($data, 'response_modes_supported', [])), + tokenEndpointAuthMethodsSupported: self::stringList(Arr::get($data, 'token_endpoint_auth_methods_supported', [])), + idTokenSigningAlgValuesSupported: self::stringList(Arr::get($data, 'id_token_signing_alg_values_supported', [])), + subjectTypesSupported: self::stringList(Arr::get($data, 'subject_types_supported', [])), + codeChallengeMethodsSupported: self::stringList(Arr::get($data, 'code_challenge_methods_supported', [])), requestParameterSupported: Arr::get($data, 'request_parameter_supported'), - requestObjectSigningAlgValuesSupported: Arr::get($data, 'request_object_signing_alg_values_supported', []), - promptValuesSupported: Arr::get($data, 'prompt_values_supported', []), + requestObjectSigningAlgValuesSupported: self::stringList(Arr::get($data, 'request_object_signing_alg_values_supported', [])), + promptValuesSupported: self::stringList(Arr::get($data, 'prompt_values_supported', [])), authorizationResponseIssParameterSupported: Arr::get($data, 'authorization_response_iss_parameter_supported'), - backchannelTokenDeliveryModesSupported: Arr::get($data, 'backchannel_token_delivery_modes_supported', []), + backchannelTokenDeliveryModesSupported: self::stringList(Arr::get($data, 'backchannel_token_delivery_modes_supported', [])), backchannelUserCodeParameterSupported: Arr::get($data, 'backchannel_user_code_parameter_supported'), - dpopSigningAlgValuesSupported: Arr::get($data, 'dpop_signing_alg_values_supported', []), + dpopSigningAlgValuesSupported: self::stringList(Arr::get($data, 'dpop_signing_alg_values_supported', [])), windowsAuthEndpoint: Arr::get($data, 'windows_auth_endpoint'), ); } + /** + * @param list $scopesSupported + * @param list $claimsSupported + * @param list $grantTypesSupported + * @param list $responseTypesSupported + * @param list $responseModesSupported + * @param list $tokenEndpointAuthMethodsSupported + * @param list $idTokenSigningAlgValuesSupported + * @param list $subjectTypesSupported + * @param list $codeChallengeMethodsSupported + * @param list $requestObjectSigningAlgValuesSupported + * @param list $promptValuesSupported + * @param list $backchannelTokenDeliveryModesSupported + * @param list $dpopSigningAlgValuesSupported + */ public function __construct( public ?string $issuer, public ?string $jwksUri, @@ -82,4 +100,25 @@ public function __construct( public array $dpopSigningAlgValuesSupported, public ?string $windowsAuthEndpoint, ) {} + + /** + * @return list + */ + private static function stringList(mixed $value): array + { + if (! is_array($value)) { + return []; + } + + $out = []; + foreach (array_values($value) as $item) { + if (is_string($item)) { + $out[] = $item; + } elseif (is_scalar($item)) { + $out[] = (string) $item; + } + } + + return $out; + } } diff --git a/src/DTO/Documents/Document.php b/src/DTO/Documents/Document.php index adfc596e..bb8a2720 100644 --- a/src/DTO/Documents/Document.php +++ b/src/DTO/Documents/Document.php @@ -12,18 +12,21 @@ final class Document { + /** + * @param array $data + */ public static function fromJson(array $data): self { $fields = Arr::has($data, 'Fields') - ? self::convertFields(collect(Arr::get($data, 'Fields'))) + ? self::convertFields(collect(self::listOfFieldArraysFromData($data, 'Fields'))) : null; $sections = Arr::has($data, 'Sections') - ? self::convertSections(collect(Arr::get($data, 'Sections'))) + ? self::convertSections(collect(self::listOfFieldArraysFromData($data, 'Sections'))) : null; $suggestions = Arr::has($data, 'Suggestions') - ? self::convertSuggestions(collect(Arr::get($data, 'Suggestions'))) + ? self::convertSuggestions(collect(self::listOfFieldArraysFromData($data, 'Suggestions'))) : null; return new self( @@ -31,7 +34,7 @@ public static function fromJson(array $data): self file_size: Arr::get($data, 'FileSize'), total_pages: Arr::get($data, 'TotalPages'), title: Arr::get($data, 'Title'), - extension: (Arr::get($fields, 'DWEXTENSION'))->value ?? null, + extension: self::extensionFromFields($fields), content_type: Arr::get($data, 'ContentType'), file_cabinet_id: Arr::get($data, 'FileCabinetId'), intellixTrust: Arr::get($data, 'IntellixTrust'), @@ -43,6 +46,50 @@ public static function fromJson(array $data): self ); } + /** + * @param array $data + * @return list> + */ + protected static function listOfFieldArraysFromData(array $data, string $key): array + { + $raw = Arr::get($data, $key); + if (! is_array($raw)) { + return []; + } + + $out = []; + foreach (array_values($raw) as $item) { + if (is_array($item)) { + $out[] = $item; + } + } + + return $out; + } + + /** + * @param Collection|null $fields + */ + protected static function extensionFromFields(?Collection $fields): ?string + { + if ($fields === null) { + return null; + } + + $field = $fields->get('DWEXTENSION'); + if (! $field instanceof DocumentField) { + return null; + } + + $value = $field->value; + + return is_string($value) ? $value : null; + } + + /** + * @param Collection> $fields + * @return Collection + */ protected static function convertFields(Collection $fields): Collection { return $fields->mapWithKeys(function (array $field) { @@ -50,6 +97,10 @@ protected static function convertFields(Collection $fields): Collection }); } + /** + * @param Collection> $suggestions + * @return Collection + */ protected static function convertSuggestions(Collection $suggestions): Collection { return $suggestions->mapWithKeys(function (array $suggestion) { @@ -57,6 +108,10 @@ protected static function convertSuggestions(Collection $suggestions): Collectio }); } + /** + * @param Collection> $sections + * @return Collection + */ protected static function convertSections(Collection $sections): Collection { return $sections->mapWithKeys(function (array $section) { @@ -64,6 +119,11 @@ protected static function convertSections(Collection $sections): Collection }); } + /** + * @param Collection|null $fields + * @param Collection|null $sections + * @param Collection|null $suggestions + */ public function __construct( public int $id, public int $file_size, @@ -118,6 +178,11 @@ public function fileName(): string return "{$name}{$this->extension}"; } + /** + * @param Collection|null $fields + * @param Collection|null $sections + * @param Collection|null $suggestions + */ public static function fake( ?int $id = null, ?int $file_size = null, diff --git a/src/DTO/Documents/DocumentField.php b/src/DTO/Documents/DocumentField.php index d7fe0c13..d38c6b60 100644 --- a/src/DTO/Documents/DocumentField.php +++ b/src/DTO/Documents/DocumentField.php @@ -9,6 +9,9 @@ final class DocumentField { + /** + * @param array $data + */ public static function fromJson(array $data): self { return new self( @@ -21,6 +24,9 @@ public static function fromJson(array $data): self ); } + /** + * @param null|int|float|Carbon|string|Collection $value + */ public function __construct( public bool $systemField, public string $name, diff --git a/src/DTO/Documents/DocumentIndex/IndexDateDTO.php b/src/DTO/Documents/DocumentIndex/IndexDateDTO.php index c794c05f..78f68544 100644 --- a/src/DTO/Documents/DocumentIndex/IndexDateDTO.php +++ b/src/DTO/Documents/DocumentIndex/IndexDateDTO.php @@ -16,7 +16,7 @@ public static function make(string $name, null|Carbon|\Carbon\Carbon $value): se return new self($name, $value); } - public static function makeWithFallback($name, object $value): mixed + public static function makeWithFallback(string $name, object $value): ?self { return match (true) { $value instanceof Carbon => self::make($name, $value), @@ -24,6 +24,9 @@ public static function makeWithFallback($name, object $value): mixed }; } + /** + * @return array + */ public function values(): array { return [ diff --git a/src/DTO/Documents/DocumentIndex/IndexDateTimeDTO.php b/src/DTO/Documents/DocumentIndex/IndexDateTimeDTO.php index 3bc6d581..92067153 100644 --- a/src/DTO/Documents/DocumentIndex/IndexDateTimeDTO.php +++ b/src/DTO/Documents/DocumentIndex/IndexDateTimeDTO.php @@ -16,7 +16,7 @@ public static function make(string $name, null|Carbon|\Carbon\Carbon $value): se return new self($name, $value); } - public static function makeWithFallback($name, object $value): mixed + public static function makeWithFallback(string $name, object $value): ?self { return match (true) { $value instanceof Carbon => self::make($name, $value), @@ -24,6 +24,9 @@ public static function makeWithFallback($name, object $value): mixed }; } + /** + * @return array + */ public function values(): array { return [ diff --git a/src/DTO/Documents/DocumentIndex/IndexDecimalDTO.php b/src/DTO/Documents/DocumentIndex/IndexDecimalDTO.php index e1de1531..72876b66 100644 --- a/src/DTO/Documents/DocumentIndex/IndexDecimalDTO.php +++ b/src/DTO/Documents/DocumentIndex/IndexDecimalDTO.php @@ -14,6 +14,9 @@ public static function make(string $name, null|int|float $value): self return new self($name, $value); } + /** + * @return array + */ public function values(): array { return [ diff --git a/src/DTO/Documents/DocumentIndex/IndexKeywordDTO.php b/src/DTO/Documents/DocumentIndex/IndexKeywordDTO.php index 7b4f960e..62fffa4d 100644 --- a/src/DTO/Documents/DocumentIndex/IndexKeywordDTO.php +++ b/src/DTO/Documents/DocumentIndex/IndexKeywordDTO.php @@ -14,6 +14,9 @@ public static function make(string $name, ?string $value): self return new self($name, $value); } + /** + * @return array + */ public function values(): array { return [ diff --git a/src/DTO/Documents/DocumentIndex/IndexMemoDTO.php b/src/DTO/Documents/DocumentIndex/IndexMemoDTO.php index db8765a1..d59085dd 100644 --- a/src/DTO/Documents/DocumentIndex/IndexMemoDTO.php +++ b/src/DTO/Documents/DocumentIndex/IndexMemoDTO.php @@ -14,6 +14,9 @@ public static function make(string $name, ?string $value): self return new self($name, $value); } + /** + * @return array + */ public function values(): array { return [ diff --git a/src/DTO/Documents/DocumentIndex/IndexNumericDTO.php b/src/DTO/Documents/DocumentIndex/IndexNumericDTO.php index abd2b876..e0365f88 100644 --- a/src/DTO/Documents/DocumentIndex/IndexNumericDTO.php +++ b/src/DTO/Documents/DocumentIndex/IndexNumericDTO.php @@ -16,6 +16,9 @@ public static function make(string $name, ?int $value): self return new self($name, $value); } + /** + * @return array + */ public function values(): array { return [ diff --git a/src/DTO/Documents/DocumentIndex/IndexTableDTO.php b/src/DTO/Documents/DocumentIndex/IndexTableDTO.php index a6b9c321..b37272dd 100644 --- a/src/DTO/Documents/DocumentIndex/IndexTableDTO.php +++ b/src/DTO/Documents/DocumentIndex/IndexTableDTO.php @@ -6,16 +6,25 @@ class IndexTableDTO { + /** + * @param array|Collection|null $rows + */ public function __construct( public string $name, public null|Collection|array $rows, ) {} + /** + * @param array|Collection $rows + */ public static function make(string $name, Collection|array $rows): self { return new self($name, $rows); } + /** + * @return array + */ public function values(): array { return [ @@ -28,16 +37,34 @@ public function values(): array ]; } + /** + * @return list> + */ protected function rowsCollection(): array { - return collect($this->rows ?? [])->map(function ($row) { - return self::makeRowContent(collect($row)); - }) + $rows = $this->rows ?? []; + + $collection = $rows instanceof Collection + ? $rows + : collect($rows); + + return $collection + ->map(function (mixed $row): array { + $rowCollection = $row instanceof Collection + ? $row + : collect(is_array($row) ? $row : []); + + return self::makeRowContent($rowCollection); + }) ->filter() ->values() ->toArray(); } + /** + * @param Collection $indexes + * @return array>> + */ public static function makeRowContent(Collection $indexes): array { return [ diff --git a/src/DTO/Documents/DocumentIndex/IndexTextDTO.php b/src/DTO/Documents/DocumentIndex/IndexTextDTO.php index 8917b1ab..a144fba8 100644 --- a/src/DTO/Documents/DocumentIndex/IndexTextDTO.php +++ b/src/DTO/Documents/DocumentIndex/IndexTextDTO.php @@ -14,6 +14,9 @@ public static function make(string $name, ?string $value): self return new self($name, $value); } + /** + * @return array + */ public function values(): array { return [ diff --git a/src/DTO/Documents/DocumentIndex/PrepareDTO.php b/src/DTO/Documents/DocumentIndex/PrepareDTO.php index 356d4390..cfd245f1 100644 --- a/src/DTO/Documents/DocumentIndex/PrepareDTO.php +++ b/src/DTO/Documents/DocumentIndex/PrepareDTO.php @@ -6,6 +6,10 @@ class PrepareDTO { + /** + * @param Collection $indexes + * @return array + */ public static function makeFields(Collection $indexes): array { return [ @@ -16,6 +20,10 @@ public static function makeFields(Collection $indexes): array ]; } + /** + * @param Collection $indexes + * @return array + */ public static function makeField(Collection $indexes, bool $forceUpdate = false): array { return [ diff --git a/src/DTO/Documents/DocumentPaginator.php b/src/DTO/Documents/DocumentPaginator.php index 422e7862..2319f126 100644 --- a/src/DTO/Documents/DocumentPaginator.php +++ b/src/DTO/Documents/DocumentPaginator.php @@ -8,10 +8,13 @@ use Illuminate\Support\Collection; /** - * @property Collection|Document[] $documents + * @property Collection $documents */ class DocumentPaginator { + /** + * @param Collection $documents + */ public function __construct( public int $total, public int $per_page, @@ -43,6 +46,9 @@ public function failed(): bool return ! $this->successful(); } + /** + * @param array $data + */ public static function fromJson( array $data, int $page, @@ -56,7 +62,17 @@ public static function fromJson( $to = $page === $lastPage ? $total : $page * $perPage; - $documents = collect(Arr::get($data, 'Items'))->map(function (array $document) { + $itemsRaw = Arr::get($data, 'Items', []); + $itemList = []; + if (is_array($itemsRaw)) { + foreach (array_values($itemsRaw) as $item) { + if (is_array($item)) { + $itemList[] = $item; + } + } + } + + $documents = collect($itemList)->map(function (array $document) { return Document::fromJson($document); }); @@ -80,11 +96,14 @@ public static function fromFailed(Exception $e): self last_page: 0, from: 0, to: 0, - documents: collect(), + documents: new Collection, error: ErrorBag::make($e), ); } + /** + * @param Collection|null $documents + */ public static function fake( ?int $total = null, ?int $per_page = null, diff --git a/src/DTO/Documents/TableRow.php b/src/DTO/Documents/TableRow.php index 9612b62b..6b393ca1 100644 --- a/src/DTO/Documents/TableRow.php +++ b/src/DTO/Documents/TableRow.php @@ -6,15 +6,29 @@ class TableRow { + /** + * @param array $data + */ public static function fromJson(array $data): self { - $fields = self::convertFields(collect($data)); + $fieldList = []; + foreach (array_values($data) as $item) { + if (is_array($item)) { + $fieldList[] = $item; + } + } + + $fields = self::convertFields(collect($fieldList)); return new self( fields: $fields, ); } + /** + * @param Collection> $fields + * @return Collection + */ protected static function convertFields(Collection $fields): Collection { return $fields->mapWithKeys(function (array $field) { @@ -22,10 +36,16 @@ protected static function convertFields(Collection $fields): Collection }); } + /** + * @param Collection $fields + */ public function __construct( public Collection $fields, ) {} + /** + * @param Collection|null $fields + */ public static function fake( ?Collection $fields = null, ): self { diff --git a/src/DTO/Documents/TrashDocumentPaginator.php b/src/DTO/Documents/TrashDocumentPaginator.php index c67dcd41..85acebc0 100644 --- a/src/DTO/Documents/TrashDocumentPaginator.php +++ b/src/DTO/Documents/TrashDocumentPaginator.php @@ -8,10 +8,15 @@ use Illuminate\Support\Collection; /** - * @property Collection|Document[] $documents + * @property Collection> $documents */ class TrashDocumentPaginator { + /** + * @param Collection> $headers + * @param Collection> $documents + * @param Collection> $mappedDocuments + */ public function __construct( public int $total, public int $per_page, @@ -45,6 +50,9 @@ public function failed(): bool return ! $this->successful(); } + /** + * @param array $data + */ public static function fromJson( array $data, int $page, @@ -58,14 +66,34 @@ public static function fromJson( $to = $page === $lastPage ? $total : $page * $perPage; - $headers = collect(Arr::get($data, 'Headers')); - $documents = collect(Arr::get($data, 'Rows')); - - $mappedDocuments = $documents->map(function (array $document) use ($headers) { + $headersRaw = Arr::get($data, 'Headers', []); + $headerMap = []; + if (is_array($headersRaw)) { + foreach ($headersRaw as $key => $value) { + if (is_array($value)) { + $headerMap[$key] = $value; + } + } + } + $headers = collect($headerMap); + + $rowsRaw = Arr::get($data, 'Rows', []); + $rowList = []; + if (is_array($rowsRaw)) { + foreach (array_values($rowsRaw) as $row) { + if (is_array($row)) { + $rowList[] = $row; + } + } + } + $documents = collect($rowList); + + $mappedDocuments = $documents->map(function (array $document) use ($headers): Collection { $document = collect($document); - return $document->mapWithKeys(function ($value, $key) use ($headers) { - $header = collect($headers->get($key)); + return $document->mapWithKeys(function (mixed $value, int|string $key) use ($headers): array { + $headerRaw = $headers->get($key); + $header = collect(is_array($headerRaw) ? $headerRaw : []); return $header->has('FieldName') ? [$header->get('FieldName') => $value] : []; })->filter(); @@ -100,6 +128,11 @@ public static function fromFailed(Exception $e): self ); } + /** + * @param Collection>|null $headers + * @param Collection>|null $documents + * @param Collection>|null $mappedDocuments + */ public static function fake( ?int $total = null, ?int $per_page = null, diff --git a/src/DTO/General/Organization/Organization.php b/src/DTO/General/Organization/Organization.php index 26643bc9..13ed220d 100644 --- a/src/DTO/General/Organization/Organization.php +++ b/src/DTO/General/Organization/Organization.php @@ -7,6 +7,9 @@ final class Organization { + /** + * @param array $data + */ public static function fromJson(array $data): self { return new self( @@ -18,6 +21,10 @@ public static function fromJson(array $data): self ); } + /** + * @param array $additionalInfo + * @param array $configurationRights + */ public function __construct( public string $id, public string $name, @@ -26,6 +33,10 @@ public function __construct( public array $configurationRights = [], ) {} + /** + * @param array $additionalInfo + * @param array $configurationRights + */ public static function fake( ?string $id = null, ?string $name = null, diff --git a/src/DTO/SuggestionField.php b/src/DTO/SuggestionField.php index 6e0a11ee..a9510c5c 100644 --- a/src/DTO/SuggestionField.php +++ b/src/DTO/SuggestionField.php @@ -6,6 +6,9 @@ final class SuggestionField { + /** + * @param array $data + */ public static function fromJson(array $data): self { return new self( @@ -16,6 +19,9 @@ public static function fromJson(array $data): self ); } + /** + * @param array $value + */ public function __construct( public array $value, public ?string $name, @@ -23,6 +29,9 @@ public function __construct( public ?string $confidence, ) {} + /** + * @param array $value + */ public static function fake( array $value = [], ?string $name = null, diff --git a/src/DocuWareSearchRequestBuilder.php b/src/DocuWareSearchRequestBuilder.php index 0e70ee76..f3283c67 100644 --- a/src/DocuWareSearchRequestBuilder.php +++ b/src/DocuWareSearchRequestBuilder.php @@ -6,6 +6,7 @@ use CodebarAg\DocuWare\Exceptions\UnableToSearch; use CodebarAg\DocuWare\Requests\Documents\DocumentsTrashBin\GetDocuments; use CodebarAg\DocuWare\Requests\Search\GetSearchRequest; +use Illuminate\Support\Collection; use Illuminate\Support\Str; use Saloon\Exceptions\InvalidResponseClassException; use Saloon\Exceptions\PendingRequestException; @@ -16,6 +17,7 @@ class DocuWareSearchRequestBuilder protected ?string $dialogId = null; + /** @var list */ protected array $additionalFileCabinetIds = []; protected int $page = 1; @@ -28,8 +30,10 @@ class DocuWareSearchRequestBuilder protected string $orderDirection = 'asc'; + /** @var array> */ protected array $filters = []; + /** @var array> */ protected array $usedDateOperators = []; protected bool $trashBin = false; @@ -48,6 +52,9 @@ public function fileCabinet(string $fileCabinetId): self return $this; } + /** + * @param list $fileCabinetIds + */ public function fileCabinets(array $fileCabinetIds): self { $this->fileCabinetId = $fileCabinetIds[0] ?? null; @@ -95,6 +102,10 @@ public function fulltext(?string $searchTerm): self public function filterDate(string $name, string $operator, ?Carbon $date): self { + if ($date === null) { + throw new \InvalidArgumentException('A date is required for date filters.'); + } + $date = $this->exactDateTime($date, $operator); $this->makeSureFilterDateRangeIsCorrect($name, $operator); @@ -140,11 +151,17 @@ public function filterIn(string $name, mixed $values): self return $this->filter($name, $values); } - $values = collect($values)->map(function ($value) { + $list = match (true) { + is_array($values) => array_values($values), + $values instanceof Collection => $values->values()->all(), + default => [], + }; + + $prepared = collect($list)->map(function (mixed $value) { return self::prepareValueForFilter($value); })->toArray(); - $this->filters[$name][] = implode(' OR ', $values); + $this->filters[$name][] = implode(' OR ', $prepared); return $this; } @@ -250,7 +267,7 @@ private function restructureMonoDateFilterRange(): void } } - private function makeSureFilterDateRangeIsCorrect($name, $operator): void + private function makeSureFilterDateRangeIsCorrect(string $name, string $operator): void { if (isset($this->usedDateOperators[$name])) { if ($operatorFilterIndex = array_search($operator, $this->usedDateOperators[$name])) { @@ -270,7 +287,7 @@ private function makeSureFilterDateRangeIsCorrect($name, $operator): void } } - private function exactDateTime($date, $operator): Carbon + private function exactDateTime(Carbon $date, string $operator): Carbon { return match ($operator) { '<', '>=' => $date->startOfDay(), diff --git a/src/Facades/DocuWare.php b/src/Facades/DocuWare.php index cc08cb89..edf46ef1 100644 --- a/src/Facades/DocuWare.php +++ b/src/Facades/DocuWare.php @@ -21,19 +21,19 @@ * @method static string login() * @method static void logout() * @method static Organization getOrganization(string $organizationId) - * @method static Collection|OrganizationIndex[] getOrganizations() - * @method static Collection|FileCabinetInformation[] getFileCabinets() - * @method static Collection|Field[] getFields(string $fileCabinetId) - * @method static Collection|Dialog[] getDialogs(string $fileCabinetId) - * @method static array getSelectList(string $fileCabinetId, string $dialogId, string $fieldName) + * @method static Collection getOrganizations() + * @method static Collection getFileCabinets() + * @method static Collection getFields(string $fileCabinetId) + * @method static Collection getDialogs(string $fileCabinetId) + * @method static array getSelectList(string $fileCabinetId, string $dialogId, string $fieldName) * @method static Document getDocument(string $fileCabinetId, int $documentId) * @method static string getDocumentPreview(string $fileCabinetId, int $documentId) * @method static string downloadDocument(string $fileCabinetId, int $documentId) - * @method static string downloadDocuments(string $fileCabinetId, array $documentIds) - * @method DocumentThumbnail downloadDocumentThumbnail(string $fileCabinetId, int $documentId, int $section, int $page = 0) + * @method static string downloadDocuments(string $fileCabinetId, list $documentIds) + * @method static DocumentThumbnail downloadDocumentThumbnail(string $fileCabinetId, int $documentId, int $section, int $page = 0) * @method static null|int|float|Carbon|string updateDocumentValue(string $fileCabinetId, int $documentId, string $fieldName, string $newValue, bool $forceUpdate = false) - * @method static null|int|float|Carbon|string updateDocumentValues(string $fileCabinetId, int $documentId, array $values, bool $forceUpdate = false) - * @method static Document uploadDocument(string $fileCabinetId, string $fileContent, string $fileName, ?Collection $indexes = null) + * @method static null|int|float|Carbon|string updateDocumentValues(string $fileCabinetId, int $documentId, array $values, bool $forceUpdate = false) + * @method static Document uploadDocument(string $fileCabinetId, string $fileContent, string $fileName, ?Collection $indexes = null) * @method static int documentCount(string $fileCabinetId, string $dialogId) * @method static void deleteDocument(string $fileCabinetId, int $documentId) * @method static DocuWareSearchRequestBuilder search() diff --git a/src/Responses/Documents/UpdateIndexValues/UpdateIndexValuesResponse.php b/src/Responses/Documents/UpdateIndexValues/UpdateIndexValuesResponse.php index 912e998c..2bcce424 100644 --- a/src/Responses/Documents/UpdateIndexValues/UpdateIndexValuesResponse.php +++ b/src/Responses/Documents/UpdateIndexValues/UpdateIndexValuesResponse.php @@ -4,12 +4,16 @@ use CodebarAg\DocuWare\Events\DocuWareResponseLog; use CodebarAg\DocuWare\Support\EnsureValidResponse; +use CodebarAg\DocuWare\Support\JsonArrays; use CodebarAg\DocuWare\Support\ParseValue; use Illuminate\Support\Collection; use Saloon\Http\Response; final class UpdateIndexValuesResponse { + /** + * @return Collection + */ public static function fromResponse(Response $response): Collection { event(new DocuWareResponseLog($response)); @@ -18,7 +22,7 @@ public static function fromResponse(Response $response): Collection $fields = $response->throw()->json('Field'); - return collect($fields)->mapWithKeys(function (array $field) { + return collect(JsonArrays::listOfRecords($fields))->mapWithKeys(function (array $field) { return [ $field['FieldName'] => ParseValue::field($field), ]; diff --git a/src/Responses/Fields/GetFieldsResponse.php b/src/Responses/Fields/GetFieldsResponse.php index bd2b8584..34a8f64a 100644 --- a/src/Responses/Fields/GetFieldsResponse.php +++ b/src/Responses/Fields/GetFieldsResponse.php @@ -5,13 +5,16 @@ use CodebarAg\DocuWare\DTO\Documents\Field; use CodebarAg\DocuWare\Events\DocuWareResponseLog; use CodebarAg\DocuWare\Support\EnsureValidResponse; +use CodebarAg\DocuWare\Support\JsonArrays; use Illuminate\Support\Collection; -use Illuminate\Support\Enumerable; use Saloon\Http\Response; final class GetFieldsResponse { - public static function fromResponse(Response $response): Collection|Enumerable + /** + * @return Collection + */ + public static function fromResponse(Response $response): Collection { event(new DocuWareResponseLog($response)); @@ -19,6 +22,6 @@ public static function fromResponse(Response $response): Collection|Enumerable $fields = $response->throw()->json('Fields'); - return collect($fields)->map(fn (array $field) => Field::fromJson($field)); + return collect(JsonArrays::listOfRecords($fields))->map(fn (array $field) => Field::fromJson($field)); } } diff --git a/src/Responses/FileCabinets/Dialogs/GetAllDialogsResponse.php b/src/Responses/FileCabinets/Dialogs/GetAllDialogsResponse.php index 6e1df2f3..64d0a56c 100644 --- a/src/Responses/FileCabinets/Dialogs/GetAllDialogsResponse.php +++ b/src/Responses/FileCabinets/Dialogs/GetAllDialogsResponse.php @@ -5,13 +5,16 @@ use CodebarAg\DocuWare\DTO\FileCabinets\Dialog; use CodebarAg\DocuWare\Events\DocuWareResponseLog; use CodebarAg\DocuWare\Support\EnsureValidResponse; +use CodebarAg\DocuWare\Support\JsonArrays; use Illuminate\Support\Collection; -use Illuminate\Support\Enumerable; use Saloon\Http\Response; final class GetAllDialogsResponse { - public static function fromResponse(Response $response): Collection|Enumerable + /** + * @return Collection + */ + public static function fromResponse(Response $response): Collection { event(new DocuWareResponseLog($response)); @@ -19,6 +22,6 @@ public static function fromResponse(Response $response): Collection|Enumerable $dialogs = $response->throw()->json('Dialog'); - return collect($dialogs)->map(fn (array $dialog) => Dialog::fromJson($dialog)); + return collect(JsonArrays::listOfRecords($dialogs))->map(fn (array $dialog) => Dialog::fromJson($dialog)); } } diff --git a/src/Responses/General/Organization/GetAllFileCabinetsAndDocumentTraysResponse.php b/src/Responses/General/Organization/GetAllFileCabinetsAndDocumentTraysResponse.php index 52aa8d89..13ff8d75 100644 --- a/src/Responses/General/Organization/GetAllFileCabinetsAndDocumentTraysResponse.php +++ b/src/Responses/General/Organization/GetAllFileCabinetsAndDocumentTraysResponse.php @@ -5,13 +5,16 @@ use CodebarAg\DocuWare\DTO\General\Organization\FileCabinet; use CodebarAg\DocuWare\Events\DocuWareResponseLog; use CodebarAg\DocuWare\Support\EnsureValidResponse; +use CodebarAg\DocuWare\Support\JsonArrays; use Illuminate\Support\Collection; -use Illuminate\Support\Enumerable; use Saloon\Http\Response; final class GetAllFileCabinetsAndDocumentTraysResponse { - public static function fromResponse(Response $response): Collection|Enumerable + /** + * @return Collection + */ + public static function fromResponse(Response $response): Collection { event(new DocuWareResponseLog($response)); @@ -19,6 +22,6 @@ public static function fromResponse(Response $response): Collection|Enumerable $cabinets = $response->throw()->json('FileCabinet'); - return collect($cabinets)->map(fn (array $cabinet) => FileCabinet::fromJson($cabinet)); + return collect(JsonArrays::listOfRecords($cabinets))->map(fn (array $cabinet) => FileCabinet::fromJson($cabinet)); } } diff --git a/src/Responses/General/Organization/GetOrganizationResponse.php b/src/Responses/General/Organization/GetOrganizationResponse.php index a43e41dc..9090b253 100644 --- a/src/Responses/General/Organization/GetOrganizationResponse.php +++ b/src/Responses/General/Organization/GetOrganizationResponse.php @@ -5,13 +5,16 @@ use CodebarAg\DocuWare\DTO\General\Organization\Organization; use CodebarAg\DocuWare\Events\DocuWareResponseLog; use CodebarAg\DocuWare\Support\EnsureValidResponse; +use CodebarAg\DocuWare\Support\JsonArrays; use Illuminate\Support\Collection; -use Illuminate\Support\Enumerable; use Saloon\Http\Response; final class GetOrganizationResponse { - public static function fromResponse(Response $response): Collection|Enumerable + /** + * @return Collection + */ + public static function fromResponse(Response $response): Collection { event(new DocuWareResponseLog($response)); @@ -19,6 +22,6 @@ public static function fromResponse(Response $response): Collection|Enumerable $organizations = $response->throw()->json('Organization'); - return collect($organizations)->map(fn (array $organization) => Organization::fromJson($organization)); + return collect(JsonArrays::listOfRecords($organizations))->map(fn (array $organization) => Organization::fromJson($organization)); } } diff --git a/src/Responses/General/UserManagement/GetModifyGroups/GetGroupsResponse.php b/src/Responses/General/UserManagement/GetModifyGroups/GetGroupsResponse.php index 58228264..41d59ba5 100644 --- a/src/Responses/General/UserManagement/GetModifyGroups/GetGroupsResponse.php +++ b/src/Responses/General/UserManagement/GetModifyGroups/GetGroupsResponse.php @@ -5,13 +5,16 @@ use CodebarAg\DocuWare\DTO\General\UserManagement\GetModifyGroups\Group; use CodebarAg\DocuWare\Events\DocuWareResponseLog; use CodebarAg\DocuWare\Support\EnsureValidResponse; +use CodebarAg\DocuWare\Support\JsonArrays; use Illuminate\Support\Collection; -use Illuminate\Support\Enumerable; use Saloon\Http\Response; final class GetGroupsResponse { - public static function fromResponse(Response $response): Enumerable|Collection + /** + * @return Collection + */ + public static function fromResponse(Response $response): Collection { event(new DocuWareResponseLog($response)); @@ -19,6 +22,6 @@ public static function fromResponse(Response $response): Enumerable|Collection $groups = $response->throw()->json('Item'); - return collect($groups)->map(fn (array $group) => Group::fromJson($group)); + return collect(JsonArrays::listOfRecords($groups))->map(fn (array $group) => Group::fromJson($group)); } } diff --git a/src/Responses/General/UserManagement/GetModifyRoles/GetRolesResponse.php b/src/Responses/General/UserManagement/GetModifyRoles/GetRolesResponse.php index b07ff814..d05c8268 100644 --- a/src/Responses/General/UserManagement/GetModifyRoles/GetRolesResponse.php +++ b/src/Responses/General/UserManagement/GetModifyRoles/GetRolesResponse.php @@ -5,13 +5,16 @@ use CodebarAg\DocuWare\DTO\General\UserManagement\GetModifyRoles\Role; use CodebarAg\DocuWare\Events\DocuWareResponseLog; use CodebarAg\DocuWare\Support\EnsureValidResponse; +use CodebarAg\DocuWare\Support\JsonArrays; use Illuminate\Support\Collection; -use Illuminate\Support\Enumerable; use Saloon\Http\Response; final class GetRolesResponse { - public static function fromResponse(Response $response): Enumerable|Collection + /** + * @return Collection + */ + public static function fromResponse(Response $response): Collection { event(new DocuWareResponseLog($response)); @@ -19,6 +22,6 @@ public static function fromResponse(Response $response): Enumerable|Collection $roles = $response->throw()->json('Item'); - return collect($roles)->map(fn (array $role) => Role::fromJson($role)); + return collect(JsonArrays::listOfRecords($roles))->map(fn (array $role) => Role::fromJson($role)); } } diff --git a/src/Responses/General/UserManagement/GetUsers/GetUsersResponse.php b/src/Responses/General/UserManagement/GetUsers/GetUsersResponse.php index 40104035..4ea47eef 100644 --- a/src/Responses/General/UserManagement/GetUsers/GetUsersResponse.php +++ b/src/Responses/General/UserManagement/GetUsers/GetUsersResponse.php @@ -5,13 +5,16 @@ use CodebarAg\DocuWare\DTO\General\UserManagement\GetUsers\User; use CodebarAg\DocuWare\Events\DocuWareResponseLog; use CodebarAg\DocuWare\Support\EnsureValidResponse; +use CodebarAg\DocuWare\Support\JsonArrays; use Illuminate\Support\Collection; -use Illuminate\Support\Enumerable; use Saloon\Http\Response; final class GetUsersResponse { - public static function fromResponse(Response $response): Enumerable|Collection + /** + * @return Collection + */ + public static function fromResponse(Response $response): Collection { event(new DocuWareResponseLog($response)); @@ -19,6 +22,6 @@ public static function fromResponse(Response $response): Enumerable|Collection $users = $response->throw()->json('User'); - return collect($users)->map(fn (array $user) => User::fromJson($user)); + return collect(JsonArrays::listOfRecords($users))->map(fn (array $user) => User::fromJson($user)); } } diff --git a/src/Responses/Workflow/GetDocumentWorkflowHistoryResponse.php b/src/Responses/Workflow/GetDocumentWorkflowHistoryResponse.php index 0396d9b5..0b8436c6 100644 --- a/src/Responses/Workflow/GetDocumentWorkflowHistoryResponse.php +++ b/src/Responses/Workflow/GetDocumentWorkflowHistoryResponse.php @@ -5,11 +5,15 @@ use CodebarAg\DocuWare\DTO\Workflow\InstanceHistory; use CodebarAg\DocuWare\Events\DocuWareResponseLog; use CodebarAg\DocuWare\Support\EnsureValidResponse; +use CodebarAg\DocuWare\Support\JsonArrays; use Illuminate\Support\Collection; use Saloon\Http\Response; final class GetDocumentWorkflowHistoryResponse { + /** + * @return Collection + */ public static function fromResponse(Response $response): Collection { event(new DocuWareResponseLog($response)); @@ -18,6 +22,6 @@ public static function fromResponse(Response $response): Collection $instanceHistories = $response->throw()->json('InstanceHistory'); - return collect($instanceHistories)->map(fn (array $instanceHistory) => InstanceHistory::fromJson($instanceHistory)); + return collect(JsonArrays::listOfRecords($instanceHistories))->map(fn (array $instanceHistory) => InstanceHistory::fromJson($instanceHistory)); } } diff --git a/src/Support/Auth.php b/src/Support/Auth.php index 2b7887a6..cbf8ad87 100644 --- a/src/Support/Auth.php +++ b/src/Support/Auth.php @@ -18,7 +18,10 @@ class Auth public static function store(CookieJar $cookies): void { - $cookie = collect($cookies->toArray()) + /** @var list> $cookieList */ + $cookieList = $cookies->toArray(); + + $cookie = collect($cookieList) ->reject(fn (array $cookie) => Arr::get($cookie, 'Value') === '') ->firstWhere('Name', self::COOKIE_NAME); @@ -33,9 +36,14 @@ public static function store(CookieJar $cookies): void ); } + /** + * @return array|null + */ public static function cookies(): ?array { - return Cache::driver(self::cacheDriver())->get(self::CACHE_KEY); + $cached = Cache::driver(self::cacheDriver())->get(self::CACHE_KEY); + + return is_array($cached) ? $cached : null; } public static function cookieJar(): ?CookieJar @@ -49,7 +57,9 @@ public static function cookieJar(): ?CookieJar public static function cookieDate(): string { - return Arr::get(Cache::driver(self::cacheDriver())->get(self::CACHE_KEY), 'CreatedAt'); + $cached = Cache::driver(self::cacheDriver())->get(self::CACHE_KEY); + + return is_array($cached) ? (string) Arr::get($cached, 'CreatedAt') : ''; } public static function forget(): void diff --git a/src/Support/JsonArrays.php b/src/Support/JsonArrays.php new file mode 100644 index 00000000..b30405ef --- /dev/null +++ b/src/Support/JsonArrays.php @@ -0,0 +1,25 @@ +> + */ + public static function listOfRecords(mixed $raw): array + { + if (! is_array($raw)) { + return []; + } + + $out = []; + foreach (array_values($raw) as $item) { + if (is_array($item)) { + $out[] = $item; + } + } + + return $out; + } +} diff --git a/src/Support/ParseValue.php b/src/Support/ParseValue.php index 46db420c..16463f05 100644 --- a/src/Support/ParseValue.php +++ b/src/Support/ParseValue.php @@ -10,6 +10,11 @@ class ParseValue { + /** + * @param array|null $field + * @param int|float|Carbon|string|Collection|null $default + * @return int|float|Carbon|string|Collection|null + */ public static function field( ?array $field, int|float|Carbon|string|Collection|null $default = null, @@ -25,9 +30,12 @@ public static function field( 'Int' => (int) $item, 'String' => (string) $item, 'Decimal' => (float) $item, - 'Date', 'DateTime' => self::date($item), - 'Keywords' => Arr::join($item['Keyword'], ', '), - 'Table' => self::table($item), + 'Date', 'DateTime' => self::date(is_string($item) ? $item : ''), + 'Keywords' => Arr::join( + is_array($item) && isset($item['Keyword']) && is_array($item['Keyword']) ? $item['Keyword'] : [], + ', ' + ), + 'Table' => is_array($item) ? self::table($item) : $default, default => $default, }; } @@ -42,20 +50,42 @@ public static function date(string $date): Carbon return Carbon::createFromTimestampMs($timestamp); } + /** + * @param array $Item + * @return Collection|null + */ public static function table(array $Item): ?Collection { - return match ($Item['$type']) { - 'DocumentIndexFieldTable' => self::documentIndexFieldTable($Item['Row']), + $type = $Item['$type'] ?? null; + + return match ($type) { + 'DocumentIndexFieldTable' => isset($Item['Row']) && is_array($Item['Row']) + ? self::documentIndexFieldTable($Item['Row']) + : null, default => null, }; } + /** + * @param array $Row + * @return Collection|null + */ public static function documentIndexFieldTable(array $Row): ?Collection { - $rows = collect($Row); + /** @var list> $list */ + $list = []; + foreach (array_values($Row) as $row) { + if (is_array($row)) { + $list[] = $row; + } + } + + $rows = collect($list); return $rows->map(function (array $row) { - return TableRow::fromJson($row['ColumnValue']); + $columnValue = $row['ColumnValue'] ?? []; + + return TableRow::fromJson(is_array($columnValue) ? $columnValue : []); }); } } diff --git a/tests/Pest.php b/tests/Pest.php index fc959f42..2629eb72 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -3,6 +3,7 @@ use CodebarAg\DocuWare\Connectors\DocuWareConnector; use CodebarAg\DocuWare\DocuWare; use CodebarAg\DocuWare\DTO\Config\ConfigWithCredentials; +use CodebarAg\DocuWare\DTO\Documents\Document; use CodebarAg\DocuWare\Requests\Documents\DocumentsTrashBin\DeleteDocuments; use CodebarAg\DocuWare\Requests\Documents\ModifyDocuments\DeleteDocument; use CodebarAg\DocuWare\Requests\FileCabinets\Search\GetASpecificDocumentFromAFileCabinet; @@ -21,28 +22,37 @@ ->beforeEach(function () { $this->connector = getConnector(); - clearFiles(); + clearFiles($this->connector); }) ->afterEach(function () { - setUsersInactive(); + setUsersInactive($this->connector); }) ->in('Feature'); -function clearFiles(): void +function clearFiles(DocuWareConnector $connector): void { - $connector = getConnector(); + $fileCabinetId = config('laravel-docuware.tests.file_cabinet_id'); - $paginator = $connector->send(new GetDocumentsFromAFileCabinet( - config('laravel-docuware.tests.file_cabinet_id') - ))->dto(); + $paginator = $connector->send(new GetDocumentsFromAFileCabinet($fileCabinetId))->dto(); + + if ($paginator->documents->isEmpty()) { + emptyTrashForConnector($connector); + + return; + } foreach ($paginator->documents as $document) { $connector->send(new DeleteDocument( - config('laravel-docuware.tests.file_cabinet_id'), + $fileCabinetId, $document->id, ))->dto(); } + emptyTrashForConnector($connector); +} + +function emptyTrashForConnector(DocuWareConnector $connector): void +{ $paginatorRequest = (new DocuWare) ->searchRequestBuilder() ->trashBin() @@ -56,10 +66,8 @@ function clearFiles(): void } } -function setUsersInactive(): void +function setUsersInactive(DocuWareConnector $connector): void { - $connector = getConnector(); - $response = $connector->send(new GetUsers); $users = $response->dto()->filter(function ($user) { @@ -76,7 +84,7 @@ function setUsersInactive(): void /** * @throws Throwable */ -function getConnector(): object +function getConnector(): DocuWareConnector { return new DocuWareConnector(new ConfigWithCredentials( username: config('laravel-docuware.credentials.username'), @@ -98,7 +106,38 @@ function cleanup($connector, $fileCabinetId): void } } -function uploadFiles($connector, $fileCabinetId, $path): array +function documentLooksProcessed(Document $document): bool +{ + return $document->total_pages > 0 + && $document->sections !== null + && $document->sections->isNotEmpty(); +} + +function refreshDocumentAfterProcessing(DocuWareConnector $connector, string $fileCabinetId, int $documentId): Document +{ + $maxAttempts = 60; + $sleepMs = 250; + + for ($attempt = 1; $attempt <= $maxAttempts; $attempt++) { + $document = $connector->send(new GetASpecificDocumentFromAFileCabinet( + $fileCabinetId, + $documentId + ))->dto(); + + if (documentLooksProcessed($document)) { + return $document; + } + + Sleep::for($sleepMs)->milliseconds(); + } + + return $connector->send(new GetASpecificDocumentFromAFileCabinet( + $fileCabinetId, + $documentId + ))->dto(); +} + +function uploadFiles(DocuWareConnector $connector, $fileCabinetId, $path): array { $document = $connector->send(new CreateDataRecord( $fileCabinetId, @@ -112,19 +151,8 @@ function uploadFiles($connector, $fileCabinetId, $path): array 'test-2.pdf', ))->dto(); - Sleep::for(5)->seconds(); // Wait for the files to be uploaded and processed - - // Have to get document again as returned data is incorrect - $document = $connector->send(new GetASpecificDocumentFromAFileCabinet( - $fileCabinetId, - $document->id - ))->dto(); - - // Have to get document2 again as returned data is incorrect - $document2 = $connector->send(new GetASpecificDocumentFromAFileCabinet( - $fileCabinetId, - $document2->id - ))->dto(); + $document = refreshDocumentAfterProcessing($connector, $fileCabinetId, $document->id); + $document2 = refreshDocumentAfterProcessing($connector, $fileCabinetId, $document2->id); return [$document, $document2]; } diff --git a/tests/TestCase.php b/tests/TestCase.php index fd588b78..f2b582fc 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -3,37 +3,10 @@ namespace CodebarAg\DocuWare\Tests; use CodebarAg\DocuWare\DocuWareServiceProvider; -use CodebarAg\DocuWare\Events\DocuWareOAuthLog; -use CodebarAg\DocuWare\Events\DocuWareResponseLog; -use Illuminate\Database\Eloquent\Factories\Factory; -use Illuminate\Support\Facades\Event; -use Illuminate\Support\Facades\Log; use Orchestra\Testbench\TestCase as Orchestra; class TestCase extends Orchestra { - protected function setUp(): void - { - parent::setUp(); - - Factory::guessFactoryNamesUsing( - fn (string $modelName) => 'codebar\\DocuWare\\Database\\Factories\\'.class_basename($modelName).'Factory', - ); - - // Event::listen(DocuWareResponseLog::class, function (DocuWareResponseLog $event) { - // Log::info('Docuware response', [ - // $event->response->getPendingRequest()->getUrl(), - // ]); - // }); - // - // Event::listen(DocuWareOAuthLog::class, function (DocuWareOAuthLog $event) { - // Log::info($event->message, [ - // 'url' => $event->url, - // 'username' => $event->username, - // ]); - // }); - } - protected function getPackageProviders($app): array { return [ From ae6213688795c03f39cce873e5f10bd7efb81628 Mon Sep 17 00:00:00 2001 From: Sebastian Fix Date: Tue, 7 Apr 2026 18:28:33 +0200 Subject: [PATCH 30/30] #major updated to laravel 13 --- .env.example | 37 ++++++++ README.md | 64 ++++++++++--- composer.json | 6 +- config/laravel-docuware.php | 16 ++++ docs/postman-parity.md | 95 +++++++++++++++++++ phpunit.xml.dist | 11 ++- src/Connectors/DocuWareConnector.php | 5 +- src/DTO/Authentication/OAuth/RequestToken.php | 3 + .../OAuth/ResponsibleIdentityService.php | 3 + src/DTO/Documents/Document.php | 28 +----- .../DocumentIndex/IndexDetectDTO.php | 2 +- src/DTO/Documents/DocumentThumbnail.php | 3 + .../DocumentsTrashBin/DeleteDocuments.php | 10 +- .../DocumentsTrashBin/RestoreDocuments.php | 10 +- src/DTO/Documents/Field.php | 3 + src/DTO/Documents/TableRow.php | 10 +- src/DTO/Documents/TrashDocumentPaginator.php | 69 ++++++++------ .../CheckoutToFileSystemResult.php | 29 ++++++ src/DTO/FileCabinets/Dialog.php | 15 ++- .../General/FileCabinetInformation.php | 3 + src/DTO/General/Organization/FileCabinet.php | 3 + .../Organization/OrganizationIndex.php | 3 + .../UserManagement/CreateUpdateUser/User.php | 3 + .../UserManagement/GetModifyGroups/Group.php | 3 + .../UserManagement/GetModifyRoles/Role.php | 3 + .../UserManagement/GetUsers/OutOfOffice.php | 3 + .../GetUsers/RegionalSettings.php | 3 + .../General/UserManagement/GetUsers/User.php | 3 + src/DTO/Section.php | 3 + src/DTO/Textshot.php | 9 +- src/DTO/TextshotPage.php | 19 +++- src/DTO/Workflow/HistoryStep.php | 18 +++- src/DTO/Workflow/InstanceHistory.php | 14 ++- src/DocuWareSearchRequestBuilder.php | 7 +- src/DocuWareUrl.php | 7 +- .../OAuth/GetResponsibleIdentityService.php | 3 +- .../OAuth/RequestTokenWithCredentials.php | 3 + ...RequestTokenWithCredentialsTrustedUser.php | 3 + .../AddApplicationProperties.php | 8 +- .../DeleteApplicationProperties.php | 10 +- .../UpdateApplicationProperties.php | 8 +- .../ClipUnclipStapleUnstaple/Clip.php | 6 ++ .../ClipUnclipStapleUnstaple/Staple.php | 6 ++ .../ClipUnclipStapleUnstaple/Unclip.php | 3 + .../ClipUnclipStapleUnstaple/Unstaple.php | 3 + .../DocumentsTrashBin/DeleteDocuments.php | 6 ++ .../DocumentsTrashBin/GetDocuments.php | 6 ++ .../DocumentsTrashBin/RestoreDocuments.php | 6 ++ .../ModifyDocuments/TransferDocument.php | 16 +++- .../Sections/GetAllSectionsFromADocument.php | 7 +- .../Stamps/AddDocumentAnnotations.php | 58 +++++++++++ src/Requests/Documents/Stamps/GetStamps.php | 39 ++++++++ .../UpdateIndexValues/UpdateIndexValues.php | 17 ++++ src/Requests/Fields/GetFieldsRequest.php | 7 +- .../Batch/BatchDocumentsUpdateFields.php | 61 ++++++++++++ .../CheckInDocumentFromFileSystem.php | 54 +++++++++++ .../CheckoutDocumentToFileSystem.php | 28 ++++++ .../CheckInCheckOut/UndoDocumentCheckout.php | 43 +++++++++ .../Search/GetDocumentsFromAFileCabinet.php | 3 + .../Upload/AppendASinglePDFToADocument.php | 3 + .../Upload/AppendFilesToADataRecord.php | 7 ++ .../FileCabinets/Upload/CreateDataRecord.php | 23 ++++- .../Upload/ReplaceAPDFDocumentSection.php | 3 + .../GetAllFileCabinetsAndDocumentTrays.php | 7 +- .../General/Organization/GetLoginToken.php | 6 ++ .../General/Organization/GetOrganization.php | 7 +- .../CreateUpdateUsers/CreateUser.php | 3 + .../CreateUpdateUsers/UpdateUser.php | 3 + .../GetModifyGroups/AddUserToAGroup.php | 6 ++ .../GetAllGroupsForASpecificUser.php | 7 +- .../GetModifyGroups/GetGroups.php | 7 +- .../GetModifyGroups/RemoveUserFromAGroup.php | 6 ++ .../GetModifyRoles/AddUserToARole.php | 6 ++ .../GetAllRolesForASpecificUser.php | 7 +- .../GetModifyRoles/GetRoles.php | 7 +- .../GetModifyRoles/RemoveUserFromARole.php | 6 ++ .../UserManagement/GetUsers/GetUsers.php | 7 +- .../GetUsers/GetUsersOfAGroup.php | 7 +- .../GetUsers/GetUsersOfARole.php | 7 +- src/Requests/Search/GetSearchRequest.php | 7 ++ .../Workflow/GetDocumentWorkflowHistory.php | 4 + .../GetApplicationPropertiesResponse.php | 9 +- .../GetAllSectionsFromADocumentResponse.php | 10 +- .../GetDocumentsFromAFileCabinetResponse.php | 2 +- src/Responses/Search/GetSearchResponse.php | 2 +- .../Search/GetTrashSearchResponse.php | 2 +- src/Support/JsonArrays.php | 36 ++++++- src/Support/ParseValue.php | 2 +- .../GetOrganizationFixtureTest.php | 26 +++++ tests/Fixtures/saloon/get-organization.json | 10 ++ .../DocuWareAuthenticationTest.php | 0 .../{Feature => Integration}/DocuWareTest.php | 14 +-- .../ApplicationPropertiesTest.php | 0 .../ClipUnclipStapleUnstaple/ClipTest.php | 0 .../ClipUnclipStapleUnstaple/StapleTest.php | 0 .../ClipUnclipStapleUnstaple/UnclipTest.php | 0 .../ClipUnclipStapleUnstaple/UnstapleTest.php | 0 .../DeleteDocumentsFromTrashBinTest.php | 0 .../GetDocumentsFromTrashBinTest.php | 0 .../RestoreDocumentsFromTrashBinTest.php | 0 .../Download/DownloadDocumentTest.php | 0 .../Download/DownloadSectionTest.php | 0 .../Download/DownloadThumbnailTest.php | 0 .../Documents/GetDocumentCountRequestTest.php | 0 .../GetDocumentPreviewRequestTest.php | 0 .../Documents/PostDocumentRequestTest.php | 0 .../PutDocumentFieldsRequestTest.php | 0 .../Documents/Sections/DeleteSectionTest.php | 0 .../Sections/GetASpecificSectionTest.php | 0 .../GetAllSectionsFromADocumentTest.php | 0 .../Documents/Sections/GetTextshotTest.php | 0 ...etDocumentDownloadThumbnailRequestTest.php | 0 .../Requests/Fields/GetFieldsRequestTest.php | 0 .../Dialogs/GetASpecificDialogTest.php | 0 .../FileCabinets/Dialogs/GetAllDialogs.php | 0 .../Dialogs/GetDialogsOfASpecificTypeTest.php | 0 .../General/GetFileCabinetInformationTest.php | 0 ...tASpecificDocumentFromAFileCabinetTest.php | 0 .../GetDocumentsFromAFileCabinetTest.php | 0 .../AppendASinglePDFToADocumentTest.php | 0 .../Upload/AppendFilesToADataRecordTest.php | 0 .../Upload/ReplaceAPDFDocumentSectionTest.php | 0 .../CreateUpdateUserTest.php | 0 .../AddRemoveUserToAGroupTest.php | 0 .../GetAllGroupsForASpecificUserTest.php | 0 .../GetModifyGroups/GetGroupsTest.php | 0 .../AddRemoveUserToARoleTest.php | 0 .../GetAllRolesForASpecificUserTest.php | 0 .../GetModifyRoles/GetRolesTest.php | 0 .../GetUsers/GetUserByIdTest.php | 0 .../GetUsers/GetUsersOfAGroupTest.php | 0 .../GetUsers/GetUsersOfARoleTest.php | 0 .../UserManagement/GetUsers/GetUsersTest.php | 0 .../GetOrganizationsRequestTest.php | 0 .../Requests/Search/GetSearchRequestTest.php | 0 .../SelectList/GetSelectListRequest.php | 0 .../GetDocumentWorkflowHistoryStepsTest.php | 0 .../GetDocumentWorkflowHistoryTest.php | 0 .../RecordGetOrganizationFixtureTest.php | 29 ++++++ tests/Pest.php | 3 +- tests/Support/FixtureDocuWareConnector.php | 27 ++++++ tests/TestCase.php | 3 + 142 files changed, 1103 insertions(+), 145 deletions(-) create mode 100644 .env.example create mode 100644 docs/postman-parity.md create mode 100644 src/DTO/FileCabinets/CheckoutToFileSystemResult.php create mode 100644 src/Requests/Documents/Stamps/AddDocumentAnnotations.php create mode 100644 src/Requests/Documents/Stamps/GetStamps.php create mode 100644 src/Requests/FileCabinets/Batch/BatchDocumentsUpdateFields.php create mode 100644 src/Requests/FileCabinets/CheckInCheckOut/CheckInDocumentFromFileSystem.php create mode 100644 src/Requests/FileCabinets/CheckInCheckOut/CheckoutDocumentToFileSystem.php create mode 100644 src/Requests/FileCabinets/CheckInCheckOut/UndoDocumentCheckout.php create mode 100644 tests/Feature/SaloonFixtures/GetOrganizationFixtureTest.php create mode 100644 tests/Fixtures/saloon/get-organization.json rename tests/{Feature => Integration}/DocuWareAuthenticationTest.php (100%) rename tests/{Feature => Integration}/DocuWareTest.php (82%) rename tests/{Feature => Integration}/Requests/Documents/ApplicationProperties/ApplicationPropertiesTest.php (100%) rename tests/{Feature => Integration}/Requests/Documents/ClipUnclipStapleUnstaple/ClipTest.php (100%) rename tests/{Feature => Integration}/Requests/Documents/ClipUnclipStapleUnstaple/StapleTest.php (100%) rename tests/{Feature => Integration}/Requests/Documents/ClipUnclipStapleUnstaple/UnclipTest.php (100%) rename tests/{Feature => Integration}/Requests/Documents/ClipUnclipStapleUnstaple/UnstapleTest.php (100%) rename tests/{Feature => Integration}/Requests/Documents/DocumentsTrashBin/DeleteDocumentsFromTrashBinTest.php (100%) rename tests/{Feature => Integration}/Requests/Documents/DocumentsTrashBin/GetDocumentsFromTrashBinTest.php (100%) rename tests/{Feature => Integration}/Requests/Documents/DocumentsTrashBin/RestoreDocumentsFromTrashBinTest.php (100%) rename tests/{Feature => Integration}/Requests/Documents/Download/DownloadDocumentTest.php (100%) rename tests/{Feature => Integration}/Requests/Documents/Download/DownloadSectionTest.php (100%) rename tests/{Feature => Integration}/Requests/Documents/Download/DownloadThumbnailTest.php (100%) rename tests/{Feature => Integration}/Requests/Documents/GetDocumentCountRequestTest.php (100%) rename tests/{Feature => Integration}/Requests/Documents/GetDocumentPreviewRequestTest.php (100%) rename tests/{Feature => Integration}/Requests/Documents/PostDocumentRequestTest.php (100%) rename tests/{Feature => Integration}/Requests/Documents/PutDocumentFieldsRequestTest.php (100%) rename tests/{Feature => Integration}/Requests/Documents/Sections/DeleteSectionTest.php (100%) rename tests/{Feature => Integration}/Requests/Documents/Sections/GetASpecificSectionTest.php (100%) rename tests/{Feature => Integration}/Requests/Documents/Sections/GetAllSectionsFromADocumentTest.php (100%) rename tests/{Feature => Integration}/Requests/Documents/Sections/GetTextshotTest.php (100%) rename tests/{Feature => Integration}/Requests/Documents/Thumbnail/GetDocumentDownloadThumbnailRequestTest.php (100%) rename tests/{Feature => Integration}/Requests/Fields/GetFieldsRequestTest.php (100%) rename tests/{Feature => Integration}/Requests/FileCabinets/Dialogs/GetASpecificDialogTest.php (100%) rename tests/{Feature => Integration}/Requests/FileCabinets/Dialogs/GetAllDialogs.php (100%) rename tests/{Feature => Integration}/Requests/FileCabinets/Dialogs/GetDialogsOfASpecificTypeTest.php (100%) rename tests/{Feature => Integration}/Requests/FileCabinets/General/GetFileCabinetInformationTest.php (100%) rename tests/{Feature => Integration}/Requests/FileCabinets/Search/GetASpecificDocumentFromAFileCabinetTest.php (100%) rename tests/{Feature => Integration}/Requests/FileCabinets/Search/GetDocumentsFromAFileCabinetTest.php (100%) rename tests/{Feature => Integration}/Requests/FileCabinets/Upload/AppendASinglePDFToADocumentTest.php (100%) rename tests/{Feature => Integration}/Requests/FileCabinets/Upload/AppendFilesToADataRecordTest.php (100%) rename tests/{Feature => Integration}/Requests/FileCabinets/Upload/ReplaceAPDFDocumentSectionTest.php (100%) rename tests/{Feature => Integration}/Requests/General/UserManagement/CreateUpdateUsers/CreateUpdateUserTest.php (100%) rename tests/{Feature => Integration}/Requests/General/UserManagement/GetModifyGroups/AddRemoveUserToAGroupTest.php (100%) rename tests/{Feature => Integration}/Requests/General/UserManagement/GetModifyGroups/GetAllGroupsForASpecificUserTest.php (100%) rename tests/{Feature => Integration}/Requests/General/UserManagement/GetModifyGroups/GetGroupsTest.php (100%) rename tests/{Feature => Integration}/Requests/General/UserManagement/GetModifyRoles/AddRemoveUserToARoleTest.php (100%) rename tests/{Feature => Integration}/Requests/General/UserManagement/GetModifyRoles/GetAllRolesForASpecificUserTest.php (100%) rename tests/{Feature => Integration}/Requests/General/UserManagement/GetModifyRoles/GetRolesTest.php (100%) rename tests/{Feature => Integration}/Requests/General/UserManagement/GetUsers/GetUserByIdTest.php (100%) rename tests/{Feature => Integration}/Requests/General/UserManagement/GetUsers/GetUsersOfAGroupTest.php (100%) rename tests/{Feature => Integration}/Requests/General/UserManagement/GetUsers/GetUsersOfARoleTest.php (100%) rename tests/{Feature => Integration}/Requests/General/UserManagement/GetUsers/GetUsersTest.php (100%) rename tests/{Feature => Integration}/Requests/Organization/GetOrganizationsRequestTest.php (100%) rename tests/{Feature => Integration}/Requests/Search/GetSearchRequestTest.php (100%) rename tests/{Feature => Integration}/Requests/SelectList/GetSelectListRequest.php (100%) rename tests/{Feature => Integration}/Requests/Workflow/GetDocumentWorkflowHistoryStepsTest.php (100%) rename tests/{Feature => Integration}/Requests/Workflow/GetDocumentWorkflowHistoryTest.php (100%) create mode 100644 tests/Manual/RecordGetOrganizationFixtureTest.php create mode 100644 tests/Support/FixtureDocuWareConnector.php diff --git a/.env.example b/.env.example new file mode 100644 index 00000000..2a1f3629 --- /dev/null +++ b/.env.example @@ -0,0 +1,37 @@ +# DocuWare REST API (maps to Postman environment "DocuWare") +# +# Postman Laravel / config +# ---------------- -------------------------------------------- +# ServerUrl DOCUWARE_URL (scheme + host, no trailing path) +# Platform DOCUWARE_PLATFORM_PATH (default: DocuWare/Platform) +# Username DOCUWARE_USERNAME +# Password DOCUWARE_PASSWORD +# OrgId DOCUWARE_TESTS_ORG_ID (optional; or DOCUWARE_TESTS_ORGANIZATION_ID) +# FileCabinetId DOCUWARE_TESTS_FILE_CABINET_ID +# SearchDialogId DOCUWARE_TESTS_SEARCH_DIALOG_ID (optional; falls back to DOCUWARE_TESTS_DIALOG_ID in your app) +# StoreDialogId DOCUWARE_TESTS_STORE_DIALOG_ID +# DocumentId DOCUWARE_TESTS_DOCUMENT_ID +# ClientID / ClientSecret — OAuth client; package uses DOCUWARE_CLIENT_ID + password grant by default + +DOCUWARE_URL= +DOCUWARE_PLATFORM_PATH=DocuWare/Platform +DOCUWARE_USERNAME= +DOCUWARE_PASSWORD= +DOCUWARE_PASSPHRASE= +DOCUWARE_CLIENT_ID=docuware.platform.net.client +DOCUWARE_SCOPE=docuware.platform +DOCUWARE_TIMEOUT=60 +DOCUWARE_CACHE_DRIVER=file +DOCUWARE_CACHE_LIFETIME_IN_SECONDS=60 + +# PHPUnit / local live tests (see docs/postman-parity.md) +DOCUWARE_TESTS_FILE_CABINET_ID= +DOCUWARE_TESTS_DIALOG_ID= +DOCUWARE_TESTS_BASKET_ID= +DOCUWARE_TESTS_ORG_ID= +DOCUWARE_TESTS_SEARCH_DIALOG_ID= +DOCUWARE_TESTS_STORE_DIALOG_ID= +DOCUWARE_TESTS_DOCUMENT_ID= +DOCUWARE_TESTS_ORGANIZATION_ID= +DOCUWARE_TESTS_GROUP_ID= +DOCUWARE_TESTS_ROLE_ID= diff --git a/README.md b/README.md index 69ed4391..0b512b27 100644 --- a/README.md +++ b/README.md @@ -130,6 +130,7 @@ See the documentation if you need further functionality. ⚠️ * [💥 Exceptions explained](#-exceptions-explained) * [✨ Events](#-events) * [🔧 Configuration file](#-configuration-file) + * [Postman collection parity & Saloon fixtures](#postman-collection-parity--saloon-fixtures) * [🚧 Testing](#-testing) * [📝 Changelog](#-changelog) * [✏️ Contributing](#-contributing) @@ -198,20 +199,20 @@ then optimize the processes that power the core of your business. | FileCabinets/Search | Get a Specific Document From a File Cabinet | ✅ | | | FileCabinets/Search | Search for Documents in a Single File Cabinet | ✅ | | | FileCabinets/Search | Search for Documents in Multiple File Cabinets | ✅ | | -| FileCabinets/CheckInCheckOut | Check-out & Download a Document | 🕣 | | -| FileCabinets/CheckInCheckOut | Check-in a Document from the File System | 🕣 | | -| FileCabinets/CheckInCheckOut | Undo Check-out | 🕣 | | +| FileCabinets/CheckInCheckOut | Check-out & Download a Document | ✅ | `CheckoutDocumentToFileSystem` | +| FileCabinets/CheckInCheckOut | Check-in a Document from the File System | ✅ | `CheckInDocumentFromFileSystem` | +| FileCabinets/CheckInCheckOut | Undo Check-out | ✅ | `UndoDocumentCheckout` | | FileCabinets/SelectLists | Get Select Lists & Get Filtered Select Lists | ✅ | | | FileCabinets/Upload | Create Data Record | ✅ | | | FileCabinets/Upload | Append File(s) to a Data Record | ✅ | | | FileCabinets/Upload | Upload a Single File for a Data Record | ❌ | - | | FileCabinets/Upload | Create a Data Record & Upload File | ❌ | - | -| FileCabinets/Upload | Create Data Record & Upload File Using Store Dialog | ❌ | - | +| FileCabinets/Upload | Create Data Record & Upload File Using Store Dialog | ✅ | `CreateDataRecord` + `storeDialogId` | | FileCabinets/Upload | Append a Single PDF to a Document | ✅ | - | | FileCabinets/Upload | Replace a PDF Document Section | ✅ | | -| FileCabinets/BatchIndexFieldsUpdate | Batch Update Index Fields By Id | ❌ | - | -| FileCabinets/BatchIndexFieldsUpdate | Batch Update Index Fields By Search | ❌ | - | -| FileCabinets/BatchIndexFieldsUpdate | Batch Append/Update Keyword Fields By Id | ❌ | - | +| FileCabinets/BatchIndexFieldsUpdate | Batch Update Index Fields By Id | ✅ | `BatchDocumentsUpdateFields` | +| FileCabinets/BatchIndexFieldsUpdate | Batch Update Index Fields By Search | ✅ | `BatchDocumentsUpdateFields` | +| FileCabinets/BatchIndexFieldsUpdate | Batch Append/Update Keyword Fields By Id | ✅ | `BatchDocumentsUpdateFields` | | Documents/UpdateIndexValues | Update Index Values | ✅ | | | Documents/UpdateIndexValues | Update Table Field Values | ❌ | - ? | | Documents/ModifyDocuments | Transfer Document | ✅ | | @@ -220,15 +221,15 @@ then optimize the processes that power the core of your business. | Documents/ClipUnclip&StapleUnstaple | Unclip | ✅ | | | Documents/ClipUnclip&StapleUnstaple | Staple | ✅ | | | Documents/ClipUnclip&StapleUnstaple | Unstaple | ✅ | | -| Documents/AnnotationsStamps | AddStampWithPosition | 🕣 | | -| Documents/AnnotationsStamps | AddStampWithBestPosition | 🕣 | | +| Documents/AnnotationsStamps | AddStampWithPosition | ✅ | `AddDocumentAnnotations` | +| Documents/AnnotationsStamps | AddStampWithBestPosition | ✅ | `AddDocumentAnnotations` | | Documents/AnnotationsStamps | AddTextAnnotation | 🕣 | | | Documents/AnnotationsStamps | AddRectEntryAnnotation | 🕣 | | | Documents/AnnotationsStamps | AddLineEntryAnnotation | 🕣 | | | Documents/AnnotationsStamps | AddPolyLineEntryAnnotation | ❌ | - | | Documents/AnnotationsStamps | DeleteAnnotation | ❌ | - | | Documents/AnnotationsStamps | UpdateTextAnnotation | 🕣 | | -| Documents/AnnotationsStamps | Get Stamps | ❌ | - | +| Documents/AnnotationsStamps | Get Stamps | ✅ | `GetStamps` | | Documents/DocumentsTrashBin | Get Documents | ✅ | | | Documents/DocumentsTrashBin | Delete Documents | ✅ | | | Documents/DocumentsTrashBin | Restore Documents | ✅ | | @@ -1744,6 +1745,17 @@ return [ 'timeout' => env('DOCUWARE_TIMEOUT', 15), + /* + |-------------------------------------------------------------------------- + | Platform path + |-------------------------------------------------------------------------- + | + | Matches Postman {{Platform}} (default DocuWare/Platform). + | + */ + + 'platform_path' => env('DOCUWARE_PLATFORM_PATH', 'DocuWare/Platform'), + /* |-------------------------------------------------------------------------- | DocuWare Credentials @@ -1816,10 +1828,29 @@ return [ 'file_cabinet_id' => env('DOCUWARE_TESTS_FILE_CABINET_ID'), 'dialog_id' => env('DOCUWARE_TESTS_DIALOG_ID'), 'basket_id' => env('DOCUWARE_TESTS_BASKET_ID'), + 'org_id' => env('DOCUWARE_TESTS_ORG_ID', env('DOCUWARE_TESTS_ORGANIZATION_ID')), + 'search_dialog_id' => env('DOCUWARE_TESTS_SEARCH_DIALOG_ID'), + 'store_dialog_id' => env('DOCUWARE_TESTS_STORE_DIALOG_ID'), + 'document_id' => env('DOCUWARE_TESTS_DOCUMENT_ID'), ], ]; ``` +## Postman collection parity & Saloon fixtures + +The official DocuWare Postman collection uses `{{ServerUrl}}` and `{{Platform}}` (default `DocuWare/Platform`). This package maps them to Laravel env vars — see [`.env.example`](.env.example) for a **Postman variable → `DOCUWARE_*`** table. + +- **Parity matrix** (endpoints vs request classes): [`docs/postman-parity.md`](docs/postman-parity.md). +- **Platform path**: `DOCUWARE_PLATFORM_PATH` (used by `DocuWareConnector`, `GetResponsibleIdentityService`, and encrypted Web Client URLs in `DocuWareUrl`). +- **CI-friendly tests**: Default `composer test` runs **unit**, **DTO**, and **Saloon fixture** tests (`tests/Feature/SaloonFixtures`). HTTP responses are replayed from JSON files under [`tests/Fixtures/saloon/`](tests/Fixtures/saloon) using [Saloon fixtures](https://docs.saloon.dev/digging-deeper/testing) (`MockClient` + `Fixture`). Bodies use Saloon’s recorded format: `statusCode`, `headers`, `data` (raw response body), `context`. +- **Recording fixtures** (optional): Edit [`tests/Manual/RecordGetOrganizationFixtureTest.php`](tests/Manual/RecordGetOrganizationFixtureTest.php), remove the `->skip(...)`, set real `DOCUWARE_*` credentials, then run: + ```bash + composer test:manual + ``` + (`composer test:manual` runs only `tests/Manual`.) + Review the generated JSON for secrets, commit if safe, then restore the skip. +- **Live tenant tests** (destructive cleanup, real API): `composer test:live` runs the `integration` PHPUnit testsuite (`tests/Integration`). Requires valid DocuWare credentials and test cabinet IDs in `phpunit.xml` or the environment. + ## 🚧 Testing Copy your own phpunit.xml-file. @@ -1832,6 +1863,7 @@ Modify environment variables in the phpunit.xml-file: ```xml + @@ -1844,14 +1876,24 @@ Modify environment variables in the phpunit.xml-file: + + + + ``` -Run the tests: +Default test run (no live DocuWare required): ```bash composer test ``` +Against a real system (integration suite): + +```bash +composer test:live +``` + ## 📝 Changelog Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently. diff --git a/composer.json b/composer.json index 52b90235..428151ce 100644 --- a/composer.json +++ b/composer.json @@ -56,8 +56,10 @@ "scripts": { "post-autoload-dump": "@php ./vendor/bin/testbench package:discover --ansi", "analyse": "vendor/bin/phpstan analyse", - "test": "vendor/bin/pest --no-coverage", - "test-coverage": "vendor/bin/pest --coverage", + "test": "vendor/bin/pest --no-coverage --testsuite=default", + "test:live": "vendor/bin/pest --no-coverage --testsuite=integration", + "test:manual": "vendor/bin/pest --no-coverage tests/Manual", + "test-coverage": "vendor/bin/pest --coverage --testsuite=default", "format": "vendor/bin/pint" }, "config": { diff --git a/config/laravel-docuware.php b/config/laravel-docuware.php index d8cc11ef..d6934a07 100644 --- a/config/laravel-docuware.php +++ b/config/laravel-docuware.php @@ -23,6 +23,18 @@ 'timeout' => env('DOCUWARE_TIMEOUT', 15), + /* + |-------------------------------------------------------------------------- + | Platform path + |-------------------------------------------------------------------------- + | + | Postman variable {{Platform}} is usually "DocuWare/Platform". Base URL is + | rtrim(DOCUWARE_URL,'/').'/'.platform_path + | + */ + + 'platform_path' => env('DOCUWARE_PLATFORM_PATH', 'DocuWare/Platform'), + /* |-------------------------------------------------------------------------- | DocuWare Credentials @@ -95,5 +107,9 @@ 'file_cabinet_id' => env('DOCUWARE_TESTS_FILE_CABINET_ID'), 'dialog_id' => env('DOCUWARE_TESTS_DIALOG_ID'), 'basket_id' => env('DOCUWARE_TESTS_BASKET_ID'), + 'org_id' => env('DOCUWARE_TESTS_ORG_ID', env('DOCUWARE_TESTS_ORGANIZATION_ID')), + 'search_dialog_id' => env('DOCUWARE_TESTS_SEARCH_DIALOG_ID'), + 'store_dialog_id' => env('DOCUWARE_TESTS_STORE_DIALOG_ID'), + 'document_id' => env('DOCUWARE_TESTS_DOCUMENT_ID'), ], ]; diff --git a/docs/postman-parity.md b/docs/postman-parity.md new file mode 100644 index 00000000..b22fc4b8 --- /dev/null +++ b/docs/postman-parity.md @@ -0,0 +1,95 @@ +# DocuWare Postman collection vs this package + +Reference: official **DocuWare** Postman collection (e.g. `DocuWare.postman_collection.json`, Sept 2024). +Base URL pattern: `{ServerUrl}/{Platform}/…` with `Platform` default `DocuWare/Platform` — matches `DOCUWARE_URL` + `DOCUWARE_PLATFORM_PATH` in this package. + +Legend: **Parity** = covered with equivalent Saloon request; **Partial** = same endpoint, naming/options differ; **Missing** = not implemented yet. + +## Authentication + +| Postman | Package | +|--------|---------| +| 1. Get Responsible Identity Service | `GetResponsibleIdentityService` — Parity | +| 2. Get Identity Service Configuration | `GetIdentityServiceConfiguration` — Parity | +| 3.a–3.d OAuth token requests | `RequestTokenWithCredentials`, `RequestTokenWithCredentialsTrustedUser` — Partial (Postman has DocuWare token / Windows variants) | + +## General — Organization + +| Postman | Package | +|--------|---------| +| Get Login Token | `GetLoginToken` — Parity | +| Get Organization | `GetOrganization` — Parity | +| Get all File Cabinets and Document Trays | `GetAllFileCabinetsAndDocumentTrays` — Parity (`OrgId` via constructor) | + +## General — User management + +| Postman | Package | +|--------|---------| +| Get Users, Get User by ID, Users of Role/Group | `GetUsers`, `GetUserById`, … — Parity | +| Create / Update User | `CreateUser`, `UpdateUser` — Parity | +| Groups / Roles CRUD | `GetGroups`, `AddUserToAGroup`, … — Parity | + +## File cabinets — General / Dialogs / Search / Select lists + +| Postman | Package | +|--------|---------| +| Get File Cabinet Information | `GetFileCabinetInformation` — Parity | +| Get Total Number of Documents | `GetTotalNumberOfDocuments` — Parity | +| Get All / Specific / Typed Dialogs | `GetAllDialogs`, `GetASpecificDialog`, `GetDialogsOfASpecificType` — Parity | +| Get Documents / Specific Document | `GetDocumentsFromAFileCabinet`, `GetASpecificDocumentFromAFileCabinet` — Parity | +| DialogExpression search (single / multi cabinet) | `GetSearchRequest` / builder — Partial (align query/body with Postman examples) | +| Get / Filtered Select Lists | `GetSelectLists`, `GetFilteredSelectLists` — Parity | + +## File cabinets — Check in / Check out + +| Postman | Package | +|--------|---------| +| Check-out & Download (CheckoutToFileSystem) | `CheckoutDocumentToFileSystem` — Parity | +| Check-in from file system (multipart) | `CheckInDocumentFromFileSystem` — Parity | +| Undo Check-out (ProcessDocumentAction) | `UndoDocumentCheckout` — Parity | + +## File cabinets — Upload + +| Postman | Package | +|--------|---------| +| Create Data Record | `CreateDataRecord` — Parity | +| Create with `StoreDialogId` query | `CreateDataRecord` — Partial (use `storeDialogId` constructor arg) | +| Append files / Replace PDF / Append single PDF | `AppendFilesToADataRecord`, `ReplaceAPDFDocumentSection`, `AppendASinglePDFToADocument` — Parity | +| Other Postman-named upload variants | Same endpoints as above — Partial (naming only) | + +## File cabinets — Batch index + +| Postman | Package | +|--------|---------| +| Batch Update By Id / By Search / Keywords | `BatchDocumentsUpdateFields` — Parity (pass full JSON `Source` + `Data` as array) | + +## Documents + +| Postman | Package | +|--------|---------| +| Update Index Values / Table fields | `UpdateIndexValues` — Parity | +| Transfer / Delete | `TransferDocument`, `DeleteDocument` — Parity | +| Clip / Unclip / Staple / Unstaple | `Clip`, `Unclip`, `Staple`, `Unstaple` — Parity | +| Trash bin | `GetDocuments`, `DeleteDocuments`, `RestoreDocuments` (trash) — Parity | +| Application properties | `GetApplicationProperties`, … — Parity | +| Sections / Textshot | `GetAllSectionsFromADocument`, … — Parity | +| Download / Thumbnail | `DownloadDocument`, `DownloadSection`, `DownloadThumbnail` — Parity | +| Get Stamps | `GetStamps` — Parity | +| Add stamp (Annotation endpoint) | `AddDocumentAnnotations` — Parity (body as `array`) | +| Get / Add / Update / Delete annotations (full set) | **Partial** — stamp-oriented coverage via `AddDocumentAnnotations`; other annotation types may still be Missing | + +## Workflow + +| Postman | Package | +|--------|---------| +| Workflow history / steps | `GetDocumentWorkflowHistory`, `GetDocumentWorkflowHistorySteps` — Parity | + +## Fields + +| Postman | Package | +|--------|---------| +| Fields on cabinet | `GetFieldsRequest` — Parity | + +--- + +When Postman updates, diff new `raw` URLs under `FileCabinets`, `Documents`, and `Organization` against `src/Requests/**/resolveEndpoint()`. diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 475320c8..addd3cf5 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -5,8 +5,14 @@ executionOrder="defects" failOnWarning="true" failOnRisky="true" failOnEmptyTestSuite="true" beStrictAboutOutputDuringTests="true" cacheDirectory=".phpunit.cache" backupStaticProperties="false"> - - tests + + tests/Unit + tests/Core + tests/Feature + tests/Manual + + + tests/Integration @@ -22,6 +28,7 @@ + diff --git a/src/Connectors/DocuWareConnector.php b/src/Connectors/DocuWareConnector.php index b3a44e0b..3796eee8 100644 --- a/src/Connectors/DocuWareConnector.php +++ b/src/Connectors/DocuWareConnector.php @@ -27,7 +27,10 @@ public function __construct( public function resolveBaseUrl(): string { - return $this->configuration->url.'/DocuWare/Platform'; + $base = rtrim($this->configuration->url, '/'); + $platform = trim(config('laravel-docuware.platform_path', 'DocuWare/Platform'), '/'); + + return $base.'/'.$platform; } public function defaultHeaders(): array diff --git a/src/DTO/Authentication/OAuth/RequestToken.php b/src/DTO/Authentication/OAuth/RequestToken.php index 1c8d84cc..0760760e 100644 --- a/src/DTO/Authentication/OAuth/RequestToken.php +++ b/src/DTO/Authentication/OAuth/RequestToken.php @@ -7,6 +7,9 @@ final class RequestToken { + /** + * @param array $data + */ public static function make(array $data): self { return new self( diff --git a/src/DTO/Authentication/OAuth/ResponsibleIdentityService.php b/src/DTO/Authentication/OAuth/ResponsibleIdentityService.php index 8099d024..68942fe2 100644 --- a/src/DTO/Authentication/OAuth/ResponsibleIdentityService.php +++ b/src/DTO/Authentication/OAuth/ResponsibleIdentityService.php @@ -6,6 +6,9 @@ final class ResponsibleIdentityService { + /** + * @param array $data + */ public static function make(array $data): self { return new self( diff --git a/src/DTO/Documents/Document.php b/src/DTO/Documents/Document.php index bb8a2720..9f505614 100644 --- a/src/DTO/Documents/Document.php +++ b/src/DTO/Documents/Document.php @@ -5,6 +5,7 @@ use Carbon\Carbon; use CodebarAg\DocuWare\DTO\Section; use CodebarAg\DocuWare\DTO\SuggestionField; +use CodebarAg\DocuWare\Support\JsonArrays; use CodebarAg\DocuWare\Support\ParseValue; use Illuminate\Support\Arr; use Illuminate\Support\Collection; @@ -18,15 +19,15 @@ final class Document public static function fromJson(array $data): self { $fields = Arr::has($data, 'Fields') - ? self::convertFields(collect(self::listOfFieldArraysFromData($data, 'Fields'))) + ? self::convertFields(collect(JsonArrays::listOfRecords(Arr::get($data, 'Fields')))) : null; $sections = Arr::has($data, 'Sections') - ? self::convertSections(collect(self::listOfFieldArraysFromData($data, 'Sections'))) + ? self::convertSections(collect(JsonArrays::listOfRecords(Arr::get($data, 'Sections')))) : null; $suggestions = Arr::has($data, 'Suggestions') - ? self::convertSuggestions(collect(self::listOfFieldArraysFromData($data, 'Suggestions'))) + ? self::convertSuggestions(collect(JsonArrays::listOfRecords(Arr::get($data, 'Suggestions')))) : null; return new self( @@ -46,27 +47,6 @@ public static function fromJson(array $data): self ); } - /** - * @param array $data - * @return list> - */ - protected static function listOfFieldArraysFromData(array $data, string $key): array - { - $raw = Arr::get($data, $key); - if (! is_array($raw)) { - return []; - } - - $out = []; - foreach (array_values($raw) as $item) { - if (is_array($item)) { - $out[] = $item; - } - } - - return $out; - } - /** * @param Collection|null $fields */ diff --git a/src/DTO/Documents/DocumentIndex/IndexDetectDTO.php b/src/DTO/Documents/DocumentIndex/IndexDetectDTO.php index 861bfc91..102f02c4 100644 --- a/src/DTO/Documents/DocumentIndex/IndexDetectDTO.php +++ b/src/DTO/Documents/DocumentIndex/IndexDetectDTO.php @@ -11,7 +11,7 @@ public function __construct( public mixed $value, ) {} - public static function make(string $name, mixed $value) + public static function make(string $name, mixed $value): IndexTextDTO|IndexNumericDTO|IndexDecimalDTO|IndexDateTimeDTO|null { return match (true) { is_string($value) => IndexTextDTO::make($name, $value), diff --git a/src/DTO/Documents/DocumentThumbnail.php b/src/DTO/Documents/DocumentThumbnail.php index 0a32d52c..1510a07b 100644 --- a/src/DTO/Documents/DocumentThumbnail.php +++ b/src/DTO/Documents/DocumentThumbnail.php @@ -6,6 +6,9 @@ final class DocumentThumbnail { + /** + * @param array $data + */ public static function fromData(array $data): self { $mime = Arr::get($data, 'mime'); diff --git a/src/DTO/Documents/DocumentsTrashBin/DeleteDocuments.php b/src/DTO/Documents/DocumentsTrashBin/DeleteDocuments.php index 9eebdc0e..1496c151 100644 --- a/src/DTO/Documents/DocumentsTrashBin/DeleteDocuments.php +++ b/src/DTO/Documents/DocumentsTrashBin/DeleteDocuments.php @@ -2,13 +2,18 @@ namespace CodebarAg\DocuWare\DTO\Documents\DocumentsTrashBin; +use CodebarAg\DocuWare\Support\JsonArrays; use Illuminate\Support\Arr; final class DeleteDocuments { + /** + * @param array $data + */ public static function fromData(array $data): self { - $failedItems = Arr::get($data, 'FailedItems'); + $failedRaw = Arr::get($data, 'FailedItems', []); + $failedItems = JsonArrays::listOfRecords(is_array($failedRaw) ? $failedRaw : []); $successCount = Arr::get($data, 'SuccessCount'); return new self( @@ -17,6 +22,9 @@ public static function fromData(array $data): self ); } + /** + * @param list> $failedItems + */ public function __construct( public array $failedItems = [], public int $successCount = 0, diff --git a/src/DTO/Documents/DocumentsTrashBin/RestoreDocuments.php b/src/DTO/Documents/DocumentsTrashBin/RestoreDocuments.php index d87bf877..3d15951c 100644 --- a/src/DTO/Documents/DocumentsTrashBin/RestoreDocuments.php +++ b/src/DTO/Documents/DocumentsTrashBin/RestoreDocuments.php @@ -2,13 +2,18 @@ namespace CodebarAg\DocuWare\DTO\Documents\DocumentsTrashBin; +use CodebarAg\DocuWare\Support\JsonArrays; use Illuminate\Support\Arr; final class RestoreDocuments { + /** + * @param array $data + */ public static function fromData(array $data): self { - $failedItems = Arr::get($data, 'FailedItems'); + $failedRaw = Arr::get($data, 'FailedItems', []); + $failedItems = JsonArrays::listOfRecords(is_array($failedRaw) ? $failedRaw : []); $successCount = Arr::get($data, 'SuccessCount'); return new self( @@ -17,6 +22,9 @@ public static function fromData(array $data): self ); } + /** + * @param list> $failedItems + */ public function __construct( public array $failedItems = [], public int $successCount = 0, diff --git a/src/DTO/Documents/Field.php b/src/DTO/Documents/Field.php index 0c8fc4e9..706f25b2 100644 --- a/src/DTO/Documents/Field.php +++ b/src/DTO/Documents/Field.php @@ -6,6 +6,9 @@ final class Field { + /** + * @param array $data + */ public static function fromJson(array $data): self { return new self( diff --git a/src/DTO/Documents/TableRow.php b/src/DTO/Documents/TableRow.php index 6b393ca1..079238b8 100644 --- a/src/DTO/Documents/TableRow.php +++ b/src/DTO/Documents/TableRow.php @@ -2,6 +2,7 @@ namespace CodebarAg\DocuWare\DTO\Documents; +use CodebarAg\DocuWare\Support\JsonArrays; use Illuminate\Support\Collection; class TableRow @@ -11,14 +12,7 @@ class TableRow */ public static function fromJson(array $data): self { - $fieldList = []; - foreach (array_values($data) as $item) { - if (is_array($item)) { - $fieldList[] = $item; - } - } - - $fields = self::convertFields(collect($fieldList)); + $fields = self::convertFields(collect(JsonArrays::listOfRecords($data))); return new self( fields: $fields, diff --git a/src/DTO/Documents/TrashDocumentPaginator.php b/src/DTO/Documents/TrashDocumentPaginator.php index 85acebc0..60399295 100644 --- a/src/DTO/Documents/TrashDocumentPaginator.php +++ b/src/DTO/Documents/TrashDocumentPaginator.php @@ -3,19 +3,20 @@ namespace CodebarAg\DocuWare\DTO\Documents; use CodebarAg\DocuWare\DTO\ErrorBag; +use CodebarAg\DocuWare\Support\JsonArrays; use Exception; use Illuminate\Support\Arr; use Illuminate\Support\Collection; /** - * @property Collection> $documents + * @property Collection> $documents */ class TrashDocumentPaginator { /** - * @param Collection> $headers - * @param Collection> $documents - * @param Collection> $mappedDocuments + * @param Collection> $headers + * @param Collection> $documents + * @param Collection> $mappedDocuments */ public function __construct( public int $total, @@ -71,33 +72,20 @@ public static function fromJson( if (is_array($headersRaw)) { foreach ($headersRaw as $key => $value) { if (is_array($value)) { - $headerMap[$key] = $value; + $headerMap[(string) $key] = JsonArrays::associativeRow($value); } } } $headers = collect($headerMap); $rowsRaw = Arr::get($data, 'Rows', []); - $rowList = []; - if (is_array($rowsRaw)) { - foreach (array_values($rowsRaw) as $row) { - if (is_array($row)) { - $rowList[] = $row; - } - } - } - $documents = collect($rowList); - - $mappedDocuments = $documents->map(function (array $document) use ($headers): Collection { - $document = collect($document); - - return $document->mapWithKeys(function (mixed $value, int|string $key) use ($headers): array { - $headerRaw = $headers->get($key); - $header = collect(is_array($headerRaw) ? $headerRaw : []); + $documents = collect(JsonArrays::listOfRecords(is_array($rowsRaw) ? $rowsRaw : [])); - return $header->has('FieldName') ? [$header->get('FieldName') => $value] : []; - })->filter(); - }); + $mappedList = []; + foreach ($documents as $document) { + $mappedList[] = self::mapDocumentRowToFields($document, $headers); + } + $mappedDocuments = collect($mappedList); return new self( total: $total, @@ -112,6 +100,27 @@ public static function fromJson( ); } + /** + * @param array $document + * @param Collection> $headers + * @return Collection + */ + protected static function mapDocumentRowToFields(array $document, Collection $headers): Collection + { + $row = collect(JsonArrays::associativeRow($document)); + + return $row->mapWithKeys(function (mixed $value, int|string $key) use ($headers): array { + $headerRaw = $headers->get((string) $key); + $header = collect(is_array($headerRaw) ? JsonArrays::associativeRow($headerRaw) : []); + + $fieldName = $header->get('FieldName'); + + return $header->has('FieldName') && (is_string($fieldName) || is_int($fieldName)) + ? [(string) $fieldName => $value] + : []; + })->filter(); + } + public static function fromFailed(Exception $e): self { return new self( @@ -129,9 +138,9 @@ public static function fromFailed(Exception $e): self } /** - * @param Collection>|null $headers - * @param Collection>|null $documents - * @param Collection>|null $mappedDocuments + * @param Collection>|null $headers + * @param Collection>|null $documents + * @param Collection>|null $mappedDocuments */ public static function fake( ?int $total = null, @@ -151,9 +160,9 @@ public static function fake( last_page: $last_page ?? random_int(10, 20), from: $from ?? 1, to: $to ?? 10, - headers: $headers, - documents: $documents, - mappedDocuments: $mappedDocuments, + headers: $headers ?? collect(), + documents: $documents ?? collect(), + mappedDocuments: $mappedDocuments ?? collect(), ); } } diff --git a/src/DTO/FileCabinets/CheckoutToFileSystemResult.php b/src/DTO/FileCabinets/CheckoutToFileSystemResult.php new file mode 100644 index 00000000..7e8976b6 --- /dev/null +++ b/src/DTO/FileCabinets/CheckoutToFileSystemResult.php @@ -0,0 +1,29 @@ +> $links + */ + public function __construct( + public array $links, + ) {} + + public static function fromResponse(Response $response): self + { + event(new DocuWareResponseLog($response)); + + EnsureValidResponse::from($response); + + $raw = $response->throw()->json('Links'); + + return new self(JsonArrays::listOfRecords($raw)); + } +} diff --git a/src/DTO/FileCabinets/Dialog.php b/src/DTO/FileCabinets/Dialog.php index 9e4c3c6a..32a88556 100644 --- a/src/DTO/FileCabinets/Dialog.php +++ b/src/DTO/FileCabinets/Dialog.php @@ -2,23 +2,36 @@ namespace CodebarAg\DocuWare\DTO\FileCabinets; +use CodebarAg\DocuWare\Support\JsonArrays; use Illuminate\Support\Arr; use Illuminate\Support\Str; final class Dialog { + /** + * @param array $data + */ public static function fromJson(array $data): self { + $fieldsRaw = Arr::get($data, 'Fields'); + $fields = null; + if (is_array($fieldsRaw)) { + $fields = JsonArrays::listOfRecords($fieldsRaw); + } + return new self( id: Arr::get($data, 'Id'), type: Arr::get($data, 'Type'), label: Arr::get($data, 'DisplayName'), isDefault: Arr::get($data, 'IsDefault'), fileCabinetId: Arr::get($data, 'FileCabinetId'), - fields: Arr::get($data, 'Fields'), + fields: $fields, ); } + /** + * @param list>|null $fields + */ public function __construct( public string $id, public string $type, diff --git a/src/DTO/FileCabinets/General/FileCabinetInformation.php b/src/DTO/FileCabinets/General/FileCabinetInformation.php index 242d2b23..c0d8ed12 100644 --- a/src/DTO/FileCabinets/General/FileCabinetInformation.php +++ b/src/DTO/FileCabinets/General/FileCabinetInformation.php @@ -7,6 +7,9 @@ final class FileCabinetInformation { + /** + * @param array $data + */ public static function fromJson(array $data): self { return new self( diff --git a/src/DTO/General/Organization/FileCabinet.php b/src/DTO/General/Organization/FileCabinet.php index 0e6b9736..4b7b504d 100644 --- a/src/DTO/General/Organization/FileCabinet.php +++ b/src/DTO/General/Organization/FileCabinet.php @@ -7,6 +7,9 @@ final class FileCabinet { + /** + * @param array $data + */ public static function fromJson(array $data): self { return new self( diff --git a/src/DTO/General/Organization/OrganizationIndex.php b/src/DTO/General/Organization/OrganizationIndex.php index 71a58dbb..2b745994 100644 --- a/src/DTO/General/Organization/OrganizationIndex.php +++ b/src/DTO/General/Organization/OrganizationIndex.php @@ -7,6 +7,9 @@ final class OrganizationIndex { + /** + * @param array $data + */ public static function fromJson(array $data): self { return new self( diff --git a/src/DTO/General/UserManagement/CreateUpdateUser/User.php b/src/DTO/General/UserManagement/CreateUpdateUser/User.php index dd0e1add..4a6840bc 100644 --- a/src/DTO/General/UserManagement/CreateUpdateUser/User.php +++ b/src/DTO/General/UserManagement/CreateUpdateUser/User.php @@ -6,6 +6,9 @@ final class User { + /** + * @param array $data + */ public static function fromJson(array $data): self { return new self( diff --git a/src/DTO/General/UserManagement/GetModifyGroups/Group.php b/src/DTO/General/UserManagement/GetModifyGroups/Group.php index f37e0927..0df7768d 100644 --- a/src/DTO/General/UserManagement/GetModifyGroups/Group.php +++ b/src/DTO/General/UserManagement/GetModifyGroups/Group.php @@ -6,6 +6,9 @@ final class Group { + /** + * @param array $data + */ public static function fromJson(array $data): self { return new self( diff --git a/src/DTO/General/UserManagement/GetModifyRoles/Role.php b/src/DTO/General/UserManagement/GetModifyRoles/Role.php index 6eac160f..5ef7a3b2 100644 --- a/src/DTO/General/UserManagement/GetModifyRoles/Role.php +++ b/src/DTO/General/UserManagement/GetModifyRoles/Role.php @@ -6,6 +6,9 @@ final class Role { + /** + * @param array $data + */ public static function fromJson(array $data): self { return new self( diff --git a/src/DTO/General/UserManagement/GetUsers/OutOfOffice.php b/src/DTO/General/UserManagement/GetUsers/OutOfOffice.php index 8aeb77a4..7f159cbd 100644 --- a/src/DTO/General/UserManagement/GetUsers/OutOfOffice.php +++ b/src/DTO/General/UserManagement/GetUsers/OutOfOffice.php @@ -8,6 +8,9 @@ final class OutOfOffice { + /** + * @param array $data + */ public static function fromJson(array $data): self { $startDateTime = Arr::get($data, 'StartDateTime'); diff --git a/src/DTO/General/UserManagement/GetUsers/RegionalSettings.php b/src/DTO/General/UserManagement/GetUsers/RegionalSettings.php index c926ee80..904ac32b 100644 --- a/src/DTO/General/UserManagement/GetUsers/RegionalSettings.php +++ b/src/DTO/General/UserManagement/GetUsers/RegionalSettings.php @@ -6,6 +6,9 @@ final class RegionalSettings { + /** + * @param array $data + */ public static function fromJson(array $data): self { return new self( diff --git a/src/DTO/General/UserManagement/GetUsers/User.php b/src/DTO/General/UserManagement/GetUsers/User.php index f2d3e65a..c4dec673 100644 --- a/src/DTO/General/UserManagement/GetUsers/User.php +++ b/src/DTO/General/UserManagement/GetUsers/User.php @@ -7,6 +7,9 @@ final class User { + /** + * @param array $data + */ public static function fromJson(array $data): self { return new self( diff --git a/src/DTO/Section.php b/src/DTO/Section.php index 49c554b2..0c2b7de9 100644 --- a/src/DTO/Section.php +++ b/src/DTO/Section.php @@ -8,6 +8,9 @@ final class Section { + /** + * @param array $data + */ public static function fromJson(array $data): self { if ($contentModifiedDateTime = Arr::get($data, 'ContentModified')) { diff --git a/src/DTO/Textshot.php b/src/DTO/Textshot.php index 91a2f386..1949a203 100644 --- a/src/DTO/Textshot.php +++ b/src/DTO/Textshot.php @@ -2,14 +2,18 @@ namespace CodebarAg\DocuWare\DTO; +use CodebarAg\DocuWare\Support\JsonArrays; use Illuminate\Support\Arr; use Illuminate\Support\Collection; final class Textshot { + /** + * @param array $data + */ public static function fromJson(array $data): self { - $pages = collect(Arr::get($data, 'Pages', [])); + $pages = collect(JsonArrays::listOfRecords(Arr::get($data, 'Pages', []))); return new self( page_count: $pages->count(), @@ -17,6 +21,9 @@ public static function fromJson(array $data): self ); } + /** + * @param Collection $pages + */ public function __construct( public int $page_count, public Collection $pages, diff --git a/src/DTO/TextshotPage.php b/src/DTO/TextshotPage.php index 543f3d64..bf697d7f 100644 --- a/src/DTO/TextshotPage.php +++ b/src/DTO/TextshotPage.php @@ -2,23 +2,31 @@ namespace CodebarAg\DocuWare\DTO; +use CodebarAg\DocuWare\Support\JsonArrays; use Illuminate\Support\Arr; use Illuminate\Support\Collection; final class TextshotPage { + /** + * @param Collection> $collection + * @return Collection + */ public static function fromCollection(Collection $collection): Collection { return $collection->map(fn (array $data) => self::fromJson($data)); } + /** + * @param array $data + */ public static function fromJson(array $data): self { $rawItems = Arr::get($data, 'Items', []); return new self( language: Arr::get($data, 'Lang'), - content: self::content($rawItems) + content: self::content(JsonArrays::listOfRecords(is_array($rawItems) ? $rawItems : [])) ); } @@ -27,19 +35,22 @@ public function __construct( public string $content, ) {} + /** + * @param list> $rawItems + */ protected static function content(array $rawItems): string { return collect($rawItems) - ->filter(function ($item) { + ->filter(function (mixed $item) { return Arr::get($item, '$type') === 'TextZone'; }) ->pluck('Ln') ->flatten(2) - ->filter(function ($item) { + ->filter(function (mixed $item) { return is_array($item); }) ->flatten(1) - ->map(function ($item) { + ->map(function (mixed $item) { $type = Arr::get($item, '$type'); diff --git a/src/DTO/Workflow/HistoryStep.php b/src/DTO/Workflow/HistoryStep.php index 20a832ad..d3a3dc4a 100644 --- a/src/DTO/Workflow/HistoryStep.php +++ b/src/DTO/Workflow/HistoryStep.php @@ -2,6 +2,7 @@ namespace CodebarAg\DocuWare\DTO\Workflow; +use CodebarAg\DocuWare\Support\JsonArrays; use Illuminate\Support\Arr; use Illuminate\Support\Carbon; use Illuminate\Support\Collection; @@ -9,6 +10,9 @@ final class HistoryStep { + /** + * @param array $data + */ public static function fromJson(array $data): self { if ($stepDateTime = Arr::get($data, 'StepDate')) { @@ -16,8 +20,17 @@ public static function fromJson(array $data): self $stepDateTime = Carbon::createFromTimestamp($stepDateTime); } + $itemRaw = Arr::get($data, 'Info.Item'); + $rows = []; + if (is_array($itemRaw)) { + $rows = array_is_list($itemRaw) + ? JsonArrays::listOfRecords($itemRaw) + : [JsonArrays::associativeRow($itemRaw)]; + } + $infoItem = collect($rows); + return new self( - infoItem: collect(Arr::get($data, 'Info.Item')), + infoItem: $infoItem, stepNumber: Arr::get($data, 'StepNumber'), stepDate: $stepDateTime, activityName: Arr::get($data, 'ActivityName'), @@ -26,6 +39,9 @@ public static function fromJson(array $data): self ); } + /** + * @param Collection> $infoItem + */ public function __construct( public Collection $infoItem, public int $stepNumber, diff --git a/src/DTO/Workflow/InstanceHistory.php b/src/DTO/Workflow/InstanceHistory.php index 3ae14e0f..69fe1331 100644 --- a/src/DTO/Workflow/InstanceHistory.php +++ b/src/DTO/Workflow/InstanceHistory.php @@ -2,6 +2,7 @@ namespace CodebarAg\DocuWare\DTO\Workflow; +use CodebarAg\DocuWare\Support\JsonArrays; use Illuminate\Support\Arr; use Illuminate\Support\Carbon; use Illuminate\Support\Collection; @@ -9,6 +10,9 @@ final class InstanceHistory { + /** + * @param array $data + */ public static function fromJson(array $data): self { if ($startDateTime = Arr::get($data, 'StartedAt')) { @@ -16,8 +20,11 @@ public static function fromJson(array $data): self $startDateTime = Carbon::createFromTimestamp($startDateTime); } - if ($historySteps = Arr::get($data, 'HistorySteps')) { - $historySteps = collect($historySteps)->map(fn (array $historyStep) => HistoryStep::fromJson($historyStep)); + $historySteps = null; + $stepsRaw = Arr::get($data, 'HistorySteps'); + if (is_array($stepsRaw)) { + $historySteps = collect(JsonArrays::listOfRecords($stepsRaw)) + ->map(fn (array $historyStep) => HistoryStep::fromJson($historyStep)); } return new self( @@ -32,6 +39,9 @@ public static function fromJson(array $data): self ); } + /** + * @param Collection|null $historySteps + */ public function __construct( public string $id, public string $workflowId, diff --git a/src/DocuWareSearchRequestBuilder.php b/src/DocuWareSearchRequestBuilder.php index f3283c67..6ea14a34 100644 --- a/src/DocuWareSearchRequestBuilder.php +++ b/src/DocuWareSearchRequestBuilder.php @@ -100,18 +100,13 @@ public function fulltext(?string $searchTerm): self return $this; } - public function filterDate(string $name, string $operator, ?Carbon $date): self + public function filterDate(string $name, string $operator, Carbon $date): self { - if ($date === null) { - throw new \InvalidArgumentException('A date is required for date filters.'); - } - $date = $this->exactDateTime($date, $operator); $this->makeSureFilterDateRangeIsCorrect($name, $operator); $this->filters[$name][] = $date; - $this->filters[$name] = array_values($this->filters[$name]); return $this; } diff --git a/src/DocuWareUrl.php b/src/DocuWareUrl.php index be682d9a..cedda30a 100644 --- a/src/DocuWareUrl.php +++ b/src/DocuWareUrl.php @@ -96,9 +96,12 @@ public function make(): string iv: $iv, ); + $platform = trim(config('laravel-docuware.platform_path', 'DocuWare/Platform'), '/'); + return sprintf( - '%s/DocuWare/Platform/WebClient/Integration?ep=%s', - $this->url, + '%s/%s/WebClient/Integration?ep=%s', + rtrim($this->url, '/'), + $platform, URL::format($encrypted), ); } diff --git a/src/Requests/Authentication/OAuth/GetResponsibleIdentityService.php b/src/Requests/Authentication/OAuth/GetResponsibleIdentityService.php index e82fcb0a..1c94682b 100644 --- a/src/Requests/Authentication/OAuth/GetResponsibleIdentityService.php +++ b/src/Requests/Authentication/OAuth/GetResponsibleIdentityService.php @@ -25,7 +25,8 @@ public function __construct( public function resolveEndpoint(): string { $url = $this->url ?? config('laravel-docuware.credentials.url'); - $base = $url.'/DocuWare/Platform'; + $platform = trim(config('laravel-docuware.platform_path', 'DocuWare/Platform'), '/'); + $base = rtrim($url, '/').'/'.$platform; return $base.'/Home/IdentityServiceInfo'; } diff --git a/src/Requests/Authentication/OAuth/RequestTokenWithCredentials.php b/src/Requests/Authentication/OAuth/RequestTokenWithCredentials.php index 01bd572d..6b5827a3 100644 --- a/src/Requests/Authentication/OAuth/RequestTokenWithCredentials.php +++ b/src/Requests/Authentication/OAuth/RequestTokenWithCredentials.php @@ -36,6 +36,9 @@ public function defaultHeaders(): array ]; } + /** + * @return array + */ public function defaultBody(): array { return [ diff --git a/src/Requests/Authentication/OAuth/RequestTokenWithCredentialsTrustedUser.php b/src/Requests/Authentication/OAuth/RequestTokenWithCredentialsTrustedUser.php index ef4d65f6..8a11d50e 100644 --- a/src/Requests/Authentication/OAuth/RequestTokenWithCredentialsTrustedUser.php +++ b/src/Requests/Authentication/OAuth/RequestTokenWithCredentialsTrustedUser.php @@ -37,6 +37,9 @@ public function defaultHeaders(): array ]; } + /** + * @return array + */ public function defaultBody(): array { return [ diff --git a/src/Requests/Documents/ApplicationProperties/AddApplicationProperties.php b/src/Requests/Documents/ApplicationProperties/AddApplicationProperties.php index 40fd9b7b..dfb7db96 100644 --- a/src/Requests/Documents/ApplicationProperties/AddApplicationProperties.php +++ b/src/Requests/Documents/ApplicationProperties/AddApplicationProperties.php @@ -20,6 +20,9 @@ class AddApplicationProperties extends Request implements Cacheable, HasBody protected Method $method = Method::POST; + /** + * @param list> $properties + */ public function __construct( protected readonly string $fileCabinetId, protected readonly string $documentId, @@ -31,7 +34,10 @@ public function resolveEndpoint(): string return '/FileCabinets/'.$this->fileCabinetId.'/Documents/'.$this->documentId.'/DocumentApplicationProperties'; } - public function defaultBody() + /** + * @return array + */ + public function defaultBody(): array { return [ 'DocumentApplicationProperty' => $this->properties, diff --git a/src/Requests/Documents/ApplicationProperties/DeleteApplicationProperties.php b/src/Requests/Documents/ApplicationProperties/DeleteApplicationProperties.php index 67d1c4f6..5747159b 100644 --- a/src/Requests/Documents/ApplicationProperties/DeleteApplicationProperties.php +++ b/src/Requests/Documents/ApplicationProperties/DeleteApplicationProperties.php @@ -20,6 +20,9 @@ class DeleteApplicationProperties extends Request implements Cacheable, HasBody protected Method $method = Method::POST; + /** + * @param list $propertyNames + */ public function __construct( protected readonly string $fileCabinetId, protected readonly string $documentId, @@ -31,9 +34,12 @@ public function resolveEndpoint(): string return '/FileCabinets/'.$this->fileCabinetId.'/Documents/'.$this->documentId.'/DocumentApplicationProperties'; } - public function defaultBody() + /** + * @return array + */ + public function defaultBody(): array { - $props = collect($this->propertyNames)->map(function ($name) { + $props = collect($this->propertyNames)->map(function (string $name) { return [ 'Name' => $name, 'Value' => null, diff --git a/src/Requests/Documents/ApplicationProperties/UpdateApplicationProperties.php b/src/Requests/Documents/ApplicationProperties/UpdateApplicationProperties.php index 44ac8039..63259b18 100644 --- a/src/Requests/Documents/ApplicationProperties/UpdateApplicationProperties.php +++ b/src/Requests/Documents/ApplicationProperties/UpdateApplicationProperties.php @@ -20,6 +20,9 @@ class UpdateApplicationProperties extends Request implements Cacheable, HasBody protected Method $method = Method::POST; + /** + * @param list> $properties + */ public function __construct( protected readonly string $fileCabinetId, protected readonly string $documentId, @@ -31,7 +34,10 @@ public function resolveEndpoint(): string return '/FileCabinets/'.$this->fileCabinetId.'/Documents/'.$this->documentId.'/DocumentApplicationProperties'; } - public function defaultBody() + /** + * @return array + */ + public function defaultBody(): array { return [ 'DocumentApplicationProperty' => $this->properties, diff --git a/src/Requests/Documents/ClipUnclipStapleUnstaple/Clip.php b/src/Requests/Documents/ClipUnclipStapleUnstaple/Clip.php index 52cd9f52..ac8d6777 100644 --- a/src/Requests/Documents/ClipUnclipStapleUnstaple/Clip.php +++ b/src/Requests/Documents/ClipUnclipStapleUnstaple/Clip.php @@ -16,6 +16,9 @@ class Clip extends Request implements HasBody protected Method $method = Method::POST; + /** + * @param list> $documents + */ public function __construct( protected readonly string $documentTrayId, protected readonly array $documents, @@ -27,6 +30,9 @@ public function resolveEndpoint(): string return '/FileCabinets/'.$this->documentTrayId.'/Operations/ContentMerge'; } + /** + * @return array + */ public function defaultBody(): array { return [ diff --git a/src/Requests/Documents/ClipUnclipStapleUnstaple/Staple.php b/src/Requests/Documents/ClipUnclipStapleUnstaple/Staple.php index f3f86651..8522833f 100644 --- a/src/Requests/Documents/ClipUnclipStapleUnstaple/Staple.php +++ b/src/Requests/Documents/ClipUnclipStapleUnstaple/Staple.php @@ -16,6 +16,9 @@ class Staple extends Request implements HasBody protected Method $method = Method::POST; + /** + * @param list> $documents + */ public function __construct( protected readonly string $documentTrayId, protected readonly array $documents, @@ -27,6 +30,9 @@ public function resolveEndpoint(): string return '/FileCabinets/'.$this->documentTrayId.'/Operations/ContentMerge'; } + /** + * @return array + */ public function defaultBody(): array { return [ diff --git a/src/Requests/Documents/ClipUnclipStapleUnstaple/Unclip.php b/src/Requests/Documents/ClipUnclipStapleUnstaple/Unclip.php index 352df770..6f392000 100644 --- a/src/Requests/Documents/ClipUnclipStapleUnstaple/Unclip.php +++ b/src/Requests/Documents/ClipUnclipStapleUnstaple/Unclip.php @@ -33,6 +33,9 @@ public function defaultQuery(): array ]; } + /** + * @return array + */ public function defaultBody(): array { return [ diff --git a/src/Requests/Documents/ClipUnclipStapleUnstaple/Unstaple.php b/src/Requests/Documents/ClipUnclipStapleUnstaple/Unstaple.php index 7d4f861c..98b166ee 100644 --- a/src/Requests/Documents/ClipUnclipStapleUnstaple/Unstaple.php +++ b/src/Requests/Documents/ClipUnclipStapleUnstaple/Unstaple.php @@ -33,6 +33,9 @@ public function defaultQuery(): array ]; } + /** + * @return array + */ public function defaultBody(): array { return [ diff --git a/src/Requests/Documents/DocumentsTrashBin/DeleteDocuments.php b/src/Requests/Documents/DocumentsTrashBin/DeleteDocuments.php index e935c1e3..b2e62689 100644 --- a/src/Requests/Documents/DocumentsTrashBin/DeleteDocuments.php +++ b/src/Requests/Documents/DocumentsTrashBin/DeleteDocuments.php @@ -17,6 +17,9 @@ class DeleteDocuments extends Request implements HasBody protected Method $method = Method::POST; + /** + * @param array|Collection $ids + */ public function __construct( protected readonly array|Collection $ids = [], ) {} @@ -26,6 +29,9 @@ public function resolveEndpoint(): string return '/TrashBin/BatchDelete'; } + /** + * @return array + */ public function defaultBody(): array { return [ diff --git a/src/Requests/Documents/DocumentsTrashBin/GetDocuments.php b/src/Requests/Documents/DocumentsTrashBin/GetDocuments.php index 71466142..61f32198 100644 --- a/src/Requests/Documents/DocumentsTrashBin/GetDocuments.php +++ b/src/Requests/Documents/DocumentsTrashBin/GetDocuments.php @@ -21,6 +21,9 @@ class GetDocuments extends Request implements Cacheable, HasBody protected Method $method = Method::POST; + /** + * @param array $condition + */ public function __construct( protected readonly int $page = 1, protected readonly int $perPage = 50, @@ -46,6 +49,9 @@ public function cacheExpiryInSeconds(): int return config('laravel-docuware.configurations.cache.lifetime_in_seconds', 3600); } + /** + * @return array + */ public function defaultBody(): array { return [ diff --git a/src/Requests/Documents/DocumentsTrashBin/RestoreDocuments.php b/src/Requests/Documents/DocumentsTrashBin/RestoreDocuments.php index 33b29adc..2415a6ca 100644 --- a/src/Requests/Documents/DocumentsTrashBin/RestoreDocuments.php +++ b/src/Requests/Documents/DocumentsTrashBin/RestoreDocuments.php @@ -17,6 +17,9 @@ class RestoreDocuments extends Request implements HasBody protected Method $method = Method::POST; + /** + * @param array|Collection $ids + */ public function __construct( protected readonly array|Collection $ids = [], ) {} @@ -26,6 +29,9 @@ public function resolveEndpoint(): string return '/TrashBin/BatchRestore'; } + /** + * @return array + */ public function defaultBody(): array { return [ diff --git a/src/Requests/Documents/ModifyDocuments/TransferDocument.php b/src/Requests/Documents/ModifyDocuments/TransferDocument.php index b80a2a96..f6d7b7c4 100644 --- a/src/Requests/Documents/ModifyDocuments/TransferDocument.php +++ b/src/Requests/Documents/ModifyDocuments/TransferDocument.php @@ -2,9 +2,17 @@ namespace CodebarAg\DocuWare\Requests\Documents\ModifyDocuments; -use Arr; +use CodebarAg\DocuWare\DTO\Documents\DocumentIndex\IndexDateDTO; +use CodebarAg\DocuWare\DTO\Documents\DocumentIndex\IndexDateTimeDTO; +use CodebarAg\DocuWare\DTO\Documents\DocumentIndex\IndexDecimalDTO; +use CodebarAg\DocuWare\DTO\Documents\DocumentIndex\IndexKeywordDTO; +use CodebarAg\DocuWare\DTO\Documents\DocumentIndex\IndexMemoDTO; +use CodebarAg\DocuWare\DTO\Documents\DocumentIndex\IndexNumericDTO; +use CodebarAg\DocuWare\DTO\Documents\DocumentIndex\IndexTableDTO; +use CodebarAg\DocuWare\DTO\Documents\DocumentIndex\IndexTextDTO; use CodebarAg\DocuWare\DTO\Documents\DocumentIndex\PrepareDTO; use CodebarAg\DocuWare\Responses\Documents\ModifyDocuments\TransferDocumentResponse; +use Illuminate\Support\Arr; use Illuminate\Support\Collection; use Saloon\Contracts\Body\HasBody; use Saloon\Enums\Method; @@ -18,6 +26,9 @@ class TransferDocument extends Request implements HasBody protected Method $method = Method::POST; + /** + * @param Collection|null $fields + */ public function __construct( protected readonly string $fileCabinetId, protected readonly string $destinationFileCabinetId, @@ -49,6 +60,9 @@ protected function defaultHeaders(): array ]; } + /** + * @return array + */ protected function defaultBody(): array { $body = [ diff --git a/src/Requests/Documents/Sections/GetAllSectionsFromADocument.php b/src/Requests/Documents/Sections/GetAllSectionsFromADocument.php index eb106e3b..b8a9e22b 100644 --- a/src/Requests/Documents/Sections/GetAllSectionsFromADocument.php +++ b/src/Requests/Documents/Sections/GetAllSectionsFromADocument.php @@ -2,9 +2,9 @@ namespace CodebarAg\DocuWare\Requests\Documents\Sections; +use CodebarAg\DocuWare\DTO\Section; use CodebarAg\DocuWare\Responses\Documents\Sections\GetAllSectionsFromADocumentResponse; use Illuminate\Support\Collection; -use Illuminate\Support\Enumerable; use Illuminate\Support\Facades\Cache; use Saloon\CachePlugin\Contracts\Cacheable; use Saloon\CachePlugin\Drivers\LaravelCacheDriver; @@ -46,7 +46,10 @@ public function cacheExpiryInSeconds(): int return config('laravel-docuware.configurations.cache.lifetime_in_seconds', 3600); } - public function createDtoFromResponse(Response $response): Collection|Enumerable + /** + * @return Collection + */ + public function createDtoFromResponse(Response $response): Collection { return GetAllSectionsFromADocumentResponse::fromResponse($response); } diff --git a/src/Requests/Documents/Stamps/AddDocumentAnnotations.php b/src/Requests/Documents/Stamps/AddDocumentAnnotations.php new file mode 100644 index 00000000..10fa2e45 --- /dev/null +++ b/src/Requests/Documents/Stamps/AddDocumentAnnotations.php @@ -0,0 +1,58 @@ + $payload e.g. ["Annotations" => [...]] + */ + public function __construct( + protected readonly string $fileCabinetId, + protected readonly int|string $documentId, + protected readonly array $payload, + ) {} + + public function resolveEndpoint(): string + { + return '/FileCabinets/'.$this->fileCabinetId.'/Documents/'.$this->documentId.'/Annotation'; + } + + /** + * @return array + */ + protected function defaultBody(): array + { + return $this->payload; + } + + /** + * @return array + */ + public function createDtoFromResponse(Response $response): array + { + event(new DocuWareResponseLog($response)); + + EnsureValidResponse::from($response); + + /** @var array $json */ + $json = $response->throw()->json(); + + return $json; + } +} diff --git a/src/Requests/Documents/Stamps/GetStamps.php b/src/Requests/Documents/Stamps/GetStamps.php new file mode 100644 index 00000000..a9203390 --- /dev/null +++ b/src/Requests/Documents/Stamps/GetStamps.php @@ -0,0 +1,39 @@ +fileCabinetId.'/Stamps'; + } + + /** + * @return Collection> + */ + public function createDtoFromResponse(Response $response): Collection + { + event(new DocuWareResponseLog($response)); + + EnsureValidResponse::from($response); + + $raw = $response->throw()->json('Stamp'); + + return collect(JsonArrays::listOfRecords($raw)); + } +} diff --git a/src/Requests/Documents/UpdateIndexValues/UpdateIndexValues.php b/src/Requests/Documents/UpdateIndexValues/UpdateIndexValues.php index add916dc..512188c9 100644 --- a/src/Requests/Documents/UpdateIndexValues/UpdateIndexValues.php +++ b/src/Requests/Documents/UpdateIndexValues/UpdateIndexValues.php @@ -2,6 +2,14 @@ namespace CodebarAg\DocuWare\Requests\Documents\UpdateIndexValues; +use CodebarAg\DocuWare\DTO\Documents\DocumentIndex\IndexDateDTO; +use CodebarAg\DocuWare\DTO\Documents\DocumentIndex\IndexDateTimeDTO; +use CodebarAg\DocuWare\DTO\Documents\DocumentIndex\IndexDecimalDTO; +use CodebarAg\DocuWare\DTO\Documents\DocumentIndex\IndexKeywordDTO; +use CodebarAg\DocuWare\DTO\Documents\DocumentIndex\IndexMemoDTO; +use CodebarAg\DocuWare\DTO\Documents\DocumentIndex\IndexNumericDTO; +use CodebarAg\DocuWare\DTO\Documents\DocumentIndex\IndexTableDTO; +use CodebarAg\DocuWare\DTO\Documents\DocumentIndex\IndexTextDTO; use CodebarAg\DocuWare\DTO\Documents\DocumentIndex\PrepareDTO; use CodebarAg\DocuWare\Responses\Documents\UpdateIndexValues\UpdateIndexValuesResponse; use Illuminate\Support\Collection; @@ -17,6 +25,9 @@ class UpdateIndexValues extends Request implements HasBody protected Method $method = Method::PUT; + /** + * @param Collection|null $indexes + */ public function __construct( protected readonly string $fileCabinetId, protected readonly string $documentId, @@ -29,6 +40,9 @@ public function resolveEndpoint(): string return '/FileCabinets/'.$this->fileCabinetId.'/Documents/'.$this->documentId.'/Fields'; } + /** + * @return array + */ public function defaultBody(): array { $body = []; @@ -43,6 +57,9 @@ public function defaultBody(): array } + /** + * @return Collection + */ public function createDtoFromResponse(Response $response): Collection { return UpdateIndexValuesResponse::fromResponse($response); diff --git a/src/Requests/Fields/GetFieldsRequest.php b/src/Requests/Fields/GetFieldsRequest.php index 614b9e10..7fc42b73 100644 --- a/src/Requests/Fields/GetFieldsRequest.php +++ b/src/Requests/Fields/GetFieldsRequest.php @@ -2,9 +2,9 @@ namespace CodebarAg\DocuWare\Requests\Fields; +use CodebarAg\DocuWare\DTO\Documents\Field; use CodebarAg\DocuWare\Responses\Fields\GetFieldsResponse; use Illuminate\Support\Collection; -use Illuminate\Support\Enumerable; use Illuminate\Support\Facades\Cache; use Saloon\CachePlugin\Contracts\Cacheable; use Saloon\CachePlugin\Drivers\LaravelCacheDriver; @@ -38,7 +38,10 @@ public function cacheExpiryInSeconds(): int return config('laravel-docuware.configurations.cache.lifetime_in_seconds', 3600); } - public function createDtoFromResponse(Response $response): Collection|Enumerable + /** + * @return Collection + */ + public function createDtoFromResponse(Response $response): Collection { return GetFieldsResponse::fromResponse($response); } diff --git a/src/Requests/FileCabinets/Batch/BatchDocumentsUpdateFields.php b/src/Requests/FileCabinets/Batch/BatchDocumentsUpdateFields.php new file mode 100644 index 00000000..1b8d8179 --- /dev/null +++ b/src/Requests/FileCabinets/Batch/BatchDocumentsUpdateFields.php @@ -0,0 +1,61 @@ + + */ +final class BatchDocumentsUpdateFields extends Request implements HasBody +{ + use HasJsonBody; + + protected Method $method = Method::POST; + + /** + * @param array $payload + */ + public function __construct( + protected readonly string $fileCabinetId, + protected readonly array $payload, + ) {} + + public function resolveEndpoint(): string + { + return '/FileCabinets/'.$this->fileCabinetId.'/Operations/BatchDocumentsUpdateFields'; + } + + /** + * @return array + */ + protected function defaultBody(): array + { + return $this->payload; + } + + /** + * @return array + */ + public function createDtoFromResponse(Response $response): array + { + event(new DocuWareResponseLog($response)); + + EnsureValidResponse::from($response); + + /** @var array $json */ + $json = $response->throw()->json(); + + return $json; + } +} diff --git a/src/Requests/FileCabinets/CheckInCheckOut/CheckInDocumentFromFileSystem.php b/src/Requests/FileCabinets/CheckInCheckOut/CheckInDocumentFromFileSystem.php new file mode 100644 index 00000000..20812c40 --- /dev/null +++ b/src/Requests/FileCabinets/CheckInCheckOut/CheckInDocumentFromFileSystem.php @@ -0,0 +1,54 @@ +fileCabinetId.'/Documents/'.$this->documentId.'/CheckInFromFileSystem'; + } + + /** + * @return list + */ + protected function defaultBody(): array + { + return [ + new MultipartValue(name: 'CheckIn', value: $this->checkInJson, filename: 'CheckIn.json'), + new MultipartValue(name: 'File[]', value: $this->fileContent, filename: $this->fileName), + ]; + } + + public function createDtoFromResponse(Response $response): Document + { + return GetASpecificDocumentFromAFileCabinetResponse::fromResponse($response); + } +} diff --git a/src/Requests/FileCabinets/CheckInCheckOut/CheckoutDocumentToFileSystem.php b/src/Requests/FileCabinets/CheckInCheckOut/CheckoutDocumentToFileSystem.php new file mode 100644 index 00000000..8e72bb75 --- /dev/null +++ b/src/Requests/FileCabinets/CheckInCheckOut/CheckoutDocumentToFileSystem.php @@ -0,0 +1,28 @@ +fileCabinetId.'/Documents/'.$this->documentId.'/CheckoutToFileSystem'; + } + + public function createDtoFromResponse(Response $response): CheckoutToFileSystemResult + { + return CheckoutToFileSystemResult::fromResponse($response); + } +} diff --git a/src/Requests/FileCabinets/CheckInCheckOut/UndoDocumentCheckout.php b/src/Requests/FileCabinets/CheckInCheckOut/UndoDocumentCheckout.php new file mode 100644 index 00000000..5feeb36b --- /dev/null +++ b/src/Requests/FileCabinets/CheckInCheckOut/UndoDocumentCheckout.php @@ -0,0 +1,43 @@ +fileCabinetId.'/Operations/ProcessDocumentAction?DocId='.$this->documentId; + } + + /** + * @return array + */ + protected function defaultBody(): array + { + return [ + 'DocumentAction' => 'UndoCheckOut', + ]; + } + + public function createDtoFromResponse(Response $response): Document + { + return GetASpecificDocumentFromAFileCabinetResponse::fromResponse($response); + } +} diff --git a/src/Requests/FileCabinets/Search/GetDocumentsFromAFileCabinet.php b/src/Requests/FileCabinets/Search/GetDocumentsFromAFileCabinet.php index 537611df..b7cd0eba 100644 --- a/src/Requests/FileCabinets/Search/GetDocumentsFromAFileCabinet.php +++ b/src/Requests/FileCabinets/Search/GetDocumentsFromAFileCabinet.php @@ -18,6 +18,9 @@ class GetDocumentsFromAFileCabinet extends Request implements Cacheable protected Method $method = Method::GET; + /** + * @param list $fields + */ public function __construct( protected readonly string $fileCabinetId, protected readonly array $fields = [], diff --git a/src/Requests/FileCabinets/Upload/AppendASinglePDFToADocument.php b/src/Requests/FileCabinets/Upload/AppendASinglePDFToADocument.php index eca8114d..54ab68f2 100644 --- a/src/Requests/FileCabinets/Upload/AppendASinglePDFToADocument.php +++ b/src/Requests/FileCabinets/Upload/AppendASinglePDFToADocument.php @@ -37,6 +37,9 @@ protected function defaultQuery(): array ]; } + /** + * @return list + */ protected function defaultBody(): array { return [ diff --git a/src/Requests/FileCabinets/Upload/AppendFilesToADataRecord.php b/src/Requests/FileCabinets/Upload/AppendFilesToADataRecord.php index 6fb25a87..6f098824 100644 --- a/src/Requests/FileCabinets/Upload/AppendFilesToADataRecord.php +++ b/src/Requests/FileCabinets/Upload/AppendFilesToADataRecord.php @@ -6,6 +6,7 @@ use CodebarAg\DocuWare\Responses\FileCabinets\Upload\CreateDataRecordResponse; use Illuminate\Support\Collection; use Saloon\Contracts\Body\HasBody; +use Saloon\Data\MultipartValue; use Saloon\Enums\Method; use Saloon\Http\Request; use Saloon\Http\Response; @@ -17,6 +18,9 @@ class AppendFilesToADataRecord extends Request implements HasBody protected Method $method = Method::POST; + /** + * @param Collection $files + */ public function __construct( protected readonly string $fileCabinetId, protected readonly string $dataRecordId, @@ -28,6 +32,9 @@ public function resolveEndpoint(): string return '/FileCabinets/'.$this->fileCabinetId.'/Documents/'.$this->dataRecordId; } + /** + * @return list + */ protected function defaultBody(): array { return $this->files->toArray(); diff --git a/src/Requests/FileCabinets/Upload/CreateDataRecord.php b/src/Requests/FileCabinets/Upload/CreateDataRecord.php index fb44e8a6..994964ba 100644 --- a/src/Requests/FileCabinets/Upload/CreateDataRecord.php +++ b/src/Requests/FileCabinets/Upload/CreateDataRecord.php @@ -3,6 +3,14 @@ namespace CodebarAg\DocuWare\Requests\FileCabinets\Upload; use CodebarAg\DocuWare\DTO\Documents\Document; +use CodebarAg\DocuWare\DTO\Documents\DocumentIndex\IndexDateDTO; +use CodebarAg\DocuWare\DTO\Documents\DocumentIndex\IndexDateTimeDTO; +use CodebarAg\DocuWare\DTO\Documents\DocumentIndex\IndexDecimalDTO; +use CodebarAg\DocuWare\DTO\Documents\DocumentIndex\IndexKeywordDTO; +use CodebarAg\DocuWare\DTO\Documents\DocumentIndex\IndexMemoDTO; +use CodebarAg\DocuWare\DTO\Documents\DocumentIndex\IndexNumericDTO; +use CodebarAg\DocuWare\DTO\Documents\DocumentIndex\IndexTableDTO; +use CodebarAg\DocuWare\DTO\Documents\DocumentIndex\IndexTextDTO; use CodebarAg\DocuWare\DTO\Documents\DocumentIndex\PrepareDTO; use CodebarAg\DocuWare\Responses\FileCabinets\Upload\CreateDataRecordResponse; use Illuminate\Support\Collection; @@ -19,18 +27,31 @@ class CreateDataRecord extends Request implements HasBody protected Method $method = Method::POST; + /** + * @param Collection|null $indexes + */ public function __construct( protected readonly string $fileCabinetId, protected readonly ?string $fileContent, protected readonly ?string $fileName, protected readonly ?Collection $indexes = null, + protected readonly ?string $storeDialogId = null, ) {} public function resolveEndpoint(): string { - return '/FileCabinets/'.$this->fileCabinetId.'/Documents'; + $path = '/FileCabinets/'.$this->fileCabinetId.'/Documents'; + + if ($this->storeDialogId !== null && $this->storeDialogId !== '') { + $path .= '?StoreDialogId='.rawurlencode($this->storeDialogId); + } + + return $path; } + /** + * @return list + */ protected function defaultBody(): array { $body = []; diff --git a/src/Requests/FileCabinets/Upload/ReplaceAPDFDocumentSection.php b/src/Requests/FileCabinets/Upload/ReplaceAPDFDocumentSection.php index dd64e7a2..4de2ca90 100644 --- a/src/Requests/FileCabinets/Upload/ReplaceAPDFDocumentSection.php +++ b/src/Requests/FileCabinets/Upload/ReplaceAPDFDocumentSection.php @@ -37,6 +37,9 @@ protected function defaultQuery(): array ]; } + /** + * @return list + */ protected function defaultBody(): array { return [ diff --git a/src/Requests/General/Organization/GetAllFileCabinetsAndDocumentTrays.php b/src/Requests/General/Organization/GetAllFileCabinetsAndDocumentTrays.php index 06a31e48..cdffe3fb 100644 --- a/src/Requests/General/Organization/GetAllFileCabinetsAndDocumentTrays.php +++ b/src/Requests/General/Organization/GetAllFileCabinetsAndDocumentTrays.php @@ -2,9 +2,9 @@ namespace CodebarAg\DocuWare\Requests\General\Organization; +use CodebarAg\DocuWare\DTO\General\Organization\FileCabinet; use CodebarAg\DocuWare\Responses\General\Organization\GetAllFileCabinetsAndDocumentTraysResponse; use Illuminate\Support\Collection; -use Illuminate\Support\Enumerable; use Illuminate\Support\Facades\Cache; use Saloon\CachePlugin\Contracts\Cacheable; use Saloon\CachePlugin\Drivers\LaravelCacheDriver; @@ -48,7 +48,10 @@ public function cacheExpiryInSeconds(): int return config('laravel-docuware.configurations.cache.lifetime_in_seconds', 3600); } - public function createDtoFromResponse(Response $response): Collection|Enumerable + /** + * @return Collection + */ + public function createDtoFromResponse(Response $response): Collection { return GetAllFileCabinetsAndDocumentTraysResponse::fromResponse($response); } diff --git a/src/Requests/General/Organization/GetLoginToken.php b/src/Requests/General/Organization/GetLoginToken.php index 12f65fb6..7385b3e1 100644 --- a/src/Requests/General/Organization/GetLoginToken.php +++ b/src/Requests/General/Organization/GetLoginToken.php @@ -20,6 +20,9 @@ class GetLoginToken extends Request implements Cacheable, HasBody protected Method $method = Method::POST; + /** + * @param list $targetProducts + */ public function __construct( public array $targetProducts = ['PlatformService'], public string $usage = 'Multi', @@ -31,6 +34,9 @@ public function resolveEndpoint(): string return '/Organization/LoginToken'; } + /** + * @return array + */ protected function defaultBody(): array { return [ diff --git a/src/Requests/General/Organization/GetOrganization.php b/src/Requests/General/Organization/GetOrganization.php index 1518ebb8..d65176f7 100644 --- a/src/Requests/General/Organization/GetOrganization.php +++ b/src/Requests/General/Organization/GetOrganization.php @@ -2,9 +2,9 @@ namespace CodebarAg\DocuWare\Requests\General\Organization; +use CodebarAg\DocuWare\DTO\General\Organization\Organization; use CodebarAg\DocuWare\Responses\General\Organization\GetOrganizationResponse; use Illuminate\Support\Collection; -use Illuminate\Support\Enumerable; use Illuminate\Support\Facades\Cache; use Saloon\CachePlugin\Contracts\Cacheable; use Saloon\CachePlugin\Drivers\LaravelCacheDriver; @@ -34,7 +34,10 @@ public function cacheExpiryInSeconds(): int return config('laravel-docuware.configurations.cache.lifetime_in_seconds', 3600); } - public function createDtoFromResponse(Response $response): Collection|Enumerable + /** + * @return Collection + */ + public function createDtoFromResponse(Response $response): Collection { return GetOrganizationResponse::fromResponse($response); } diff --git a/src/Requests/General/UserManagement/CreateUpdateUsers/CreateUser.php b/src/Requests/General/UserManagement/CreateUpdateUsers/CreateUser.php index ec6cb16c..8fe8cb7f 100644 --- a/src/Requests/General/UserManagement/CreateUpdateUsers/CreateUser.php +++ b/src/Requests/General/UserManagement/CreateUpdateUsers/CreateUser.php @@ -38,6 +38,9 @@ public function defaultHeaders(): array ]; } + /** + * @return array + */ protected function defaultBody(): array { return [ diff --git a/src/Requests/General/UserManagement/CreateUpdateUsers/UpdateUser.php b/src/Requests/General/UserManagement/CreateUpdateUsers/UpdateUser.php index 2d06e910..75097d76 100644 --- a/src/Requests/General/UserManagement/CreateUpdateUsers/UpdateUser.php +++ b/src/Requests/General/UserManagement/CreateUpdateUsers/UpdateUser.php @@ -37,6 +37,9 @@ public function defaultHeaders(): array ]; } + /** + * @return array + */ protected function defaultBody(): array { return [ diff --git a/src/Requests/General/UserManagement/GetModifyGroups/AddUserToAGroup.php b/src/Requests/General/UserManagement/GetModifyGroups/AddUserToAGroup.php index 00db60de..b4de5f42 100644 --- a/src/Requests/General/UserManagement/GetModifyGroups/AddUserToAGroup.php +++ b/src/Requests/General/UserManagement/GetModifyGroups/AddUserToAGroup.php @@ -16,6 +16,9 @@ class AddUserToAGroup extends Request implements HasBody protected Method $method = Method::PUT; + /** + * @param list $ids + */ public function __construct( public string $userId, public array $ids @@ -33,6 +36,9 @@ protected function defaultQuery(): array ]; } + /** + * @return array + */ protected function defaultBody(): array { return [ diff --git a/src/Requests/General/UserManagement/GetModifyGroups/GetAllGroupsForASpecificUser.php b/src/Requests/General/UserManagement/GetModifyGroups/GetAllGroupsForASpecificUser.php index 7d3812b7..c9ea7969 100644 --- a/src/Requests/General/UserManagement/GetModifyGroups/GetAllGroupsForASpecificUser.php +++ b/src/Requests/General/UserManagement/GetModifyGroups/GetAllGroupsForASpecificUser.php @@ -2,9 +2,9 @@ namespace CodebarAg\DocuWare\Requests\General\UserManagement\GetModifyGroups; +use CodebarAg\DocuWare\DTO\General\UserManagement\GetModifyGroups\Group; use CodebarAg\DocuWare\Responses\General\UserManagement\GetModifyGroups\GetGroupsResponse; use Illuminate\Support\Collection; -use Illuminate\Support\Enumerable; use Illuminate\Support\Facades\Cache; use Saloon\CachePlugin\Contracts\Cacheable; use Saloon\CachePlugin\Drivers\LaravelCacheDriver; @@ -49,7 +49,10 @@ public function cacheExpiryInSeconds(): int return config('laravel-docuware.configurations.cache.lifetime_in_seconds', 3600); } - public function createDtoFromResponse(Response $response): Enumerable|Collection + /** + * @return Collection + */ + public function createDtoFromResponse(Response $response): Collection { return GetGroupsResponse::fromResponse($response); } diff --git a/src/Requests/General/UserManagement/GetModifyGroups/GetGroups.php b/src/Requests/General/UserManagement/GetModifyGroups/GetGroups.php index bfcb872f..c2eee8a7 100644 --- a/src/Requests/General/UserManagement/GetModifyGroups/GetGroups.php +++ b/src/Requests/General/UserManagement/GetModifyGroups/GetGroups.php @@ -2,9 +2,9 @@ namespace CodebarAg\DocuWare\Requests\General\UserManagement\GetModifyGroups; +use CodebarAg\DocuWare\DTO\General\UserManagement\GetModifyGroups\Group; use CodebarAg\DocuWare\Responses\General\UserManagement\GetModifyGroups\GetGroupsResponse; use Illuminate\Support\Collection; -use Illuminate\Support\Enumerable; use Illuminate\Support\Facades\Cache; use Saloon\CachePlugin\Contracts\Cacheable; use Saloon\CachePlugin\Drivers\LaravelCacheDriver; @@ -47,7 +47,10 @@ public function cacheExpiryInSeconds(): int return config('laravel-docuware.configurations.cache.lifetime_in_seconds', 3600); } - public function createDtoFromResponse(Response $response): Enumerable|Collection + /** + * @return Collection + */ + public function createDtoFromResponse(Response $response): Collection { return GetGroupsResponse::fromResponse($response); } diff --git a/src/Requests/General/UserManagement/GetModifyGroups/RemoveUserFromAGroup.php b/src/Requests/General/UserManagement/GetModifyGroups/RemoveUserFromAGroup.php index a1a04cf6..b24b8cc9 100644 --- a/src/Requests/General/UserManagement/GetModifyGroups/RemoveUserFromAGroup.php +++ b/src/Requests/General/UserManagement/GetModifyGroups/RemoveUserFromAGroup.php @@ -16,6 +16,9 @@ class RemoveUserFromAGroup extends Request implements HasBody protected Method $method = Method::PUT; + /** + * @param list $ids + */ public function __construct( public string $userId, public array $ids @@ -33,6 +36,9 @@ protected function defaultQuery(): array ]; } + /** + * @return array + */ protected function defaultBody(): array { return [ diff --git a/src/Requests/General/UserManagement/GetModifyRoles/AddUserToARole.php b/src/Requests/General/UserManagement/GetModifyRoles/AddUserToARole.php index f61095b2..7f7b09cf 100644 --- a/src/Requests/General/UserManagement/GetModifyRoles/AddUserToARole.php +++ b/src/Requests/General/UserManagement/GetModifyRoles/AddUserToARole.php @@ -16,6 +16,9 @@ class AddUserToARole extends Request implements HasBody protected Method $method = Method::PUT; + /** + * @param list $ids + */ public function __construct( public string $userId, public array $ids @@ -33,6 +36,9 @@ protected function defaultQuery(): array ]; } + /** + * @return array + */ protected function defaultBody(): array { return [ diff --git a/src/Requests/General/UserManagement/GetModifyRoles/GetAllRolesForASpecificUser.php b/src/Requests/General/UserManagement/GetModifyRoles/GetAllRolesForASpecificUser.php index 5d2b70ba..64cc7c0e 100644 --- a/src/Requests/General/UserManagement/GetModifyRoles/GetAllRolesForASpecificUser.php +++ b/src/Requests/General/UserManagement/GetModifyRoles/GetAllRolesForASpecificUser.php @@ -2,9 +2,9 @@ namespace CodebarAg\DocuWare\Requests\General\UserManagement\GetModifyRoles; +use CodebarAg\DocuWare\DTO\General\UserManagement\GetModifyRoles\Role; use CodebarAg\DocuWare\Responses\General\UserManagement\GetModifyRoles\GetRolesResponse; use Illuminate\Support\Collection; -use Illuminate\Support\Enumerable; use Illuminate\Support\Facades\Cache; use Saloon\CachePlugin\Contracts\Cacheable; use Saloon\CachePlugin\Drivers\LaravelCacheDriver; @@ -51,7 +51,10 @@ public function cacheExpiryInSeconds(): int return config('laravel-docuware.configurations.cache.lifetime_in_seconds', 3600); } - public function createDtoFromResponse(Response $response): Enumerable|Collection + /** + * @return Collection + */ + public function createDtoFromResponse(Response $response): Collection { return GetRolesResponse::fromResponse($response); } diff --git a/src/Requests/General/UserManagement/GetModifyRoles/GetRoles.php b/src/Requests/General/UserManagement/GetModifyRoles/GetRoles.php index 961b2518..374978bc 100644 --- a/src/Requests/General/UserManagement/GetModifyRoles/GetRoles.php +++ b/src/Requests/General/UserManagement/GetModifyRoles/GetRoles.php @@ -2,9 +2,9 @@ namespace CodebarAg\DocuWare\Requests\General\UserManagement\GetModifyRoles; +use CodebarAg\DocuWare\DTO\General\UserManagement\GetModifyRoles\Role; use CodebarAg\DocuWare\Responses\General\UserManagement\GetModifyRoles\GetRolesResponse; use Illuminate\Support\Collection; -use Illuminate\Support\Enumerable; use Illuminate\Support\Facades\Cache; use Saloon\CachePlugin\Contracts\Cacheable; use Saloon\CachePlugin\Drivers\LaravelCacheDriver; @@ -49,7 +49,10 @@ public function cacheExpiryInSeconds(): int return config('laravel-docuware.configurations.cache.lifetime_in_seconds', 3600); } - public function createDtoFromResponse(Response $response): Enumerable|Collection + /** + * @return Collection + */ + public function createDtoFromResponse(Response $response): Collection { return GetRolesResponse::fromResponse($response); } diff --git a/src/Requests/General/UserManagement/GetModifyRoles/RemoveUserFromARole.php b/src/Requests/General/UserManagement/GetModifyRoles/RemoveUserFromARole.php index abc7cf73..34d1f8bf 100644 --- a/src/Requests/General/UserManagement/GetModifyRoles/RemoveUserFromARole.php +++ b/src/Requests/General/UserManagement/GetModifyRoles/RemoveUserFromARole.php @@ -16,6 +16,9 @@ class RemoveUserFromARole extends Request implements HasBody protected Method $method = Method::PUT; + /** + * @param list $ids + */ public function __construct( public string $userId, public array $ids @@ -33,6 +36,9 @@ protected function defaultQuery(): array ]; } + /** + * @return array + */ protected function defaultBody(): array { return [ diff --git a/src/Requests/General/UserManagement/GetUsers/GetUsers.php b/src/Requests/General/UserManagement/GetUsers/GetUsers.php index 5645dc09..bd396e3b 100644 --- a/src/Requests/General/UserManagement/GetUsers/GetUsers.php +++ b/src/Requests/General/UserManagement/GetUsers/GetUsers.php @@ -2,9 +2,9 @@ namespace CodebarAg\DocuWare\Requests\General\UserManagement\GetUsers; +use CodebarAg\DocuWare\DTO\General\UserManagement\GetUsers\User; use CodebarAg\DocuWare\Responses\General\UserManagement\GetUsers\GetUsersResponse; use Illuminate\Support\Collection; -use Illuminate\Support\Enumerable; use Illuminate\Support\Facades\Cache; use Saloon\CachePlugin\Contracts\Cacheable; use Saloon\CachePlugin\Drivers\LaravelCacheDriver; @@ -47,7 +47,10 @@ public function cacheExpiryInSeconds(): int return config('laravel-docuware.configurations.cache.lifetime_in_seconds', 3600); } - public function createDtoFromResponse(Response $response): Enumerable|Collection + /** + * @return Collection + */ + public function createDtoFromResponse(Response $response): Collection { return GetUsersResponse::fromResponse($response); } diff --git a/src/Requests/General/UserManagement/GetUsers/GetUsersOfAGroup.php b/src/Requests/General/UserManagement/GetUsers/GetUsersOfAGroup.php index 753ae7b5..81de9dd8 100644 --- a/src/Requests/General/UserManagement/GetUsers/GetUsersOfAGroup.php +++ b/src/Requests/General/UserManagement/GetUsers/GetUsersOfAGroup.php @@ -2,9 +2,9 @@ namespace CodebarAg\DocuWare\Requests\General\UserManagement\GetUsers; +use CodebarAg\DocuWare\DTO\General\UserManagement\GetUsers\User; use CodebarAg\DocuWare\Responses\General\UserManagement\GetUsers\GetUsersResponse; use Illuminate\Support\Collection; -use Illuminate\Support\Enumerable; use Illuminate\Support\Facades\Cache; use Saloon\CachePlugin\Contracts\Cacheable; use Saloon\CachePlugin\Drivers\LaravelCacheDriver; @@ -45,7 +45,10 @@ public function cacheExpiryInSeconds(): int return config('laravel-docuware.configurations.cache.lifetime_in_seconds', 3600); } - public function createDtoFromResponse(Response $response): Enumerable|Collection + /** + * @return Collection + */ + public function createDtoFromResponse(Response $response): Collection { return GetUsersResponse::fromResponse($response); } diff --git a/src/Requests/General/UserManagement/GetUsers/GetUsersOfARole.php b/src/Requests/General/UserManagement/GetUsers/GetUsersOfARole.php index 217cfd2a..f08e44b6 100644 --- a/src/Requests/General/UserManagement/GetUsers/GetUsersOfARole.php +++ b/src/Requests/General/UserManagement/GetUsers/GetUsersOfARole.php @@ -2,9 +2,9 @@ namespace CodebarAg\DocuWare\Requests\General\UserManagement\GetUsers; +use CodebarAg\DocuWare\DTO\General\UserManagement\GetUsers\User; use CodebarAg\DocuWare\Responses\General\UserManagement\GetUsers\GetUsersResponse; use Illuminate\Support\Collection; -use Illuminate\Support\Enumerable; use Illuminate\Support\Facades\Cache; use Saloon\CachePlugin\Contracts\Cacheable; use Saloon\CachePlugin\Drivers\LaravelCacheDriver; @@ -47,7 +47,10 @@ public function cacheExpiryInSeconds(): int return config('laravel-docuware.configurations.cache.lifetime_in_seconds', 3600); } - public function createDtoFromResponse(Response $response): Enumerable|Collection + /** + * @return Collection + */ + public function createDtoFromResponse(Response $response): Collection { return GetUsersResponse::fromResponse($response); } diff --git a/src/Requests/Search/GetSearchRequest.php b/src/Requests/Search/GetSearchRequest.php index 2438c00f..1106a677 100644 --- a/src/Requests/Search/GetSearchRequest.php +++ b/src/Requests/Search/GetSearchRequest.php @@ -21,6 +21,10 @@ class GetSearchRequest extends Request implements Cacheable, HasBody protected Method $method = Method::POST; + /** + * @param list $additionalFileCabinetIds + * @param array $condition + */ public function __construct( protected readonly ?string $fileCabinetId, protected readonly ?string $dialogId = null, @@ -59,6 +63,9 @@ public function defaultQuery(): array return $defultQuery; } + /** + * @return array + */ public function defaultBody(): array { return [ diff --git a/src/Requests/Workflow/GetDocumentWorkflowHistory.php b/src/Requests/Workflow/GetDocumentWorkflowHistory.php index e3fd08e7..2a8ef955 100644 --- a/src/Requests/Workflow/GetDocumentWorkflowHistory.php +++ b/src/Requests/Workflow/GetDocumentWorkflowHistory.php @@ -2,6 +2,7 @@ namespace CodebarAg\DocuWare\Requests\Workflow; +use CodebarAg\DocuWare\DTO\Workflow\InstanceHistory; use CodebarAg\DocuWare\Responses\Workflow\GetDocumentWorkflowHistoryResponse; use Illuminate\Support\Collection; use Illuminate\Support\Facades\Cache; @@ -38,6 +39,9 @@ public function cacheExpiryInSeconds(): int return config('laravel-docuware.configurations.cache.lifetime_in_seconds', 3600); } + /** + * @return Collection + */ public function createDtoFromResponse(Response $response): Collection { return GetDocumentWorkflowHistoryResponse::fromResponse($response); diff --git a/src/Responses/Documents/ApplicationProperties/GetApplicationPropertiesResponse.php b/src/Responses/Documents/ApplicationProperties/GetApplicationPropertiesResponse.php index 35d9184c..7e992c69 100644 --- a/src/Responses/Documents/ApplicationProperties/GetApplicationPropertiesResponse.php +++ b/src/Responses/Documents/ApplicationProperties/GetApplicationPropertiesResponse.php @@ -4,16 +4,21 @@ use CodebarAg\DocuWare\Events\DocuWareResponseLog; use CodebarAg\DocuWare\Support\EnsureValidResponse; +use CodebarAg\DocuWare\Support\JsonArrays; +use Illuminate\Support\Collection; use Saloon\Http\Response; final class GetApplicationPropertiesResponse { - public static function fromResponse(Response $response): mixed + /** + * @return Collection> + */ + public static function fromResponse(Response $response): Collection { event(new DocuWareResponseLog($response)); EnsureValidResponse::from($response); - return collect($response->throw()->json('DocumentApplicationProperty')); + return collect(JsonArrays::listOfRecords($response->throw()->json('DocumentApplicationProperty'))); } } diff --git a/src/Responses/Documents/Sections/GetAllSectionsFromADocumentResponse.php b/src/Responses/Documents/Sections/GetAllSectionsFromADocumentResponse.php index 8388ffb5..8a9ff1f3 100644 --- a/src/Responses/Documents/Sections/GetAllSectionsFromADocumentResponse.php +++ b/src/Responses/Documents/Sections/GetAllSectionsFromADocumentResponse.php @@ -5,18 +5,22 @@ use CodebarAg\DocuWare\DTO\Section; use CodebarAg\DocuWare\Events\DocuWareResponseLog; use CodebarAg\DocuWare\Support\EnsureValidResponse; +use CodebarAg\DocuWare\Support\JsonArrays; use Illuminate\Support\Collection; -use Illuminate\Support\Enumerable; use Saloon\Http\Response; final class GetAllSectionsFromADocumentResponse { - public static function fromResponse(Response $response): Collection|Enumerable + /** + * @return Collection + */ + public static function fromResponse(Response $response): Collection { event(new DocuWareResponseLog($response)); EnsureValidResponse::from($response); - return collect($response->throw()->json('Section'))->map(fn ($section) => Section::fromJson($section)); + return collect(JsonArrays::listOfRecords($response->throw()->json('Section'))) + ->map(fn (array $section) => Section::fromJson($section)); } } diff --git a/src/Responses/FileCabinets/Search/GetDocumentsFromAFileCabinetResponse.php b/src/Responses/FileCabinets/Search/GetDocumentsFromAFileCabinetResponse.php index c2786bd6..33049d63 100644 --- a/src/Responses/FileCabinets/Search/GetDocumentsFromAFileCabinetResponse.php +++ b/src/Responses/FileCabinets/Search/GetDocumentsFromAFileCabinetResponse.php @@ -10,7 +10,7 @@ final class GetDocumentsFromAFileCabinetResponse { - public static function fromResponse(Response $response, $page = 1, $perPage = 50): DocumentPaginator + public static function fromResponse(Response $response, int $page = 1, int $perPage = 50): DocumentPaginator { event(new DocuWareResponseLog($response)); diff --git a/src/Responses/Search/GetSearchResponse.php b/src/Responses/Search/GetSearchResponse.php index 0faa8877..430bdc75 100644 --- a/src/Responses/Search/GetSearchResponse.php +++ b/src/Responses/Search/GetSearchResponse.php @@ -10,7 +10,7 @@ final class GetSearchResponse { - public static function fromResponse(Response $response, $page, $perPage): DocumentPaginator + public static function fromResponse(Response $response, int $page, int $perPage): DocumentPaginator { event(new DocuWareResponseLog($response)); diff --git a/src/Responses/Search/GetTrashSearchResponse.php b/src/Responses/Search/GetTrashSearchResponse.php index 6cc028a2..6a9fac11 100644 --- a/src/Responses/Search/GetTrashSearchResponse.php +++ b/src/Responses/Search/GetTrashSearchResponse.php @@ -10,7 +10,7 @@ final class GetTrashSearchResponse { - public static function fromResponse(Response $response, $page, $perPage): TrashDocumentPaginator + public static function fromResponse(Response $response, int $page, int $perPage): TrashDocumentPaginator { event(new DocuWareResponseLog($response)); diff --git a/src/Support/JsonArrays.php b/src/Support/JsonArrays.php index b30405ef..ffc2683d 100644 --- a/src/Support/JsonArrays.php +++ b/src/Support/JsonArrays.php @@ -5,6 +5,22 @@ final class JsonArrays { /** + * Normalize a single JSON object/array to an associative row with string keys. + * + * @return array + */ + public static function associativeRow(mixed $raw): array + { + if (! is_array($raw)) { + return []; + } + + return self::stringKeyedRow($raw); + } + + /** + * Normalize mixed JSON (e.g. decoded list or map of rows) to a list of associative records. + * * @return list> */ public static function listOfRecords(mixed $raw): array @@ -15,11 +31,27 @@ public static function listOfRecords(mixed $raw): array $out = []; foreach (array_values($raw) as $item) { - if (is_array($item)) { - $out[] = $item; + if (! is_array($item)) { + continue; } + + $out[] = self::stringKeyedRow($item); } return $out; } + + /** + * @param array $row + * @return array + */ + private static function stringKeyedRow(array $row): array + { + $normalized = []; + foreach ($row as $key => $value) { + $normalized[(string) $key] = $value; + } + + return $normalized; + } } diff --git a/src/Support/ParseValue.php b/src/Support/ParseValue.php index 16463f05..b75e4896 100644 --- a/src/Support/ParseValue.php +++ b/src/Support/ParseValue.php @@ -30,7 +30,7 @@ public static function field( 'Int' => (int) $item, 'String' => (string) $item, 'Decimal' => (float) $item, - 'Date', 'DateTime' => self::date(is_string($item) ? $item : ''), + 'Date', 'DateTime' => is_string($item) ? self::date($item) : $default, 'Keywords' => Arr::join( is_array($item) && isset($item['Keyword']) && is_array($item['Keyword']) ? $item['Keyword'] : [], ', ' diff --git a/tests/Feature/SaloonFixtures/GetOrganizationFixtureTest.php b/tests/Feature/SaloonFixtures/GetOrganizationFixtureTest.php new file mode 100644 index 00000000..657014b4 --- /dev/null +++ b/tests/Feature/SaloonFixtures/GetOrganizationFixtureTest.php @@ -0,0 +1,26 @@ + new Fixture('get-organization'), + ]); + + $connector = (new FixtureDocuWareConnector)->withMockClient($mockClient); + + $organizations = $connector->send(new GetOrganization)->dto(); + + expect($organizations)->toHaveCount(1); + expect($organizations->first()->name)->toBe('Fixture Org'); + expect($organizations->first()->id)->toBe('org-fixture-1'); + + Event::assertDispatched(DocuWareResponseLog::class); +}); diff --git a/tests/Fixtures/saloon/get-organization.json b/tests/Fixtures/saloon/get-organization.json new file mode 100644 index 00000000..3c02f100 --- /dev/null +++ b/tests/Fixtures/saloon/get-organization.json @@ -0,0 +1,10 @@ +{ + "statusCode": 200, + "headers": { + "Content-Type": [ + "application/json; charset=utf-8" + ] + }, + "data": "{\"Organization\":[{\"Id\":\"org-fixture-1\",\"Name\":\"Fixture Org\",\"Guid\":\"aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee\",\"AdditionalInfo\":[],\"ConfigurationRights\":[]}]}", + "context": [] +} diff --git a/tests/Feature/DocuWareAuthenticationTest.php b/tests/Integration/DocuWareAuthenticationTest.php similarity index 100% rename from tests/Feature/DocuWareAuthenticationTest.php rename to tests/Integration/DocuWareAuthenticationTest.php diff --git a/tests/Feature/DocuWareTest.php b/tests/Integration/DocuWareTest.php similarity index 82% rename from tests/Feature/DocuWareTest.php rename to tests/Integration/DocuWareTest.php index 7ed6ded5..eb3af03c 100644 --- a/tests/Feature/DocuWareTest.php +++ b/tests/Integration/DocuWareTest.php @@ -1,7 +1,5 @@ validUntil(now()->addMinute()) ->make(); + $platform = trim(config('laravel-docuware.platform_path', 'DocuWare/Platform'), '/'); $endpoint = sprintf( - '%s/DocuWare/Platform/WebClient/Integration?ep=', - config('laravel-docuware.credentials.url'), + '%s/%s/WebClient/Integration?ep=', + rtrim((string) config('laravel-docuware.credentials.url'), '/'), + $platform, ); $this->assertStringStartsWith( @@ -70,9 +70,11 @@ ->validUntil(now()->addMinute()) ->make(); + $platform = trim(config('laravel-docuware.platform_path', 'DocuWare/Platform'), '/'); $endpoint = sprintf( - '%s/DocuWare/Platform/WebClient/Integration?ep=', - config('laravel-docuware.credentials.url'), + '%s/%s/WebClient/Integration?ep=', + rtrim((string) config('laravel-docuware.credentials.url'), '/'), + $platform, ); $this->assertStringStartsWith( diff --git a/tests/Feature/Requests/Documents/ApplicationProperties/ApplicationPropertiesTest.php b/tests/Integration/Requests/Documents/ApplicationProperties/ApplicationPropertiesTest.php similarity index 100% rename from tests/Feature/Requests/Documents/ApplicationProperties/ApplicationPropertiesTest.php rename to tests/Integration/Requests/Documents/ApplicationProperties/ApplicationPropertiesTest.php diff --git a/tests/Feature/Requests/Documents/ClipUnclipStapleUnstaple/ClipTest.php b/tests/Integration/Requests/Documents/ClipUnclipStapleUnstaple/ClipTest.php similarity index 100% rename from tests/Feature/Requests/Documents/ClipUnclipStapleUnstaple/ClipTest.php rename to tests/Integration/Requests/Documents/ClipUnclipStapleUnstaple/ClipTest.php diff --git a/tests/Feature/Requests/Documents/ClipUnclipStapleUnstaple/StapleTest.php b/tests/Integration/Requests/Documents/ClipUnclipStapleUnstaple/StapleTest.php similarity index 100% rename from tests/Feature/Requests/Documents/ClipUnclipStapleUnstaple/StapleTest.php rename to tests/Integration/Requests/Documents/ClipUnclipStapleUnstaple/StapleTest.php diff --git a/tests/Feature/Requests/Documents/ClipUnclipStapleUnstaple/UnclipTest.php b/tests/Integration/Requests/Documents/ClipUnclipStapleUnstaple/UnclipTest.php similarity index 100% rename from tests/Feature/Requests/Documents/ClipUnclipStapleUnstaple/UnclipTest.php rename to tests/Integration/Requests/Documents/ClipUnclipStapleUnstaple/UnclipTest.php diff --git a/tests/Feature/Requests/Documents/ClipUnclipStapleUnstaple/UnstapleTest.php b/tests/Integration/Requests/Documents/ClipUnclipStapleUnstaple/UnstapleTest.php similarity index 100% rename from tests/Feature/Requests/Documents/ClipUnclipStapleUnstaple/UnstapleTest.php rename to tests/Integration/Requests/Documents/ClipUnclipStapleUnstaple/UnstapleTest.php diff --git a/tests/Feature/Requests/Documents/DocumentsTrashBin/DeleteDocumentsFromTrashBinTest.php b/tests/Integration/Requests/Documents/DocumentsTrashBin/DeleteDocumentsFromTrashBinTest.php similarity index 100% rename from tests/Feature/Requests/Documents/DocumentsTrashBin/DeleteDocumentsFromTrashBinTest.php rename to tests/Integration/Requests/Documents/DocumentsTrashBin/DeleteDocumentsFromTrashBinTest.php diff --git a/tests/Feature/Requests/Documents/DocumentsTrashBin/GetDocumentsFromTrashBinTest.php b/tests/Integration/Requests/Documents/DocumentsTrashBin/GetDocumentsFromTrashBinTest.php similarity index 100% rename from tests/Feature/Requests/Documents/DocumentsTrashBin/GetDocumentsFromTrashBinTest.php rename to tests/Integration/Requests/Documents/DocumentsTrashBin/GetDocumentsFromTrashBinTest.php diff --git a/tests/Feature/Requests/Documents/DocumentsTrashBin/RestoreDocumentsFromTrashBinTest.php b/tests/Integration/Requests/Documents/DocumentsTrashBin/RestoreDocumentsFromTrashBinTest.php similarity index 100% rename from tests/Feature/Requests/Documents/DocumentsTrashBin/RestoreDocumentsFromTrashBinTest.php rename to tests/Integration/Requests/Documents/DocumentsTrashBin/RestoreDocumentsFromTrashBinTest.php diff --git a/tests/Feature/Requests/Documents/Download/DownloadDocumentTest.php b/tests/Integration/Requests/Documents/Download/DownloadDocumentTest.php similarity index 100% rename from tests/Feature/Requests/Documents/Download/DownloadDocumentTest.php rename to tests/Integration/Requests/Documents/Download/DownloadDocumentTest.php diff --git a/tests/Feature/Requests/Documents/Download/DownloadSectionTest.php b/tests/Integration/Requests/Documents/Download/DownloadSectionTest.php similarity index 100% rename from tests/Feature/Requests/Documents/Download/DownloadSectionTest.php rename to tests/Integration/Requests/Documents/Download/DownloadSectionTest.php diff --git a/tests/Feature/Requests/Documents/Download/DownloadThumbnailTest.php b/tests/Integration/Requests/Documents/Download/DownloadThumbnailTest.php similarity index 100% rename from tests/Feature/Requests/Documents/Download/DownloadThumbnailTest.php rename to tests/Integration/Requests/Documents/Download/DownloadThumbnailTest.php diff --git a/tests/Feature/Requests/Documents/GetDocumentCountRequestTest.php b/tests/Integration/Requests/Documents/GetDocumentCountRequestTest.php similarity index 100% rename from tests/Feature/Requests/Documents/GetDocumentCountRequestTest.php rename to tests/Integration/Requests/Documents/GetDocumentCountRequestTest.php diff --git a/tests/Feature/Requests/Documents/GetDocumentPreviewRequestTest.php b/tests/Integration/Requests/Documents/GetDocumentPreviewRequestTest.php similarity index 100% rename from tests/Feature/Requests/Documents/GetDocumentPreviewRequestTest.php rename to tests/Integration/Requests/Documents/GetDocumentPreviewRequestTest.php diff --git a/tests/Feature/Requests/Documents/PostDocumentRequestTest.php b/tests/Integration/Requests/Documents/PostDocumentRequestTest.php similarity index 100% rename from tests/Feature/Requests/Documents/PostDocumentRequestTest.php rename to tests/Integration/Requests/Documents/PostDocumentRequestTest.php diff --git a/tests/Feature/Requests/Documents/PutDocumentFieldsRequestTest.php b/tests/Integration/Requests/Documents/PutDocumentFieldsRequestTest.php similarity index 100% rename from tests/Feature/Requests/Documents/PutDocumentFieldsRequestTest.php rename to tests/Integration/Requests/Documents/PutDocumentFieldsRequestTest.php diff --git a/tests/Feature/Requests/Documents/Sections/DeleteSectionTest.php b/tests/Integration/Requests/Documents/Sections/DeleteSectionTest.php similarity index 100% rename from tests/Feature/Requests/Documents/Sections/DeleteSectionTest.php rename to tests/Integration/Requests/Documents/Sections/DeleteSectionTest.php diff --git a/tests/Feature/Requests/Documents/Sections/GetASpecificSectionTest.php b/tests/Integration/Requests/Documents/Sections/GetASpecificSectionTest.php similarity index 100% rename from tests/Feature/Requests/Documents/Sections/GetASpecificSectionTest.php rename to tests/Integration/Requests/Documents/Sections/GetASpecificSectionTest.php diff --git a/tests/Feature/Requests/Documents/Sections/GetAllSectionsFromADocumentTest.php b/tests/Integration/Requests/Documents/Sections/GetAllSectionsFromADocumentTest.php similarity index 100% rename from tests/Feature/Requests/Documents/Sections/GetAllSectionsFromADocumentTest.php rename to tests/Integration/Requests/Documents/Sections/GetAllSectionsFromADocumentTest.php diff --git a/tests/Feature/Requests/Documents/Sections/GetTextshotTest.php b/tests/Integration/Requests/Documents/Sections/GetTextshotTest.php similarity index 100% rename from tests/Feature/Requests/Documents/Sections/GetTextshotTest.php rename to tests/Integration/Requests/Documents/Sections/GetTextshotTest.php diff --git a/tests/Feature/Requests/Documents/Thumbnail/GetDocumentDownloadThumbnailRequestTest.php b/tests/Integration/Requests/Documents/Thumbnail/GetDocumentDownloadThumbnailRequestTest.php similarity index 100% rename from tests/Feature/Requests/Documents/Thumbnail/GetDocumentDownloadThumbnailRequestTest.php rename to tests/Integration/Requests/Documents/Thumbnail/GetDocumentDownloadThumbnailRequestTest.php diff --git a/tests/Feature/Requests/Fields/GetFieldsRequestTest.php b/tests/Integration/Requests/Fields/GetFieldsRequestTest.php similarity index 100% rename from tests/Feature/Requests/Fields/GetFieldsRequestTest.php rename to tests/Integration/Requests/Fields/GetFieldsRequestTest.php diff --git a/tests/Feature/Requests/FileCabinets/Dialogs/GetASpecificDialogTest.php b/tests/Integration/Requests/FileCabinets/Dialogs/GetASpecificDialogTest.php similarity index 100% rename from tests/Feature/Requests/FileCabinets/Dialogs/GetASpecificDialogTest.php rename to tests/Integration/Requests/FileCabinets/Dialogs/GetASpecificDialogTest.php diff --git a/tests/Feature/Requests/FileCabinets/Dialogs/GetAllDialogs.php b/tests/Integration/Requests/FileCabinets/Dialogs/GetAllDialogs.php similarity index 100% rename from tests/Feature/Requests/FileCabinets/Dialogs/GetAllDialogs.php rename to tests/Integration/Requests/FileCabinets/Dialogs/GetAllDialogs.php diff --git a/tests/Feature/Requests/FileCabinets/Dialogs/GetDialogsOfASpecificTypeTest.php b/tests/Integration/Requests/FileCabinets/Dialogs/GetDialogsOfASpecificTypeTest.php similarity index 100% rename from tests/Feature/Requests/FileCabinets/Dialogs/GetDialogsOfASpecificTypeTest.php rename to tests/Integration/Requests/FileCabinets/Dialogs/GetDialogsOfASpecificTypeTest.php diff --git a/tests/Feature/Requests/FileCabinets/General/GetFileCabinetInformationTest.php b/tests/Integration/Requests/FileCabinets/General/GetFileCabinetInformationTest.php similarity index 100% rename from tests/Feature/Requests/FileCabinets/General/GetFileCabinetInformationTest.php rename to tests/Integration/Requests/FileCabinets/General/GetFileCabinetInformationTest.php diff --git a/tests/Feature/Requests/FileCabinets/Search/GetASpecificDocumentFromAFileCabinetTest.php b/tests/Integration/Requests/FileCabinets/Search/GetASpecificDocumentFromAFileCabinetTest.php similarity index 100% rename from tests/Feature/Requests/FileCabinets/Search/GetASpecificDocumentFromAFileCabinetTest.php rename to tests/Integration/Requests/FileCabinets/Search/GetASpecificDocumentFromAFileCabinetTest.php diff --git a/tests/Feature/Requests/FileCabinets/Search/GetDocumentsFromAFileCabinetTest.php b/tests/Integration/Requests/FileCabinets/Search/GetDocumentsFromAFileCabinetTest.php similarity index 100% rename from tests/Feature/Requests/FileCabinets/Search/GetDocumentsFromAFileCabinetTest.php rename to tests/Integration/Requests/FileCabinets/Search/GetDocumentsFromAFileCabinetTest.php diff --git a/tests/Feature/Requests/FileCabinets/Upload/AppendASinglePDFToADocumentTest.php b/tests/Integration/Requests/FileCabinets/Upload/AppendASinglePDFToADocumentTest.php similarity index 100% rename from tests/Feature/Requests/FileCabinets/Upload/AppendASinglePDFToADocumentTest.php rename to tests/Integration/Requests/FileCabinets/Upload/AppendASinglePDFToADocumentTest.php diff --git a/tests/Feature/Requests/FileCabinets/Upload/AppendFilesToADataRecordTest.php b/tests/Integration/Requests/FileCabinets/Upload/AppendFilesToADataRecordTest.php similarity index 100% rename from tests/Feature/Requests/FileCabinets/Upload/AppendFilesToADataRecordTest.php rename to tests/Integration/Requests/FileCabinets/Upload/AppendFilesToADataRecordTest.php diff --git a/tests/Feature/Requests/FileCabinets/Upload/ReplaceAPDFDocumentSectionTest.php b/tests/Integration/Requests/FileCabinets/Upload/ReplaceAPDFDocumentSectionTest.php similarity index 100% rename from tests/Feature/Requests/FileCabinets/Upload/ReplaceAPDFDocumentSectionTest.php rename to tests/Integration/Requests/FileCabinets/Upload/ReplaceAPDFDocumentSectionTest.php diff --git a/tests/Feature/Requests/General/UserManagement/CreateUpdateUsers/CreateUpdateUserTest.php b/tests/Integration/Requests/General/UserManagement/CreateUpdateUsers/CreateUpdateUserTest.php similarity index 100% rename from tests/Feature/Requests/General/UserManagement/CreateUpdateUsers/CreateUpdateUserTest.php rename to tests/Integration/Requests/General/UserManagement/CreateUpdateUsers/CreateUpdateUserTest.php diff --git a/tests/Feature/Requests/General/UserManagement/GetModifyGroups/AddRemoveUserToAGroupTest.php b/tests/Integration/Requests/General/UserManagement/GetModifyGroups/AddRemoveUserToAGroupTest.php similarity index 100% rename from tests/Feature/Requests/General/UserManagement/GetModifyGroups/AddRemoveUserToAGroupTest.php rename to tests/Integration/Requests/General/UserManagement/GetModifyGroups/AddRemoveUserToAGroupTest.php diff --git a/tests/Feature/Requests/General/UserManagement/GetModifyGroups/GetAllGroupsForASpecificUserTest.php b/tests/Integration/Requests/General/UserManagement/GetModifyGroups/GetAllGroupsForASpecificUserTest.php similarity index 100% rename from tests/Feature/Requests/General/UserManagement/GetModifyGroups/GetAllGroupsForASpecificUserTest.php rename to tests/Integration/Requests/General/UserManagement/GetModifyGroups/GetAllGroupsForASpecificUserTest.php diff --git a/tests/Feature/Requests/General/UserManagement/GetModifyGroups/GetGroupsTest.php b/tests/Integration/Requests/General/UserManagement/GetModifyGroups/GetGroupsTest.php similarity index 100% rename from tests/Feature/Requests/General/UserManagement/GetModifyGroups/GetGroupsTest.php rename to tests/Integration/Requests/General/UserManagement/GetModifyGroups/GetGroupsTest.php diff --git a/tests/Feature/Requests/General/UserManagement/GetModifyRoles/AddRemoveUserToARoleTest.php b/tests/Integration/Requests/General/UserManagement/GetModifyRoles/AddRemoveUserToARoleTest.php similarity index 100% rename from tests/Feature/Requests/General/UserManagement/GetModifyRoles/AddRemoveUserToARoleTest.php rename to tests/Integration/Requests/General/UserManagement/GetModifyRoles/AddRemoveUserToARoleTest.php diff --git a/tests/Feature/Requests/General/UserManagement/GetModifyRoles/GetAllRolesForASpecificUserTest.php b/tests/Integration/Requests/General/UserManagement/GetModifyRoles/GetAllRolesForASpecificUserTest.php similarity index 100% rename from tests/Feature/Requests/General/UserManagement/GetModifyRoles/GetAllRolesForASpecificUserTest.php rename to tests/Integration/Requests/General/UserManagement/GetModifyRoles/GetAllRolesForASpecificUserTest.php diff --git a/tests/Feature/Requests/General/UserManagement/GetModifyRoles/GetRolesTest.php b/tests/Integration/Requests/General/UserManagement/GetModifyRoles/GetRolesTest.php similarity index 100% rename from tests/Feature/Requests/General/UserManagement/GetModifyRoles/GetRolesTest.php rename to tests/Integration/Requests/General/UserManagement/GetModifyRoles/GetRolesTest.php diff --git a/tests/Feature/Requests/General/UserManagement/GetUsers/GetUserByIdTest.php b/tests/Integration/Requests/General/UserManagement/GetUsers/GetUserByIdTest.php similarity index 100% rename from tests/Feature/Requests/General/UserManagement/GetUsers/GetUserByIdTest.php rename to tests/Integration/Requests/General/UserManagement/GetUsers/GetUserByIdTest.php diff --git a/tests/Feature/Requests/General/UserManagement/GetUsers/GetUsersOfAGroupTest.php b/tests/Integration/Requests/General/UserManagement/GetUsers/GetUsersOfAGroupTest.php similarity index 100% rename from tests/Feature/Requests/General/UserManagement/GetUsers/GetUsersOfAGroupTest.php rename to tests/Integration/Requests/General/UserManagement/GetUsers/GetUsersOfAGroupTest.php diff --git a/tests/Feature/Requests/General/UserManagement/GetUsers/GetUsersOfARoleTest.php b/tests/Integration/Requests/General/UserManagement/GetUsers/GetUsersOfARoleTest.php similarity index 100% rename from tests/Feature/Requests/General/UserManagement/GetUsers/GetUsersOfARoleTest.php rename to tests/Integration/Requests/General/UserManagement/GetUsers/GetUsersOfARoleTest.php diff --git a/tests/Feature/Requests/General/UserManagement/GetUsers/GetUsersTest.php b/tests/Integration/Requests/General/UserManagement/GetUsers/GetUsersTest.php similarity index 100% rename from tests/Feature/Requests/General/UserManagement/GetUsers/GetUsersTest.php rename to tests/Integration/Requests/General/UserManagement/GetUsers/GetUsersTest.php diff --git a/tests/Feature/Requests/Organization/GetOrganizationsRequestTest.php b/tests/Integration/Requests/Organization/GetOrganizationsRequestTest.php similarity index 100% rename from tests/Feature/Requests/Organization/GetOrganizationsRequestTest.php rename to tests/Integration/Requests/Organization/GetOrganizationsRequestTest.php diff --git a/tests/Feature/Requests/Search/GetSearchRequestTest.php b/tests/Integration/Requests/Search/GetSearchRequestTest.php similarity index 100% rename from tests/Feature/Requests/Search/GetSearchRequestTest.php rename to tests/Integration/Requests/Search/GetSearchRequestTest.php diff --git a/tests/Feature/Requests/SelectList/GetSelectListRequest.php b/tests/Integration/Requests/SelectList/GetSelectListRequest.php similarity index 100% rename from tests/Feature/Requests/SelectList/GetSelectListRequest.php rename to tests/Integration/Requests/SelectList/GetSelectListRequest.php diff --git a/tests/Feature/Requests/Workflow/GetDocumentWorkflowHistoryStepsTest.php b/tests/Integration/Requests/Workflow/GetDocumentWorkflowHistoryStepsTest.php similarity index 100% rename from tests/Feature/Requests/Workflow/GetDocumentWorkflowHistoryStepsTest.php rename to tests/Integration/Requests/Workflow/GetDocumentWorkflowHistoryStepsTest.php diff --git a/tests/Feature/Requests/Workflow/GetDocumentWorkflowHistoryTest.php b/tests/Integration/Requests/Workflow/GetDocumentWorkflowHistoryTest.php similarity index 100% rename from tests/Feature/Requests/Workflow/GetDocumentWorkflowHistoryTest.php rename to tests/Integration/Requests/Workflow/GetDocumentWorkflowHistoryTest.php diff --git a/tests/Manual/RecordGetOrganizationFixtureTest.php b/tests/Manual/RecordGetOrganizationFixtureTest.php new file mode 100644 index 00000000..e403e582 --- /dev/null +++ b/tests/Manual/RecordGetOrganizationFixtureTest.php @@ -0,0 +1,29 @@ +skip() below temporarily. + * 3. Run: vendor/bin/pest tests/Manual/RecordGetOrganizationFixtureTest.php + * 4. Review the JSON for secrets, then restore ->skip(). + */ + +use CodebarAg\DocuWare\Requests\General\Organization\GetOrganization; +use Saloon\Data\RecordedResponse; +use Saloon\MockConfig; + +it('records get-organization Saloon fixture', function () { + MockConfig::setFixturePath(dirname(__DIR__).'/Fixtures/saloon'); + + $response = getConnector()->send(new GetOrganization); + + $fixturePath = dirname(__DIR__).'/Fixtures/saloon/get-organization.json'; + + file_put_contents( + $fixturePath, + RecordedResponse::fromResponse($response)->toFile() + ); + + expect(file_exists($fixturePath))->toBeTrue(); +})->group('manual')->skip('Remove skip to record fixtures against a real DocuWare system.'); diff --git a/tests/Pest.php b/tests/Pest.php index 2629eb72..53bb4714 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -19,6 +19,7 @@ ->in(__DIR__); uses() + ->group('live') ->beforeEach(function () { $this->connector = getConnector(); @@ -27,7 +28,7 @@ ->afterEach(function () { setUsersInactive($this->connector); }) - ->in('Feature'); + ->in('Integration'); function clearFiles(DocuWareConnector $connector): void { diff --git a/tests/Support/FixtureDocuWareConnector.php b/tests/Support/FixtureDocuWareConnector.php new file mode 100644 index 00000000..fe2d43a2 --- /dev/null +++ b/tests/Support/FixtureDocuWareConnector.php @@ -0,0 +1,27 @@ + ':memory:', 'prefix' => '', ]); + + MockConfig::setFixturePath(__DIR__.'/Fixtures/saloon'); } }