Skip to content

Bug: [ViewCells] when there are cells with the same short name, only the first cell is loaded #7684

@jeandemoroque

Description

@jeandemoroque

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?

Windows

Which server did you use?

apache

Database

No response

What happened?

Hello,

I created a project that uses widgets. My widgets are in folder /app/Widgets. Theses widgets are used to display partial views.
For exemple, the widget /app/Widgets/Customer/Account.php have a method lastRegistrations to display 10 last registrations to the administrator.

In the same page, I call two widgets to display latest registrations of Customers and Administrators like that :
=> <?= view_cell("\App\Widgets\Customer\Account::lastRegistration"); ?>
=> <?= view_cell("\App\Widgets\Admin\Account::lastRegistration"); ?>

Everything worked fine when I was on version 4.1 with PHP7.4.
Today, I upgraded my CodeIgniter project to the latest version 4.3.6 with PHP 8.2.

The project launches fine overall after some changes, but I noticed a problem on some pages.

In the page where I call the two previous widgets, I noticed that the second widget (Admin) displayed the same content as the first widget (Customer).

I did some research, and I found the source of the problem in the file system/Config/Factories.php in the method __callStatic.

In this method, there is a line $basename = self::getBasename($name); who return the name of the class.
=> In my case : $name = "\App\Widgets\Customer\Account";
=> Result : $basename = "Account";

This method stores the namespace in array self::$basenames using $basename as key.
The self::$basenames variable is used to check if an instance of the class already exists and to return the namespace of the class.

In my case, my two widgets have the same basename, so the second call will use an instance of the first call, because the check is based on the same basename. This is why I have the same results.

To solve this, I found two solutions:
1. Use $name instead of $basename : self::$basenames[$options['component']][$name] = $class;
2. Or, generate a hash of the $name : $basename = md5($name);

Steps to Reproduce

  1. Install CodeIgniter (version 4.3.6)
  2. Create two controllers with the same name in two subfolders :
    => /app/Controllers/SubFolderOne/Test.php
    => /app/Controllers/SubFolderTwo/Test.php
  3. Create a method on each controllers who return different string values
  4. Call this two methods in view file using "view_cell" function
    => <?= view_cell("\App\Controllers\SubFolderOne\Test::render"); ?>
    => <?= view_cell("\App\Controllers\SubFolderTwo\Test::render"); ?>
  5. The first call will return the result of first controller, but the second call will also return the content of first controller instead of the second controller

Expected Output

The first call will be return the result of first controller, and the second call will be return the content of the second controller.

Anything else?

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugVerified issues on the current code behavior or pull requests that will fix them

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions