octobercms / october

Self-hosted CMS platform based on the Laravel PHP Framework.
https://octobercms.com/
Other
11.04k stars 2.21k forks source link

After updation from v3.5 to v3.6, Plugin loads to soon failing to load translation file and to add a main menu item using BackendMenu::registerCallback #5795

Closed uematsusoft closed 7 months ago

uematsusoft commented 7 months ago

Hello,

After updating October to version 3.6.17 from v3.5 I have 2 problems;

1) I am not able to add menu items to backend's main menu with BackendMenu::registerCallback and $manager->addMainMenuItem(...) getting the error "Unable to add navigation items before they are loaded.";

2) I am not able to get translations (Lang::get) from my main plugin (IPC.Base) in the front-end but other plugins (IPC.SGE) that depends on the main one work. The main plugin requires the RainLab.Pages and RainLab.Translate.

For what I could find out, the main plugin (IPC.Base) translation file is loading before the tanslator FileLoader namespaces hints list have the ipc.base in it.

After dumping the namespaces list in FileLoader->loadNamespaced, the following code:

code_in_page

Results in this output:

output

Any ideas how I can overcome these problems?

Thank you in advance for your time.

uematsusoft commented 7 months ago

After some tests I was able to discover what was causing the translation problem and I have a fix (not final but works for now). In my plugin's boot method I extend the Backend User Class Using User::extend and when I extend the customMessages array with some translated value using Lang::get or trans, the translation problem appears in the frontend. Example code:

Backend\Models\User::extend(function ($model) {
    $model->customMessages = array_merge($model->customMessages, [
        'area_id.required_if' => Lang::get('ipc.base::lang.form.validation.required_for_area_other'),
        ...
    ]);
});

The temp fix that I found was to manually load the plugin's translations with the code on the plugin's boot method: Lang::load('ipc.base', 'lang', Lang::getLocale());

Hope this helps to replicate the error.

Best regards.

uematsusoft commented 7 months ago

The first problem about the backend menu was solved replacing the code in the plugin's boot method: BackendMenu::registerCallback(function ($manager) { With Event::listen('backend.menu.extendItems', function($manager) {

daftspunk commented 7 months ago

Hey @uematsusoft

The first problem about the backend menu was solved replacing the code in the plugin's boot method:

This is correct, the registerCallback method is only used internally by modules. Using the backend.menu.extendItems event is the documented approach for extending the navigation.

https://docs.octobercms.com/3.x/extend/backend/navigation.html#extending-the-backend-menu

daftspunk commented 7 months ago

Regarding the second issue, it's possible that if you access a language key before the plugin has initialized, then Laravel may cache the key, indicating that it does not exist.

The language paths are loaded in the register() method of the plugin base class, so the plugin load order issue could be solved by accessing the language keys in the boot() method instead.

Hopefuly this helps!

uematsusoft commented 7 months ago

Hello @daftspunk, Thank you for your answers.

All the code and the temporary fix already is on or is called from the boot method. That's why I believe that could be more to it because it should work and the problem only started to occur when I updated from version 3.5.

Thanks.

daftspunk commented 7 months ago

It is most likely related to this part of the RN: https://octobercms.com/support/article/rn-37#notable-changes


Module Load Order Changed

The load order of service providers (modules, plugins, app) has been changed in this version. This has a low likelihood of impact, however, plugin developers should be aware of this difference.


Can you provide a short/simple code example of how we can replicate the issue? I'm not sure I understand the bug fully.

uematsusoft commented 7 months ago

I did have to remove the "Backend.Models.User" from the main plugin $require items since it crashed the backend.

I was trying to make a simple plugin to send you but the error did not occur. But I found that if I kept the main plugin IPC.Base as it was and only add the code Lang::get('ipc.sge::lang.menu.equipment_types'); in the second plugin's boot method, everything start to work normally.

I attached the code for the 2 plugins and images of falling and working samples. The original plugins were created with the builder plugin and I simplified the IPC.Base plugin to the minimum to fail.

IPC.SGE.Plugin.txt IPC.Base.Plugin.txt

Not working:

failing_example

Working with the IPC.SGE boot code:

working_example

Hope I helps identifying the problem because I am lost. I don't mind if I have to manually load the translations but I don't know if it will not appear other related errors down the line.

Thank you.

daftspunk commented 7 months ago

Can you change to this code below? It defers the language resolution further down the stack and not loading them too early.

// From validation trait
$model->bindEvent('model.beforeValidate', function() use ($model) {
    $model->customMessages = array_merge($model->customMessages, [
        'area_id.required_if' => Lang::get('ipc.base::lang.form.validation.required_for_area_other'),
        'sec_area_id.required_if' => Lang::get('ipc.base::lang.form.validation.required_for_area_other'),
        'project.required_if' => Lang::get('ipc.base::lang.form.validation.required_for_position'),
        'is_phd_student.accepted_if' => Lang::get('ipc.base::lang.form.validation.required_for_position'),
        'doctoral_programme.required_if' => Lang::get('ipc.base::lang.form.validation.required_for_position'),
        'orcid_id.required_unless' => Lang::get('ipc.base::lang.form.validation.required_for_position'),
        'supervisors.*.name.required_if' => Lang::get('ipc.base::lang.form.validation.required_for_position'),
        'supervisors.*.email.required_if' => Lang::get('ipc.base::lang.form.validation.required_for_position'),
    ]);
});
uematsusoft commented 7 months ago

Hi.

Thank you for the answer, it solved the problem! I already had that bind so I just moved the code into it.

Best regards.

daftspunk commented 7 months ago

Hey @uematsusoft

That is great to hear! Thanks for reporting back.