Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Write to multiple tables in joomla component?

I'm trying to create a component (front end) that uses multiple tables. I found 1 or 2 post that partially answer to the question but none really does. The point seems always simple and evident for the one who knows how to do it but it is never really explained (or I missed the right post).

In my component, the user enters data in one view that need to be stored in two tables: the standard Joomla User table i.e. # __users an additional table to store data that are not included in Joomla i.e. # __users_complements

I'm a beginner, so maybe I'm wrong, but I understood that the standard functions of joomla can only save results of a form in one table . In my case, I guess that I have to override the standard functions in my model: com_component / model / my_model.php.

1) I'm confused because I do not really understand which function must be overrided: save ()? store ()? other?

2) Let's say I override the save() function, should I rewrite all the code to save data (explode the data array and create all the update queries) or should I create 2 standard table objects.

In this case, (2 objects) it seems weird to send each time the whole data array to the parent function as I know that a part is for table 1 and the other part for the table 2. I should be able to split before don't I?

3) Should I create 2 models and manage those models from my controller when I get back data from the form and call the save function of the model?

Could you help me to clarify how to do this saving in multiple tables? An example with code will be very much appreciated. Thank you

like image 474
l_r Avatar asked Feb 06 '13 21:02

l_r


2 Answers

I finally made it. As I spent many hours on this and found that a lot of people where looking for an answer, here is how I did.

I suppose you know how to create a component, using the standard MVC structure:

  1. Component entry point
  2. Component controller
  3. Eventually component router
  4. Component view
  5. Component model
  6. Component controller

In model components\my_component\models\my_model.php create your own save function

public function save($data)
{
    // Initialise variables.
    $userId = (!empty($data['id'])) ? $data['id'] : (int)$this->getState('user.id');
    $user = JFactory::getUser();

    $table_one = $this->getTable('TableOne', 'MyComponentTable', array());
    $table_two = $this->getTable('TableTwo', 'MyComponentTable', array());

    // Bind the data.
    if (!$table_one->bind($data))
    {
        $this->setError(JText::sprintf('USERS PROFILE BIND FAILED', $user->getError()));
        return false;
    }

    if (!$table_two->bind($data))
    {
        $this->setError(JText::sprintf('USERS PROFILE BIND FAILED', $user->getError()));
        return false;
    }

    // Store the data.
    if (!$table_one->save($data))
    {
        $this->setError($user->getError());
        return false;
    }

    if (!$table_two->save($data))
    {
        $this->setError($user->getError());
        return false;
    }

    return $user->id;
}

Of course, you need the getTable function called in the save function

public function getTable($type = 'TableOne', $prefix = 'MyComponentTable', $config = array())
{
    // call the administrator\components\com_mycomponent\tables\__tablename__.php
    $this->addTablePath(JPATH_COMPONENT_ADMINISTRATOR . '/tables');
    return JTable::getInstance($type, $prefix, $config);
}

And it works! So simple! Of course, as I said in my question the whole $data is sent to the parent save() function to with data that are not necessary for table_one or table_two. It works this way with the standard joomla structure (no hack or direct query in the code).

Hope it helps.

like image 60
l_r Avatar answered Sep 30 '22 07:09

l_r


There may be those out there who disagree with the way that the following method disrupts the MVC structure just a bit, but I've found it to be the simplest for me.

Typically, you have a model that fits one of the tables. In your example with pushing data to the users table as well as one in your component, I would add the following to the model for the table in your component:

public function save($data) {
    if (!parent::save($data)) {
        return false;
    }

    // add necessary code to save to the users table, since there isn't a standard way to do this that I'm aware of

    // sometimes I will grab another model even
    require_once(JPATH_BASE . '/administrator/components/com_users/models/user.php');
    $other_model = $this->getInstance('user', 'UsersModel');
    $other_model->save($data);

    return true;
}

The first part of this function should save the data to the components table just like normal. But you can tack what you need on to the rest of the component to make whatever you like happen.

I would almost guarantee that there is a better way to chain models (and I've seen some of the changes happening in the Joomla Platform core that will lead to better ways in the future), but this should get you going for now.

In addition, for prompt 3, I would handle in the controller if you need to sometimes save just one table and sometimes save both. I've found that the save functions are pretty safe to run even when parts aren't loaded, so I usually just let it run.

like image 38
David Fritsch Avatar answered Sep 30 '22 07:09

David Fritsch