0

I'm on Joomla 4.3

I'm creating a component and a plugin that are meant to work together. The component has a model, and new instances of the model can be saved via the admin interface, but can also be created via the plugin.

Where I'm running in to problems is creating models via the plugin and getting back the ID of the newly created model / DB row.

My relevant plugin code:

$model = Factory::getApplication()->bootComponent('com_chatlinks')
    ->getMVCFactory()
    ->createModel('Chatlink', 'Administrator');
$user = $new->getBuyer();
$data = array(
    'id' => 0,
    'user_id' => $user->id,
);

if ($model->save($data)) {
    $newId = $model->getState('chatlink.id');
    $otherId = $model->getItem()->get('id');
    Log::add('*** New Sub Model ID:' . ' ' . $newId . ' || other ID: '. $otherId, Log::INFO, 'chatlinks');
} else {
    $error = $model->getError();
    Log::add('*** New Sub ERROR' . ' ' . $error, Log::INFO, 'chatlinks');
    // Handle the error
}

This code works, all the data shows up in the database as expected, however the ID variables in the Log statement are set to 1, even though the actual ID in the DB is not 1 (it's auto-incrementing): 2024-01-02T15:52:53+00:00 INFO 24.80.19.210 chatlinks *** New Sub Model ID: 1 || other ID: 1

However, I discovered that if I add a Log statement to the part of the Joomla codebase responsible for actually setting 'chatlink.id' (/libraries/src/MVC/Model/AdminModel.php):

if (isset($table->$key)) {
  Log::add('base model isset: ' . $this->getName() . ' | ' . $table->$key . ' | ' . $this->getState($this->getName() . '.id'), Log::INFO, 'chatlinker');
  $this->setState($this->getName() . '.id', $table->$key);
}

Then my original Log statement in the plugin magically works as I expect it to:

2024-01-02T15:51:02+00:00   INFO 24.80.19.210   chatlinker  base model isset: chatlink | 22 | 1
2024-01-02T15:51:02+00:00   INFO 24.80.19.210   chatlinks   *** New Sub Model ID: 22 || other ID: 22

This is the only change I'm making. I've tried it several times now, enabling and disabling the Log statement in AdminModel.php and it replicates every time. Everything I'm doing in the Log statement is just reading data, as far as I understand it, so the code in the Log statement shouldn't be creating any changes.

I don't understand what's going wrong here, or why adding in a Log statement seems to magically fix it? I'm fairly new to php and joomla so maybe I'm missing something obvious. But just leaving the Log statement in the AdminModel.php file doesn't seem like a good or viable solution long term.

EDIT: I've narrowed it down the $this->getState($this->getName() . '.id') part of the Log statment in AdminModel.php. The ID in the plugin Log statement will read correctly only if that code is in the Log statement in AdminModel. Without that the IDs always read as 1.

1
  • In the above question you make a couple of references to changing ../libraries/src/MVC/Model/AdminModel.php. If you are changing the Joomla core libraries then you shouldn't as you elude to it is not a good long term solution.
    – Irata
    Jan 2 at 23:38

2 Answers 2

0

It looks like you just need to call getState() before doing setState(). So I added $model->getState(); before I called $model->save($data) in the plugin code and now the IDs are reading correctly. Seems super janky but apparently this is the expected behavior: https://github.com/joomla/joomla-cms/issues/23611

Maybe this is fixed in Joomla 5.

0

Without seeing the code used in your ChatlinkModel it is difficult to be more specific however generally shouldn't need to be using State to pass the value(s) between functions within the current execution.

Normally I would expect that the Model would create an object of the Table class and use the save() method of the Table class to perform the actual save of the data to the table. The Table object would then contain the values just saved, including the new record id, that you can access directly.

ChatlinkModel.php

use mycomp\Component\Chatlink\Administrator\Table\ChatlinkTable;
    
class ChatlinkModel extends AdminModel
{
        ...
    public function save($data)
    {
        $this->chatlink = new ChatLinkTable();
        $this->chatlink->save($data);
        return $this->chatlink;
    }
}

In your pluguin the code would look something like this.

$model = Factory::getApplication()->bootComponent('com_chatlinks')
    ->getMVCFactory()
    ->createModel('Chatlink', 'Administrator');
...
);

if ($model->save($data)) {
    $newId = $model->chatlink->id;
    ...
} else {
    $error = $model->getError();
    Log::add('*** New Sub ERROR' . ' ' . $error, Log::INFO, 'chatlinks');
    // Handle the error
}
1
  • In ChatlinkModel.php save method I'm doing some basic validations and then calling parent::save($data);. I recognize that I could just re-write the save method and do whatever I want there, but then I would lose all the functionality of the existing save method, which doesn't seem like a good idea.
    – Stu
    Jan 11 at 18:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.