diff --git a/composer.json b/composer.json index 4fcb682..dcf353b 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "dragon-code/laravel-feeds", - "description": "Simple generation XML feeds", + "description": "Fast export of large datasets to feeds for marketplaces and services", "license": "MIT", "type": "library", "authors": [ diff --git a/docs/labels.list b/docs/labels.list index 17544cc..632493e 100644 --- a/docs/labels.list +++ b/docs/labels.list @@ -11,4 +11,8 @@ Available for JSON feeds + + Available for JSON Lines feeds + + diff --git a/docs/laravel-feeds.tree b/docs/laravel-feeds.tree index ae75efe..41d59ab 100644 --- a/docs/laravel-feeds.tree +++ b/docs/laravel-feeds.tree @@ -12,12 +12,12 @@ - + diff --git a/docs/snippets/advanced-directive-array.xml b/docs/snippets/advanced-directive-array.xml index 8e118ea..4180cc7 100644 --- a/docs/snippets/advanced-directive-array.xml +++ b/docs/snippets/advanced-directive-array.xml @@ -2,18 +2,18 @@ - Giles Graham - https://via.placeholder.com/640x480.png/0066dd?text=ullam - https://via.placeholder.com/640x480.png/0033ff?text=autem - https://via.placeholder.com/640x480.png/00ddaa?text=voluptatibus - https://via.placeholder.com/640x480.png/00cc55?text=in + Jaiden Gerhold + https://via.placeholder.com/640x480.png/0022dd?text=aut + https://via.placeholder.com/640x480.png/00ddff?text=quia + https://via.placeholder.com/640x480.png/004400?text=enim + https://via.placeholder.com/640x480.png/0011ff?text=eveniet - Katelyn Harber - https://via.placeholder.com/640x480.png/0066dd?text=voluptatem - https://via.placeholder.com/640x480.png/004488?text=quaerat - https://via.placeholder.com/640x480.png/006655?text=ipsam - https://via.placeholder.com/640x480.png/007788?text=nam + Darien Murazik + https://via.placeholder.com/640x480.png/007700?text=vel + https://via.placeholder.com/640x480.png/00ffcc?text=nulla + https://via.placeholder.com/640x480.png/0022aa?text=dolore + https://via.placeholder.com/640x480.png/006611?text=dolorum diff --git a/docs/snippets/advanced-directive-attributes.xml b/docs/snippets/advanced-directive-attributes.xml index ac83283..1d66839 100644 --- a/docs/snippets/advanced-directive-attributes.xml +++ b/docs/snippets/advanced-directive-attributes.xml @@ -1,16 +1,16 @@ - + https://example.com - Melvina Beer - + Estell Reinger + - Vivienne Willms - + Mrs. Marilie O'Connell DDS + diff --git a/docs/snippets/advanced-directive-cdata.xml b/docs/snippets/advanced-directive-cdata.xml index 0ae74b7..e12c72f 100644 --- a/docs/snippets/advanced-directive-cdata.xml +++ b/docs/snippets/advanced-directive-cdata.xml @@ -2,12 +2,12 @@ - Elmo Hilpert]]> - alex.mohr@example.net + Jay Willms MD]]> + uerdman@example.net - Golden Sawayn]]> - jamison.ritchie@example.net + Mrs. Fae Rice]]> + kuhic.tristian@example.com diff --git a/docs/snippets/advanced-directive-mixed.xml b/docs/snippets/advanced-directive-mixed.xml index a108905..0ca9879 100644 --- a/docs/snippets/advanced-directive-mixed.xml +++ b/docs/snippets/advanced-directive-mixed.xml @@ -2,17 +2,17 @@ - Dr. Hudson Waters + Heath Cummerata Foo - macejkovic.lois@example.net + kasey.sawayn@example.org - Scarlett Walter + Dr. Levi Leannon Foo - ahaag@example.org + melany.runolfsson@example.org diff --git a/docs/snippets/advanced-directive-value.xml b/docs/snippets/advanced-directive-value.xml index 6902461..045bdd2 100644 --- a/docs/snippets/advanced-directive-value.xml +++ b/docs/snippets/advanced-directive-value.xml @@ -2,12 +2,12 @@ - Eldon Lind IV - rlarkin@example.org + Mr. Jo Emard DVM + carolina77@example.net - Miss Marcia Ebert Jr. - mayert.zackary@example.net + Nicola Moore + lkuhlman@example.com diff --git a/docs/snippets/advanced-element-attribute.xml b/docs/snippets/advanced-element-attribute.xml index 5fa8a6f..d9e6dad 100644 --- a/docs/snippets/advanced-element-attribute.xml +++ b/docs/snippets/advanced-element-attribute.xml @@ -1,13 +1,13 @@ - + 1 - Dr. Rory Streich I + Candida West - + 2 - Dr. Nikko Oberbrunner + Prof. Hilton Wuckert diff --git a/docs/snippets/advanced-element-header-footer.xml b/docs/snippets/advanced-element-header-footer.xml index 02ecc84..e6563ba 100644 --- a/docs/snippets/advanced-element-header-footer.xml +++ b/docs/snippets/advanced-element-header-footer.xml @@ -3,11 +3,11 @@ 1 - Ryann Effertz + Daija Powlowski 2 - Emely Ziemann MD + Lisa Reichel diff --git a/docs/snippets/advanced-element-info-before-false.xml b/docs/snippets/advanced-element-info-before-false.xml index 085bf9a..71ca29c 100644 --- a/docs/snippets/advanced-element-info-before-false.xml +++ b/docs/snippets/advanced-element-info-before-false.xml @@ -6,11 +6,11 @@ 1 - Suzanne Stehr + Tabitha Jakubowski 2 - Buddy Cruickshank DDS + Dr. Rachel Goyette diff --git a/docs/snippets/advanced-element-info.xml b/docs/snippets/advanced-element-info.xml index 4d10eb1..7ea6780 100644 --- a/docs/snippets/advanced-element-info.xml +++ b/docs/snippets/advanced-element-info.xml @@ -6,11 +6,11 @@ 1 - Dejuan Schoen DDS + Daija Wehner Jr. 2 - Miss Delilah Hartmann + Rosella Emard DDS diff --git a/docs/snippets/advanced-element-root.xml b/docs/snippets/advanced-element-root.xml index 2eb7719..f794228 100644 --- a/docs/snippets/advanced-element-root.xml +++ b/docs/snippets/advanced-element-root.xml @@ -3,11 +3,11 @@ 1 - Neal Rosenbaum + Baby McDermott DDS 2 - Maryse Terry + Rachael Jerde diff --git a/docs/snippets/receipt-instagram-feed.xml b/docs/snippets/receipt-instagram-feed.xml index 1ed3982..0f872f2 100644 --- a/docs/snippets/receipt-instagram-feed.xml +++ b/docs/snippets/receipt-instagram-feed.xml @@ -6,46 +6,46 @@ 1 - - - https://example.com/products/aut-dolor-et-consequuntur-possimus-eos - https://via.placeholder.com/640x480.png/002222?text=et - https://via.placeholder.com/640x480.png/006677?text=maxime - https://via.placeholder.com/640x480.png/008866?text=recusandae - sapiente + + + https://example.com/products/illo-fugiat-in-voluptatem-sunt + https://via.placeholder.com/640x480.png/00ff55?text=debitis + https://via.placeholder.com/640x480.png/001111?text=sequi + https://via.placeholder.com/640x480.png/00dd22?text=et + cupiditate new in stock - 799 - 799 + 348 + 348 12345 active - - 38 + + 45 adult - + 1000 2000 2 - - - https://example.com/products/illum-occaecati-corrupti-voluptate - https://via.placeholder.com/640x480.png/0055cc?text=sunt - https://via.placeholder.com/640x480.png/0099cc?text=sint - https://via.placeholder.com/640x480.png/00ccff?text=sequi - nostrum + + + https://example.com/products/laboriosam-hic-facilis-earum-voluptatem-sint-sit + https://via.placeholder.com/640x480.png/00bb77?text=autem + https://via.placeholder.com/640x480.png/00aa33?text=est + https://via.placeholder.com/640x480.png/002266?text=et + expedita new in stock - 228 - 228 + 331 + 331 12345 active - - 11 + + 46 adult - + 1000 2000 diff --git a/docs/snippets/receipt-sitemap-feed.xml b/docs/snippets/receipt-sitemap-feed.xml index 7f35014..067b8f4 100644 --- a/docs/snippets/receipt-sitemap-feed.xml +++ b/docs/snippets/receipt-sitemap-feed.xml @@ -2,12 +2,12 @@ - https://example.com/products/aperiam-voluptatem-atque-quia-et + https://example.com/products/sunt-aut-eum-hic-enim-veritatis-libero 2025-09-04T04:08:12+00:00 0.9 - https://example.com/products/eligendi-aperiam-est-fugiat-nobis-consequatur-harum-nihil + https://example.com/products/rerum-est-ipsum-est-et-alias-commodi-neque-quod 2025-09-04T04:08:12+00:00 0.9 diff --git a/docs/snippets/receipt-yandex-feed.xml b/docs/snippets/receipt-yandex-feed.xml index 1bf1309..a7ab487 100644 --- a/docs/snippets/receipt-yandex-feed.xml +++ b/docs/snippets/receipt-yandex-feed.xml @@ -17,36 +17,36 @@ - https://example.com/products/velit-rerum-et-omnis-provident-rerum-inventore-est - GD-N~_Z(N - et et eligendi aliquam - Itaque esse qui tempora non. Illum et quia cum ea quo est. Sit animi et voluptate voluptatem voluptates animi. At illum asperiores vero animi. + https://example.com/products/fugiat-aut-sequi-minima-quia-facere + GD-O)N->X + adipisci quis asperiores rem + Cumque necessitatibus quia minima aspernatur et dolor quae. Dignissimos maxime aut rerum velit perspiciatis. Beatae sit a quisquam atque. true - 957 + 456 RUR - porro - https://via.placeholder.com/640x480.png/00bbcc?text=possimus - https://via.placeholder.com/640x480.png/00ffdd?text=qui - https://via.placeholder.com/640x480.png/005511?text=ullam - GD-N~_Z(N - 6 - male + eos + https://via.placeholder.com/640x480.png/00ff77?text=facere + https://via.placeholder.com/640x480.png/006622?text=illo + https://via.placeholder.com/640x480.png/00cc77?text=magni + GD-O)N->X + 2 + female - https://example.com/products/deserunt-odio-earum-neque-ipsum-alias-magni - GD-'B'"SS - est veritatis officiis quae - Et velit libero dolorem sed est. Repellendus commodi tempore reiciendis quo. Cupiditate reprehenderit dolor molestiae nulla voluptas. Dolorem alias a architecto est quas dolore quas iste. + https://example.com/products/earum-voluptatem-magnam-error-molestiae-odit-consectetur + GD-+5T19 + alias veritatis dignissimos omnis + Sint qui voluptatem quos et. Sint natus beatae ipsum maiores ipsa quas. true - 844 + 553 RUR - doloribus - https://via.placeholder.com/640x480.png/0099ee?text=quo - https://via.placeholder.com/640x480.png/0044ee?text=expedita - https://via.placeholder.com/640x480.png/007777?text=fugiat - GD-'B'"SS - 5 - female + consequatur + https://via.placeholder.com/640x480.png/00bb99?text=voluptas + https://via.placeholder.com/640x480.png/00bb22?text=recusandae + https://via.placeholder.com/640x480.png/0088ee?text=fugit + GD-+5T19 + 9 + male diff --git a/docs/topics/advanced-usage.topic b/docs/topics/advanced-usage.topic index bb79d6f..e05a780 100644 --- a/docs/topics/advanced-usage.topic +++ b/docs/topics/advanced-usage.topic @@ -62,6 +62,7 @@ +

To add information to the beginning of the root element (if present) or without it, diff --git a/docs/topics/create-feeds.topic b/docs/topics/create-feeds.topic index 04d955b..9f8add8 100644 --- a/docs/topics/create-feeds.topic +++ b/docs/topics/create-feeds.topic @@ -101,10 +101,6 @@ - - - -

You can generate feeds in different formats. A feed class can be correctly exported only to the format for which it is intended. @@ -117,7 +113,6 @@

-
diff --git a/docs/topics/supported-formats.topic b/docs/topics/supported-formats.topic index a1c7400..d004e72 100644 --- a/docs/topics/supported-formats.topic +++ b/docs/topics/supported-formats.topic @@ -12,14 +12,20 @@ - - -
  • xml
  • -
  • json
  • -
    + + + Generates feeds in XML format. + + + Generates feeds in JSON format. + + + Generates feeds in JSON Lines format. + + + +

    + By default, the xml format is used. +

    -

    - By default, the xml format is used. -

    -
    diff --git a/src/Converters/ConvertToJsonLines.php b/src/Converters/ConvertToJsonLines.php new file mode 100644 index 0000000..6e028bd --- /dev/null +++ b/src/Converters/ConvertToJsonLines.php @@ -0,0 +1,77 @@ +options &= ~JSON_PRETTY_PRINT; + } + + public function header(Feed $feed): string + { + return ''; + } + + public function footer(Feed $feed): string + { + return ''; + } + + public function root(Feed $feed): string + { + return ''; + } + + public function item(FeedItem $item, bool $isLast): string + { + $data = $this->performItem($item->toArray()); + + return $this->toJson($data); + } + + public function info(array $info, bool $afterRoot): string + { + $data = $this->performItem($info); + + return $this->toJson($data); + } + + protected function performItem(array $data): array + { + foreach ($data as &$value) { + if (is_array($value)) { + $value = $this->performItem($value); + + continue; + } + + $value = $this->transformValue($value); + } + + return $data; + } + + protected function toJson(array $data): string + { + return json_encode($data, $this->options); + } +} diff --git a/src/Enums/FeedFormatEnum.php b/src/Enums/FeedFormatEnum.php index 89fc743..6055d38 100644 --- a/src/Enums/FeedFormatEnum.php +++ b/src/Enums/FeedFormatEnum.php @@ -6,6 +6,7 @@ enum FeedFormatEnum: string { - case Xml = 'xml'; - case Json = 'json'; + case Xml = 'xml'; + case Json = 'json'; + case JsonLines = 'jsonl'; } diff --git a/src/Feeds/Feed.php b/src/Feeds/Feed.php index 1c1c769..db47435 100644 --- a/src/Feeds/Feed.php +++ b/src/Feeds/Feed.php @@ -44,8 +44,8 @@ public function chunkSize(): int public function header(): string { return match ($this->format()) { - FeedFormatEnum::Xml => '', - FeedFormatEnum::Json => '', + FeedFormatEnum::Xml => '', + default => '' }; } diff --git a/src/Services/GeneratorService.php b/src/Services/GeneratorService.php index 55c9c5b..0326ff3 100644 --- a/src/Services/GeneratorService.php +++ b/src/Services/GeneratorService.php @@ -6,6 +6,7 @@ use DragonCode\LaravelFeed\Converters\Converter; use DragonCode\LaravelFeed\Converters\ConvertToJson; +use DragonCode\LaravelFeed\Converters\ConvertToJsonLines; use DragonCode\LaravelFeed\Converters\ConvertToXml; use DragonCode\LaravelFeed\Enums\FeedFormatEnum; use DragonCode\LaravelFeed\Feeds\Feed; @@ -24,6 +25,7 @@ public function __construct( protected FilesystemService $filesystem, protected ConvertToXml $xmlConverter, protected ConvertToJson $jsonConverter, + protected ConvertToJsonLines $jsonLinesConverter, protected FeedQuery $query, ) {} @@ -147,8 +149,9 @@ protected function setLastActivity(Feed $feed): void protected function converter(Feed $feed): Converter { return match ($feed->format()) { - FeedFormatEnum::Xml => $this->xmlConverter, - FeedFormatEnum::Json => $this->jsonConverter, + FeedFormatEnum::Xml => $this->xmlConverter, + FeedFormatEnum::Json => $this->jsonConverter, + FeedFormatEnum::JsonLines => $this->jsonLinesConverter, }; } diff --git a/tests/.pest/snapshots/Feature/Feeds/EmptyTest/export_with_data_set____false__.snap b/tests/.pest/snapshots/Feature/Feeds/Defaults/EmptyTest/export_with_data_set____false__.snap similarity index 100% rename from tests/.pest/snapshots/Feature/Feeds/EmptyTest/export_with_data_set____false__.snap rename to tests/.pest/snapshots/Feature/Feeds/Defaults/EmptyTest/export_with_data_set____false__.snap diff --git a/tests/.pest/snapshots/Feature/Feeds/EmptyTest/export_with_data_set____true__.snap b/tests/.pest/snapshots/Feature/Feeds/Defaults/EmptyTest/export_with_data_set____true__.snap similarity index 100% rename from tests/.pest/snapshots/Feature/Feeds/EmptyTest/export_with_data_set____true__.snap rename to tests/.pest/snapshots/Feature/Feeds/Defaults/EmptyTest/export_with_data_set____true__.snap diff --git a/tests/.pest/snapshots/Feature/Feeds/FullTest/export_with_data_set____false__.snap b/tests/.pest/snapshots/Feature/Feeds/Defaults/FullTest/export_with_data_set____false__.snap similarity index 100% rename from tests/.pest/snapshots/Feature/Feeds/FullTest/export_with_data_set____false__.snap rename to tests/.pest/snapshots/Feature/Feeds/Defaults/FullTest/export_with_data_set____false__.snap diff --git a/tests/.pest/snapshots/Feature/Feeds/FullTest/export_with_data_set____true__.snap b/tests/.pest/snapshots/Feature/Feeds/Defaults/FullTest/export_with_data_set____true__.snap similarity index 100% rename from tests/.pest/snapshots/Feature/Feeds/FullTest/export_with_data_set____true__.snap rename to tests/.pest/snapshots/Feature/Feeds/Defaults/FullTest/export_with_data_set____true__.snap diff --git a/tests/.pest/snapshots/Feature/Feeds/ModelTest/export_with_data_set____false__.snap b/tests/.pest/snapshots/Feature/Feeds/Defaults/ModelTest/export_with_data_set____false__.snap similarity index 100% rename from tests/.pest/snapshots/Feature/Feeds/ModelTest/export_with_data_set____false__.snap rename to tests/.pest/snapshots/Feature/Feeds/Defaults/ModelTest/export_with_data_set____false__.snap diff --git a/tests/.pest/snapshots/Feature/Feeds/ModelTest/export_with_data_set____true__.snap b/tests/.pest/snapshots/Feature/Feeds/Defaults/ModelTest/export_with_data_set____true__.snap similarity index 100% rename from tests/.pest/snapshots/Feature/Feeds/ModelTest/export_with_data_set____true__.snap rename to tests/.pest/snapshots/Feature/Feeds/Defaults/ModelTest/export_with_data_set____true__.snap diff --git a/tests/.pest/snapshots/Feature/Feeds/PartialTest/export_with_data_set____false__.snap b/tests/.pest/snapshots/Feature/Feeds/Defaults/PartialTest/export_with_data_set____false__.snap similarity index 100% rename from tests/.pest/snapshots/Feature/Feeds/PartialTest/export_with_data_set____false__.snap rename to tests/.pest/snapshots/Feature/Feeds/Defaults/PartialTest/export_with_data_set____false__.snap diff --git a/tests/.pest/snapshots/Feature/Feeds/PartialTest/export_with_data_set____true__.snap b/tests/.pest/snapshots/Feature/Feeds/Defaults/PartialTest/export_with_data_set____true__.snap similarity index 100% rename from tests/.pest/snapshots/Feature/Feeds/PartialTest/export_with_data_set____true__.snap rename to tests/.pest/snapshots/Feature/Feeds/Defaults/PartialTest/export_with_data_set____true__.snap diff --git a/tests/.pest/snapshots/Feature/Feeds/JsonTest/export_with_data_set____false__.snap b/tests/.pest/snapshots/Feature/Feeds/Formats/Json/DefaultTest/export_with_data_set____false__.snap similarity index 100% rename from tests/.pest/snapshots/Feature/Feeds/JsonTest/export_with_data_set____false__.snap rename to tests/.pest/snapshots/Feature/Feeds/Formats/Json/DefaultTest/export_with_data_set____false__.snap diff --git a/tests/.pest/snapshots/Feature/Feeds/JsonTest/export_with_data_set____true__.snap b/tests/.pest/snapshots/Feature/Feeds/Formats/Json/DefaultTest/export_with_data_set____true__.snap similarity index 100% rename from tests/.pest/snapshots/Feature/Feeds/JsonTest/export_with_data_set____true__.snap rename to tests/.pest/snapshots/Feature/Feeds/Formats/Json/DefaultTest/export_with_data_set____true__.snap diff --git a/tests/.pest/snapshots/Feature/Feeds/JsonInfoTest/export_with_data_set____false__.snap b/tests/.pest/snapshots/Feature/Feeds/Formats/Json/InfoTest/export_with_data_set____false__.snap similarity index 100% rename from tests/.pest/snapshots/Feature/Feeds/JsonInfoTest/export_with_data_set____false__.snap rename to tests/.pest/snapshots/Feature/Feeds/Formats/Json/InfoTest/export_with_data_set____false__.snap diff --git a/tests/.pest/snapshots/Feature/Feeds/JsonInfoTest/export_with_data_set____true__.snap b/tests/.pest/snapshots/Feature/Feeds/Formats/Json/InfoTest/export_with_data_set____true__.snap similarity index 100% rename from tests/.pest/snapshots/Feature/Feeds/JsonInfoTest/export_with_data_set____true__.snap rename to tests/.pest/snapshots/Feature/Feeds/Formats/Json/InfoTest/export_with_data_set____true__.snap diff --git a/tests/.pest/snapshots/Feature/Feeds/JsonRootInfoTest/export_with_data_set____false__.snap b/tests/.pest/snapshots/Feature/Feeds/Formats/Json/RootInfoTest/export_with_data_set____false__.snap similarity index 100% rename from tests/.pest/snapshots/Feature/Feeds/JsonRootInfoTest/export_with_data_set____false__.snap rename to tests/.pest/snapshots/Feature/Feeds/Formats/Json/RootInfoTest/export_with_data_set____false__.snap diff --git a/tests/.pest/snapshots/Feature/Feeds/JsonRootInfoTest/export_with_data_set____true__.snap b/tests/.pest/snapshots/Feature/Feeds/Formats/Json/RootInfoTest/export_with_data_set____true__.snap similarity index 100% rename from tests/.pest/snapshots/Feature/Feeds/JsonRootInfoTest/export_with_data_set____true__.snap rename to tests/.pest/snapshots/Feature/Feeds/Formats/Json/RootInfoTest/export_with_data_set____true__.snap diff --git a/tests/.pest/snapshots/Feature/Feeds/JsonRootTest/export_with_data_set____false__.snap b/tests/.pest/snapshots/Feature/Feeds/Formats/Json/RootTest/export_with_data_set____false__.snap similarity index 100% rename from tests/.pest/snapshots/Feature/Feeds/JsonRootTest/export_with_data_set____false__.snap rename to tests/.pest/snapshots/Feature/Feeds/Formats/Json/RootTest/export_with_data_set____false__.snap diff --git a/tests/.pest/snapshots/Feature/Feeds/JsonRootTest/export_with_data_set____true__.snap b/tests/.pest/snapshots/Feature/Feeds/Formats/Json/RootTest/export_with_data_set____true__.snap similarity index 100% rename from tests/.pest/snapshots/Feature/Feeds/JsonRootTest/export_with_data_set____true__.snap rename to tests/.pest/snapshots/Feature/Feeds/Formats/Json/RootTest/export_with_data_set____true__.snap diff --git a/tests/.pest/snapshots/Feature/Feeds/Formats/JsonLines/DefaultTest/export_with_data_set____false__.snap b/tests/.pest/snapshots/Feature/Feeds/Formats/JsonLines/DefaultTest/export_with_data_set____false__.snap new file mode 100644 index 0000000..5f50397 --- /dev/null +++ b/tests/.pest/snapshots/Feature/Feeds/Formats/JsonLines/DefaultTest/export_with_data_set____false__.snap @@ -0,0 +1,3 @@ +{"id":1,"title":"Some 1","content":"Some content 1","created_at":"2025-09-04T04:08:12.000000Z","updated_at":"2025-09-04T04:08:12.000000Z"} +{"id":2,"title":"Some 2","content":"Some content 2","created_at":"2025-09-04T04:08:12.000000Z","updated_at":"2025-09-04T04:08:12.000000Z"} +{"id":3,"title":"Some 3","content":"Some content 3","created_at":"2025-09-04T04:08:12.000000Z","updated_at":"2025-09-04T04:08:12.000000Z"} \ No newline at end of file diff --git a/tests/.pest/snapshots/Feature/Feeds/Formats/JsonLines/DefaultTest/export_with_data_set____true__.snap b/tests/.pest/snapshots/Feature/Feeds/Formats/JsonLines/DefaultTest/export_with_data_set____true__.snap new file mode 100644 index 0000000..5f50397 --- /dev/null +++ b/tests/.pest/snapshots/Feature/Feeds/Formats/JsonLines/DefaultTest/export_with_data_set____true__.snap @@ -0,0 +1,3 @@ +{"id":1,"title":"Some 1","content":"Some content 1","created_at":"2025-09-04T04:08:12.000000Z","updated_at":"2025-09-04T04:08:12.000000Z"} +{"id":2,"title":"Some 2","content":"Some content 2","created_at":"2025-09-04T04:08:12.000000Z","updated_at":"2025-09-04T04:08:12.000000Z"} +{"id":3,"title":"Some 3","content":"Some content 3","created_at":"2025-09-04T04:08:12.000000Z","updated_at":"2025-09-04T04:08:12.000000Z"} \ No newline at end of file diff --git a/tests/.pest/snapshots/Feature/Feeds/Formats/JsonLines/InfoTest/export_with_data_set____false__.snap b/tests/.pest/snapshots/Feature/Feeds/Formats/JsonLines/InfoTest/export_with_data_set____false__.snap new file mode 100644 index 0000000..dc646bf --- /dev/null +++ b/tests/.pest/snapshots/Feature/Feeds/Formats/JsonLines/InfoTest/export_with_data_set____false__.snap @@ -0,0 +1,4 @@ +{"name":"Laravel","company":"Laravel","platform":"Laravel","url":"https://example.com","email":"test@example.com","currencies":{"@currency":[{"@attributes":{"id":"RUR","rate":"1"}}]},"categories":{"@category":[{"@attributes":{"id":41},"@value":"Домашние майки"},{"@attributes":{"id":539},"@value":"Велосипедки"},{"@attributes":{"id":44},"@value":"Ремни"}]}} +{"id":1,"title":"Some 1","content":"Some content 1","created_at":"2025-09-04T04:08:12.000000Z","updated_at":"2025-09-04T04:08:12.000000Z"} +{"id":2,"title":"Some 2","content":"Some content 2","created_at":"2025-09-04T04:08:12.000000Z","updated_at":"2025-09-04T04:08:12.000000Z"} +{"id":3,"title":"Some 3","content":"Some content 3","created_at":"2025-09-04T04:08:12.000000Z","updated_at":"2025-09-04T04:08:12.000000Z"} \ No newline at end of file diff --git a/tests/.pest/snapshots/Feature/Feeds/Formats/JsonLines/InfoTest/export_with_data_set____true__.snap b/tests/.pest/snapshots/Feature/Feeds/Formats/JsonLines/InfoTest/export_with_data_set____true__.snap new file mode 100644 index 0000000..dc646bf --- /dev/null +++ b/tests/.pest/snapshots/Feature/Feeds/Formats/JsonLines/InfoTest/export_with_data_set____true__.snap @@ -0,0 +1,4 @@ +{"name":"Laravel","company":"Laravel","platform":"Laravel","url":"https://example.com","email":"test@example.com","currencies":{"@currency":[{"@attributes":{"id":"RUR","rate":"1"}}]},"categories":{"@category":[{"@attributes":{"id":41},"@value":"Домашние майки"},{"@attributes":{"id":539},"@value":"Велосипедки"},{"@attributes":{"id":44},"@value":"Ремни"}]}} +{"id":1,"title":"Some 1","content":"Some content 1","created_at":"2025-09-04T04:08:12.000000Z","updated_at":"2025-09-04T04:08:12.000000Z"} +{"id":2,"title":"Some 2","content":"Some content 2","created_at":"2025-09-04T04:08:12.000000Z","updated_at":"2025-09-04T04:08:12.000000Z"} +{"id":3,"title":"Some 3","content":"Some content 3","created_at":"2025-09-04T04:08:12.000000Z","updated_at":"2025-09-04T04:08:12.000000Z"} \ No newline at end of file diff --git a/tests/.pest/snapshots/Feature/Feeds/Formats/JsonLines/RootInfoTest/export_with_data_set____false__.snap b/tests/.pest/snapshots/Feature/Feeds/Formats/JsonLines/RootInfoTest/export_with_data_set____false__.snap new file mode 100644 index 0000000..dc646bf --- /dev/null +++ b/tests/.pest/snapshots/Feature/Feeds/Formats/JsonLines/RootInfoTest/export_with_data_set____false__.snap @@ -0,0 +1,4 @@ +{"name":"Laravel","company":"Laravel","platform":"Laravel","url":"https://example.com","email":"test@example.com","currencies":{"@currency":[{"@attributes":{"id":"RUR","rate":"1"}}]},"categories":{"@category":[{"@attributes":{"id":41},"@value":"Домашние майки"},{"@attributes":{"id":539},"@value":"Велосипедки"},{"@attributes":{"id":44},"@value":"Ремни"}]}} +{"id":1,"title":"Some 1","content":"Some content 1","created_at":"2025-09-04T04:08:12.000000Z","updated_at":"2025-09-04T04:08:12.000000Z"} +{"id":2,"title":"Some 2","content":"Some content 2","created_at":"2025-09-04T04:08:12.000000Z","updated_at":"2025-09-04T04:08:12.000000Z"} +{"id":3,"title":"Some 3","content":"Some content 3","created_at":"2025-09-04T04:08:12.000000Z","updated_at":"2025-09-04T04:08:12.000000Z"} \ No newline at end of file diff --git a/tests/.pest/snapshots/Feature/Feeds/Formats/JsonLines/RootInfoTest/export_with_data_set____true__.snap b/tests/.pest/snapshots/Feature/Feeds/Formats/JsonLines/RootInfoTest/export_with_data_set____true__.snap new file mode 100644 index 0000000..dc646bf --- /dev/null +++ b/tests/.pest/snapshots/Feature/Feeds/Formats/JsonLines/RootInfoTest/export_with_data_set____true__.snap @@ -0,0 +1,4 @@ +{"name":"Laravel","company":"Laravel","platform":"Laravel","url":"https://example.com","email":"test@example.com","currencies":{"@currency":[{"@attributes":{"id":"RUR","rate":"1"}}]},"categories":{"@category":[{"@attributes":{"id":41},"@value":"Домашние майки"},{"@attributes":{"id":539},"@value":"Велосипедки"},{"@attributes":{"id":44},"@value":"Ремни"}]}} +{"id":1,"title":"Some 1","content":"Some content 1","created_at":"2025-09-04T04:08:12.000000Z","updated_at":"2025-09-04T04:08:12.000000Z"} +{"id":2,"title":"Some 2","content":"Some content 2","created_at":"2025-09-04T04:08:12.000000Z","updated_at":"2025-09-04T04:08:12.000000Z"} +{"id":3,"title":"Some 3","content":"Some content 3","created_at":"2025-09-04T04:08:12.000000Z","updated_at":"2025-09-04T04:08:12.000000Z"} \ No newline at end of file diff --git a/tests/.pest/snapshots/Feature/Feeds/Formats/JsonLines/RootTest/export_with_data_set____false__.snap b/tests/.pest/snapshots/Feature/Feeds/Formats/JsonLines/RootTest/export_with_data_set____false__.snap new file mode 100644 index 0000000..5f50397 --- /dev/null +++ b/tests/.pest/snapshots/Feature/Feeds/Formats/JsonLines/RootTest/export_with_data_set____false__.snap @@ -0,0 +1,3 @@ +{"id":1,"title":"Some 1","content":"Some content 1","created_at":"2025-09-04T04:08:12.000000Z","updated_at":"2025-09-04T04:08:12.000000Z"} +{"id":2,"title":"Some 2","content":"Some content 2","created_at":"2025-09-04T04:08:12.000000Z","updated_at":"2025-09-04T04:08:12.000000Z"} +{"id":3,"title":"Some 3","content":"Some content 3","created_at":"2025-09-04T04:08:12.000000Z","updated_at":"2025-09-04T04:08:12.000000Z"} \ No newline at end of file diff --git a/tests/.pest/snapshots/Feature/Feeds/Formats/JsonLines/RootTest/export_with_data_set____true__.snap b/tests/.pest/snapshots/Feature/Feeds/Formats/JsonLines/RootTest/export_with_data_set____true__.snap new file mode 100644 index 0000000..5f50397 --- /dev/null +++ b/tests/.pest/snapshots/Feature/Feeds/Formats/JsonLines/RootTest/export_with_data_set____true__.snap @@ -0,0 +1,3 @@ +{"id":1,"title":"Some 1","content":"Some content 1","created_at":"2025-09-04T04:08:12.000000Z","updated_at":"2025-09-04T04:08:12.000000Z"} +{"id":2,"title":"Some 2","content":"Some content 2","created_at":"2025-09-04T04:08:12.000000Z","updated_at":"2025-09-04T04:08:12.000000Z"} +{"id":3,"title":"Some 3","content":"Some content 3","created_at":"2025-09-04T04:08:12.000000Z","updated_at":"2025-09-04T04:08:12.000000Z"} \ No newline at end of file diff --git a/tests/.pest/snapshots/Feature/Feeds/SitemapTest/export.snap b/tests/.pest/snapshots/Feature/Feeds/Receipts/SitemapTest/export.snap similarity index 100% rename from tests/.pest/snapshots/Feature/Feeds/SitemapTest/export.snap rename to tests/.pest/snapshots/Feature/Feeds/Receipts/SitemapTest/export.snap diff --git a/tests/.pest/snapshots/Feature/Feeds/YandexTest/export.snap b/tests/.pest/snapshots/Feature/Feeds/Receipts/YandexTest/export.snap similarity index 100% rename from tests/.pest/snapshots/Feature/Feeds/YandexTest/export.snap rename to tests/.pest/snapshots/Feature/Feeds/Receipts/YandexTest/export.snap diff --git a/tests/Expectations.php b/tests/Expectations.php index 2f3a677..d54dd5b 100644 --- a/tests/Expectations.php +++ b/tests/Expectations.php @@ -55,3 +55,11 @@ return $next(); }); + +expect()->extend('toBeJsonLines', function () { + foreach (explode("\n", $this->value) as $line) { + expect($line)->toBeJson(); + } + + return $this; +}); diff --git a/tests/Feature/Feeds/EmptyTest.php b/tests/Feature/Feeds/Defaults/EmptyTest.php similarity index 100% rename from tests/Feature/Feeds/EmptyTest.php rename to tests/Feature/Feeds/Defaults/EmptyTest.php diff --git a/tests/Feature/Feeds/FullTest.php b/tests/Feature/Feeds/Defaults/FullTest.php similarity index 100% rename from tests/Feature/Feeds/FullTest.php rename to tests/Feature/Feeds/Defaults/FullTest.php diff --git a/tests/Feature/Feeds/ModelTest.php b/tests/Feature/Feeds/Defaults/ModelTest.php similarity index 100% rename from tests/Feature/Feeds/ModelTest.php rename to tests/Feature/Feeds/Defaults/ModelTest.php diff --git a/tests/Feature/Feeds/PartialTest.php b/tests/Feature/Feeds/Defaults/PartialTest.php similarity index 100% rename from tests/Feature/Feeds/PartialTest.php rename to tests/Feature/Feeds/Defaults/PartialTest.php diff --git a/tests/Feature/Feeds/JsonTest.php b/tests/Feature/Feeds/Formats/Json/DefaultTest.php similarity index 68% rename from tests/Feature/Feeds/JsonTest.php rename to tests/Feature/Feeds/Formats/Json/DefaultTest.php index f12326a..24e1c1e 100644 --- a/tests/Feature/Feeds/JsonTest.php +++ b/tests/Feature/Feeds/Formats/Json/DefaultTest.php @@ -2,6 +2,7 @@ declare(strict_types=1); +use DragonCode\LaravelFeed\Enums\FeedFormatEnum; use Workbench\App\Data\NewsFakeData; use Workbench\App\Feeds\JsonFeed; @@ -10,5 +11,5 @@ createNews(...NewsFakeData::toArray()); - expectFeedSnapshot(JsonFeed::class, true); + expectFeedSnapshot(JsonFeed::class, FeedFormatEnum::Json); })->with('boolean'); diff --git a/tests/Feature/Feeds/JsonInfoTest.php b/tests/Feature/Feeds/Formats/Json/InfoTest.php similarity index 67% rename from tests/Feature/Feeds/JsonInfoTest.php rename to tests/Feature/Feeds/Formats/Json/InfoTest.php index 326af29..4f2e572 100644 --- a/tests/Feature/Feeds/JsonInfoTest.php +++ b/tests/Feature/Feeds/Formats/Json/InfoTest.php @@ -2,6 +2,7 @@ declare(strict_types=1); +use DragonCode\LaravelFeed\Enums\FeedFormatEnum; use Workbench\App\Data\NewsFakeData; use Workbench\App\Feeds\JsonInfoFeed; @@ -10,5 +11,5 @@ createNews(...NewsFakeData::toArray()); - expectFeedSnapshot(JsonInfoFeed::class, true); + expectFeedSnapshot(JsonInfoFeed::class, FeedFormatEnum::Json); })->with('boolean'); diff --git a/tests/Feature/Feeds/JsonRootInfoTest.php b/tests/Feature/Feeds/Formats/Json/RootInfoTest.php similarity index 67% rename from tests/Feature/Feeds/JsonRootInfoTest.php rename to tests/Feature/Feeds/Formats/Json/RootInfoTest.php index beae030..aefe67a 100644 --- a/tests/Feature/Feeds/JsonRootInfoTest.php +++ b/tests/Feature/Feeds/Formats/Json/RootInfoTest.php @@ -2,6 +2,7 @@ declare(strict_types=1); +use DragonCode\LaravelFeed\Enums\FeedFormatEnum; use Workbench\App\Data\NewsFakeData; use Workbench\App\Feeds\JsonRootInfoFeed; @@ -10,5 +11,5 @@ createNews(...NewsFakeData::toArray()); - expectFeedSnapshot(JsonRootInfoFeed::class, true); + expectFeedSnapshot(JsonRootInfoFeed::class, FeedFormatEnum::Json); })->with('boolean'); diff --git a/tests/Feature/Feeds/JsonRootTest.php b/tests/Feature/Feeds/Formats/Json/RootTest.php similarity index 67% rename from tests/Feature/Feeds/JsonRootTest.php rename to tests/Feature/Feeds/Formats/Json/RootTest.php index bef3130..476b912 100644 --- a/tests/Feature/Feeds/JsonRootTest.php +++ b/tests/Feature/Feeds/Formats/Json/RootTest.php @@ -2,6 +2,7 @@ declare(strict_types=1); +use DragonCode\LaravelFeed\Enums\FeedFormatEnum; use Workbench\App\Data\NewsFakeData; use Workbench\App\Feeds\JsonRootFeed; @@ -10,5 +11,5 @@ createNews(...NewsFakeData::toArray()); - expectFeedSnapshot(JsonRootFeed::class, true); + expectFeedSnapshot(JsonRootFeed::class, FeedFormatEnum::Json); })->with('boolean'); diff --git a/tests/Feature/Feeds/Formats/JsonLines/DefaultTest.php b/tests/Feature/Feeds/Formats/JsonLines/DefaultTest.php new file mode 100644 index 0000000..608535f --- /dev/null +++ b/tests/Feature/Feeds/Formats/JsonLines/DefaultTest.php @@ -0,0 +1,15 @@ +with('boolean'); diff --git a/tests/Feature/Feeds/Formats/JsonLines/InfoTest.php b/tests/Feature/Feeds/Formats/JsonLines/InfoTest.php new file mode 100644 index 0000000..db76746 --- /dev/null +++ b/tests/Feature/Feeds/Formats/JsonLines/InfoTest.php @@ -0,0 +1,15 @@ +with('boolean'); diff --git a/tests/Feature/Feeds/Formats/JsonLines/RootInfoTest.php b/tests/Feature/Feeds/Formats/JsonLines/RootInfoTest.php new file mode 100644 index 0000000..0263e7e --- /dev/null +++ b/tests/Feature/Feeds/Formats/JsonLines/RootInfoTest.php @@ -0,0 +1,15 @@ +with('boolean'); diff --git a/tests/Feature/Feeds/Formats/JsonLines/RootTest.php b/tests/Feature/Feeds/Formats/JsonLines/RootTest.php new file mode 100644 index 0000000..e5d083a --- /dev/null +++ b/tests/Feature/Feeds/Formats/JsonLines/RootTest.php @@ -0,0 +1,15 @@ +with('boolean'); diff --git a/tests/Feature/Feeds/SitemapTest.php b/tests/Feature/Feeds/Receipts/SitemapTest.php similarity index 100% rename from tests/Feature/Feeds/SitemapTest.php rename to tests/Feature/Feeds/Receipts/SitemapTest.php diff --git a/tests/Feature/Feeds/YandexTest.php b/tests/Feature/Feeds/Receipts/YandexTest.php similarity index 100% rename from tests/Feature/Feeds/YandexTest.php rename to tests/Feature/Feeds/Receipts/YandexTest.php diff --git a/tests/Helpers/expects.php b/tests/Helpers/expects.php index 438e207..0d805b0 100644 --- a/tests/Helpers/expects.php +++ b/tests/Helpers/expects.php @@ -3,10 +3,11 @@ declare(strict_types=1); use DragonCode\LaravelFeed\Commands\FeedGenerateCommand; +use DragonCode\LaravelFeed\Enums\FeedFormatEnum; use function Pest\Laravel\artisan; -function expectFeedSnapshot(string $class, bool $isJson = false): void +function expectFeedSnapshot(string $class, FeedFormatEnum $format = FeedFormatEnum::Xml): void { $feed = findFeed($class); @@ -20,9 +21,11 @@ function expectFeedSnapshot(string $class, bool $isJson = false): void $content = file_get_contents($instance->path()); - if ($isJson) { - expect($content)->toBeJson(); - } + match ($format) { + FeedFormatEnum::Json => expect($content)->toBeJson(), + FeedFormatEnum::JsonLines => expect($content)->toBeJsonLines(), + default => null + }; expect($content)->toMatchSnapshot(); } diff --git a/workbench/app/Feeds/JsonLinesFeed.php b/workbench/app/Feeds/JsonLinesFeed.php new file mode 100644 index 0000000..43c0fce --- /dev/null +++ b/workbench/app/Feeds/JsonLinesFeed.php @@ -0,0 +1,28 @@ +