diff --git a/CHANGELOG.md b/CHANGELOG.md index 710f401ac..ba49840b0 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ In order to read more about upgrading and BC breaks have a look at the [UPGRADE ## 4.9.0 ++ [#744](https://github.com/luyadev/luya-module-admin/pull/744) The internal CRUD export system no longer caches data in the @runtime folder, but uses the cache component instead. This could potentially cause problems when exporting large CRUD tables, but it fixes the problem when LUYA Admin is used in a cloud-scaled architecture. + [#743](https://github.com/luyadev/luya-module-admin/pull/743) Add option to ignore the pool context inside CRUD relation loader for `CheckboxRelation`, `SelectModel` and `SelectRelationActiveQuery` plugins. ## 4.8.0 (5. January 2023) diff --git a/UPGRADE.md b/UPGRADE.md index fe688ac1c..7f15dfd72 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -2,6 +2,10 @@ This document will help you upgrading from a LUYA admin module version into another. For more detailed informations about the breaking changes **click the issue detail link**, there you can examples of how to change your code. +## from 4.8 to 4.9 + ++ [#744](https://github.com/luyadev/luya-module-admin/pull/744) Make sure you have a valid cache component registered to use the LUYA admin CRUD export system. If large tables are exported, the caching system must support such data sizes, the `file` or `redis` cache component supports large amounts of data. + ## from 4.4 to 4.5 + [#726](https://github.com/luyadev/luya-module-admin/pull/726) With the new [replaced jwt auth](https://github.com/bizley/yii2-jwt) library (which is required in order to support php 8.1) we use [lcobucci/jwt v4](https://github.com/lcobucci/jwt/releases/tag/4.0.0) which massivly changed the API. Therfore the main change for LUYA users is that `Lcobucci\JWT\Token` has been replaced with `Lcobucci\JWT\Token\Plain`. The signature of `luya\admin\base\JwtIdentityInterface` has changed from: `loginByJwtToken(Lcobucci\JWT\Token $token)` to `loginByJwtToken(Lcobucci\JWT\Token\Plain $token)` and in order to to claim the user id in the login process you have to use `$userId = $token->claims()->get('uid');` instead of `$userId = $token->getClaim('uid');`. Take a look at the [JWT Guide Diff](https://github.com/luyadev/luya/commit/74118e94ac4130226b925f6d2312a028287418c0) diff --git a/src/ngrest/base/ActiveWindow.php b/src/ngrest/base/ActiveWindow.php index b165f08a0..07272d6bf 100644 --- a/src/ngrest/base/ActiveWindow.php +++ b/src/ngrest/base/ActiveWindow.php @@ -6,7 +6,6 @@ use luya\admin\ngrest\NgRestButtonConditionInterface; use luya\admin\ngrest\NgRestPermissionLevelInterface; use luya\Exception; -use luya\helpers\FileHelper; use luya\helpers\StringHelper; use luya\helpers\Url; use Yii; @@ -142,28 +141,25 @@ public function createDownloadableFileUrl($fileName, $mimeType, $content) { $key = uniqid(microtime().Inflector::slug($fileName), true); - $store = FileHelper::writeFile('@runtime/'.$key.'.tmp', $content); + if (!Yii::$app->cache->set(['download', $key], $content, 60*60)) { + return false; + } $menu = Yii::$app->adminmenu->getApiDetail($this->model->ngRestApiEndpoint()); + $route = str_replace("/index", "/export-download", $menu['route']); - $route = $menu['route']; - $route = str_replace("/index", "/export-download", $route); + Yii::$app->session->set('tempNgRestFileName', $fileName); + Yii::$app->session->set('tempNgRestFileKey', $key); + Yii::$app->session->set('tempNgRestFileMime', $mimeType); - if ($store) { - Yii::$app->session->set('tempNgRestFileName', $fileName); - Yii::$app->session->set('tempNgRestFileKey', $key); - Yii::$app->session->set('tempNgRestFileMime', $mimeType); - $url = Url::toRoute(['/'.$route], true); - $param = http_build_query(['key' => base64_encode($key), 'time' => time()]); + $url = Url::toRoute(['/'.$route], true); + $param = http_build_query(['key' => base64_encode($key), 'time' => time()]); - if (StringHelper::contains('?', $url)) { - return $url . "&" . $param; - } else { - return $url . "?" . $param; - } + if (StringHelper::contains('?', $url)) { + return $url . "&" . $param; + } else { + return $url . "?" . $param; } - - return false; } /** diff --git a/src/ngrest/base/Api.php b/src/ngrest/base/Api.php index 91eb16bbb..5ba11b84d 100644 --- a/src/ngrest/base/Api.php +++ b/src/ngrest/base/Api.php @@ -14,7 +14,6 @@ use luya\admin\traits\TaggableTrait; use luya\helpers\ArrayHelper; use luya\helpers\ExportHelper; -use luya\helpers\FileHelper; use luya\helpers\Json; use luya\helpers\ObjectHelper; use luya\helpers\StringHelper; @@ -839,32 +838,28 @@ public function actionExport() $key = uniqid('ngrestexport', true); - $store = FileHelper::writeFile('@runtime/'.$key.'.tmp', $tempData); + if (!Yii::$app->cache->set(['download', $key], $tempData, 60*60)) { + throw new ErrorException("Unable to write the temporary file. Make sure the runtime folder is writeable."); + } $menu = Yii::$app->adminmenu->getApiDetail($this->model->ngRestApiEndpoint()); + $route = str_replace("/index", "/export-download", $menu['route']); - $route = $menu['route']; - $route = str_replace("/index", "/export-download", $route); - - if ($store) { - Yii::$app->session->set('tempNgRestFileName', Inflector::slug($this->model->tableName()) . '-export-'.date("Y-m-d-H-i").'.' . $extension); - Yii::$app->session->set('tempNgRestFileMime', $mime); - Yii::$app->session->set('tempNgRestFileKey', $key); + Yii::$app->session->set('tempNgRestFileName', Inflector::slug($this->model->tableName()) . '-export-'.date("Y-m-d-H-i").'.' . $extension); + Yii::$app->session->set('tempNgRestFileMime', $mime); + Yii::$app->session->set('tempNgRestFileKey', $key); - $url = Url::toRoute(['/'.$route], true); - $param = http_build_query(['key' => base64_encode($key), 'time' => time()]); + $url = Url::toRoute(['/'.$route], true); + $param = http_build_query(['key' => base64_encode($key), 'time' => time()]); - if (StringHelper::contains('?', $url)) { - $route = $url . "&" . $param; - } else { - $route = $url . "?" . $param; - } - return [ - 'url' => $route, - ]; + if (StringHelper::contains('?', $url)) { + $route = $url . "&" . $param; + } else { + $route = $url . "?" . $param; } - - throw new ErrorException("Unable to write the temporary file. Make sure the runtime folder is writeable."); + return [ + 'url' => $route, + ]; } /** diff --git a/src/ngrest/base/Controller.php b/src/ngrest/base/Controller.php index 5a85e1318..71b188c91 100644 --- a/src/ngrest/base/Controller.php +++ b/src/ngrest/base/Controller.php @@ -7,10 +7,10 @@ use luya\admin\Module; use luya\admin\ngrest\NgRest; use luya\admin\ngrest\render\RenderCrud; -use luya\helpers\FileHelper; use Yii; use yii\base\InvalidConfigException; use yii\web\ForbiddenHttpException; +use yii\web\NotFoundHttpException; /** * Base Controller for all NgRest Controllers. @@ -241,12 +241,17 @@ public function actionExportDownload($key) throw new ForbiddenHttpException('Invalid download key.'); } - $content = FileHelper::getFileContent('@runtime/'.$sessionkey.'.tmp'); + $content = Yii::$app->cache->get(['download', $sessionkey]); + + if (!$content) { + throw new NotFoundHttpException(); + } Yii::$app->session->remove('tempNgRestFileKey'); Yii::$app->session->remove('tempNgRestFileName'); Yii::$app->session->remove('tempNgRestFileMime'); - @unlink(Yii::getAlias('@runtime/'.$sessionkey.'.tmp')); + + Yii::$app->cache->delete(['download', $sessionkey]); return Yii::$app->response->sendContentAsFile($content, $fileName, ['mimeType' => $mimeType]); }