craftcms / cms

Build bespoke content experiences with Craft.
https://craftcms.com
Other
3.28k stars 635 forks source link

[4.4.17]: An error occurs when trying to export subfolders of assets #13570

Closed rhlt closed 1 year ago

rhlt commented 1 year ago

What happened?

Description

Craft CMS provides an "Export" button on all element pages in the CP; including Assets. This allows exporting the field data of all elements in the page. If one or more elements are selected, only those elements are exported. However, this does not work when a subfolder is selected. (Subfolders only exist for Assets.)

Steps to reproduce

  1. Open the "Assets" page in the CP;
  2. Select at least one subfolder by clicking the checkbox to the left of the folder name;
  3. Click the "Export" button at the bottom right;
  4. Click the red "Export" button in the pop up that appears (there is no difference in behavior for different Export Types or Limits);

Expected behavior

A file is downloaded that contains all data for all selected elements (in this case, all assets in the selected subfolder).

Actual behavior

A small pop up appears with the message "An internal server error occured."

Inspecting the network request sent by the CP reveals the following error:

An Error occurred while handling another error:
TypeError: array_keys(): Argument #1 ($array) must be of type array, string given in /var/www/html/vendor/craftcms/cms/src/web/CsvResponseFormatter.php:92
Stack trace:
#0 /var/www/html/vendor/craftcms/cms/src/web/CsvResponseFormatter.php(92): array_keys('Exception')
#1 /var/www/html/vendor/yiisoft/yii2/web/Response.php(1098): craft\web\CsvResponseFormatter->format(Object(craft\web\Response))
#2 /var/www/html/vendor/craftcms/cms/src/web/Response.php(286): yii\web\Response->prepare()
#3 /var/www/html/vendor/yiisoft/yii2/web/Response.php(339): craft\web\Response->prepare()
#4 /var/www/html/vendor/yiisoft/yii2/web/ErrorHandler.php(136): yii\web\Response->send()
#5 /var/www/html/vendor/craftcms/cms/src/web/ErrorHandler.php(192): yii\web\ErrorHandler->renderException(Object(yii\base\InvalidArgumentException))
#6 /var/www/html/vendor/yiisoft/yii2/base/ErrorHandler.php(152): craft\web\ErrorHandler->renderException(Object(yii\base\InvalidArgumentException))
#7 /var/www/html/vendor/craftcms/cms/src/web/ErrorHandler.php(66): yii\base\ErrorHandler->handleException(Object(yii\base\InvalidArgumentException))
#8 [internal function]: craft\web\ErrorHandler->handleException(Object(yii\base\InvalidArgumentException))
#9 {main}
Previous exception:
yii\base\InvalidArgumentException: Invalid numeric value:  in /var/www/html/vendor/craftcms/cms/src/helpers/Db.php:604
Stack trace:
#0 /var/www/html/vendor/craftcms/cms/src/helpers/Db.php(855): craft\helpers\Db::parseParam('elements.id', Array, '=', false, 'integer')
#1 /var/www/html/vendor/craftcms/cms/src/elements/db/ElementQuery.php(1408): craft\helpers\Db::parseNumericParam('elements.id', Array)
#2 /var/www/html/vendor/yiisoft/yii2/db/QueryBuilder.php(227): craft\elements\db\ElementQuery->prepare(Object(craft\db\mysql\QueryBuilder))
#3 /var/www/html/vendor/yiisoft/yii2/db/Query.php(157): yii\db\QueryBuilder->build(Object(craft\elements\db\AssetQuery))
#4 /var/www/html/vendor/yiisoft/yii2/db/Query.php(249): yii\db\Query->createCommand(Object(craft\db\Connection))
#5 /var/www/html/vendor/craftcms/cms/src/db/Query.php(247): yii\db\Query->all(NULL)
#6 /var/www/html/vendor/craftcms/cms/src/elements/db/ElementQuery.php(1572): craft\db\Query->all(NULL)
#7 /var/www/html/vendor/craftcms/cms/src/elements/exporters/Raw.php(35): craft\elements\db\ElementQuery->all()
#8 /var/www/html/vendor/craftcms/cms/src/controllers/ElementIndexesController.php(342): craft\elements\exporters\Raw->export(Object(craft\elements\db\AssetQuery))
#9 [internal function]: craft\controllers\ElementIndexesController->actionExport()
#10 /var/www/html/vendor/yiisoft/yii2/base/InlineAction.php(57): call_user_func_array(Array, Array)
#11 /var/www/html/vendor/yiisoft/yii2/base/Controller.php(178): yii\base\InlineAction->runWithParams(Array)
#12 /var/www/html/vendor/yiisoft/yii2/base/Module.php(552): yii\base\Controller->runAction('export', Array)
#13 /var/www/html/vendor/craftcms/cms/src/web/Application.php(304): yii\base\Module->runAction('element-indexes...', Array)
#14 /var/www/html/vendor/craftcms/cms/src/web/Application.php(607): craft\web\Application->runAction('element-indexes...', Array)
#15 /var/www/html/vendor/craftcms/cms/src/web/Application.php(283): craft\web\Application->_processActionRequest(Object(craft\web\Request))
#16 /var/www/html/vendor/yiisoft/yii2/base/Application.php(384): craft\web\Application->handleRequest(Object(craft\web\Request))
#17 /var/www/html/public_html/index.php(36): yii\base\Application->run()
#18 {main}

This is the result of a request sent to the element-indexes/export controller action.

I also found that the payload contains a criteria parameter with an id key. It seems the value of id is expected to be an array of element IDs for the elements to be exported. However, when a subfolder is selected, an empty string ("") is added to the id array instead. This seems to be what causes the error.

Craft CMS version

4.4.17

PHP version

8.1.8

Operating system and version

No response

Database type and version

No response

Image driver and version

No response

Installed plugins and versions

No response

i-just commented 1 year ago

Hi, thanks for reporting! I raised a PR to adjust this.

brandonkelly commented 1 year ago

Just fixed this for the next releases. Going forward, any folders that are selected will be ignored by the export.

Expected behavior

A file is downloaded that contains all data for all selected elements (in this case, all assets in the selected subfolder).

We can discuss that as a possibility down the road, but the current export functionality is not designed to scale beyond 100 elements exported at a time. This behavior would lead to major issues if you tried to export a folder with thousands of nested assets.

brandonkelly commented 1 year ago

Craft 3.9.0 and 4.5.0 are out with that fix.