codeigniter4 / CodeIgniter4

Open Source PHP Framework (originally from EllisLab)
https://codeigniter.com/
MIT License
5.38k stars 1.9k forks source link

Bug: [ViewCells] The DateTimeZone object has not been correctly initialized #7647

Closed neznaika0 closed 1 year ago

neznaika0 commented 1 year ago

PHP Version

8.2

CodeIgniter4 Version

4.3.6

CodeIgniter4 Installation Method

Composer (using codeigniter4/appstarter)

Which operating systems have you tested for this bug?

Linux

Which server did you use?

apache

Database

No response

What happened?

in view_cell() I have an Entity object with Datetime fields. When calling in the template, this error appears. I found the story on php.net https://bugs.php.net/bug.php?id=75965&edit=3

CRITICAL - 2023-07-03 16:18:40 --> The DateTimeZone object has not been correctly initialized by its constructor
in SYSTEMPATH/View/Cell.php on line 76.
 1 [internal function]: DateTimeZone->__serialize()
 2 SYSTEMPATH/View/Cell.php(76): serialize()
 3 SYSTEMPATH/Common.php(1151): CodeIgniter\View\Cell->render()
 4 APPPATH/Views/metronic/project/show.php(14): view_cell()
...

Error this

        // Is the output cached?
        $cacheName = ! empty($cacheName)
            ? $cacheName
            : str_replace(['\\', '/'], '', $class) . $method . md5(serialize($params));

Steps to Reproduce

Create view_cell() template with object contain Datetime fields

// in params contains Datetime field 
<?= view_cell('App\Libraries\ViewCellManager::showCardWithTabs', [
        'project' => $project,
        'categories' => $project->getCategories(),
        'firstCategory' => $firstCategory,
        'currentTab' => $currentTab
    ]) ?>

Expected Output

Object Datetime correct serialized. Or replace logic hash in Cell.php There was no such thing before - everything worked properly. Before PHP 8.2.5

Anything else?

No response

kenjis commented 1 year ago

I cannot run the following code:

ErrorException Undefined variable $project

// in params contains Datetime field 
<?= view_cell('App\Libraries\ViewCellManager::showCardWithTabs', [
        'project' => $project,
        'categories' => $project->getCategories(),
        'firstCategory' => $firstCategory,
        'currentTab' => $currentTab
    ]) ?>

Can you provide minimum code to reproduce the error?

neznaika0 commented 1 year ago

I tried to shorten the code for the demo, but the error disappears in several cases:

echo serialize($project);
echo view_cell('App\Libraries\ViewCellManager::showCardWithTabs', ['project' => $project]);

But the error is still shown in the template (code above). My question is is it possible to change caching using serialize()? Let's say I have an object with nesting:

$project->getUser(): object
$project->getCategories(): object[]

And all this for md5() strings. I'll keep searching for a demo, but I don't think it's that easy.

kenjis commented 1 year ago

You can specify a custom cache name. Workaround:

<?= view_cell('App\Cells\Blog::recentPosts', 'limit=5', 0, 'custom-cache-name') ?>

See https://codeigniter4.github.io/CodeIgniter4/outgoing/view_cells.html#cell-caching

neznaika0 commented 1 year ago

Yes, I found this function by hints. The point is to make it work out of the box (auto)

kenjis commented 1 year ago

There was no such thing before - everything worked properly. Before PHP 8.2.5

Isn't it a bug in PHP?

neznaika0 commented 1 year ago

Probably. I gave a link to bugs.php.net - it says that serialize is called before wakeup(). I don't quite understand what the conversation is about

kenjis commented 1 year ago

CI4 does not have a class that implements Serializable. So the bug has nothing to do with CI4.

I recommend you report the bug to bugs.php.net.

neznaika0 commented 1 year ago

You can specify a custom cache name. Workaround:

<?= view_cell('App\Cells\Blog::recentPosts', 'limit=5', 0, 'custom-cache-name') ?>

See https://codeigniter4.github.io/CodeIgniter4/outgoing/view_cells.html#cell-caching

kenjis, couldn't figure out the reason. The best solution seems to be to specify the cache name. Because the object is too big

kenjis commented 1 year ago

I can't think of a better way than serialize(). So, if you are passing in an object that cannot be serialized, there is no other way than to modify it to a serializable class or specify a custom cache name.