Love Fuel?    Donate

FuelPHP Forums

Ask your question about FuelPHP in the appropriate forum, or help others by answering their questions.
Setting a value for PK
  • Hello everyone,

    A couple of years ago I used FuelPHP 1.7.2 to develop a portal for internal use in my company. I recently updated the server and also updated Fuel to 1.8.1, as I'll be doing some further development. Everything worked just fine, but one issue with what it seems the PK being reset when I try to set a value for it at the time of forging a new entry.

    So, my a snippet of my code goes like this:

    $values = array(
                            'id' => Input::post('order'),
                            'customer_id' => Input::post('customer'),
                            'material_id' => Input::post('material_id'),
                            'job_name' => Input::post('job_name'),
                            'secondary_name' => Input::post('secondary_name'),
                            'shipping_id' => Input::post('shipping'),
                            'due_date' => $due_date,
                    );
    if ($val->run($values))
                    {
                        $order = Model_Order::forge($values);
       
                        if ($order and $order->save())
                        {
                            Message::success(e('Added order #'.$order->id.'.'));
       
                            Response::redirect('admin/orders');
                        }
       
                        else
                        {
                            Message::error(e('Could not save order.'));
                        }
                    }
                    else
                    {
                        $errors = $val->error();
                        foreach($errors as $error)
                            Message::error($error);
                    }

    "Id" contains the order #, which is also the PK of the table, and is not and cannot be auto-generated. If I check the content of the $value array, all my 7 elements are correctly there, but if check $order->to_array() after forging, "Id" is blank.

    After some code-digging and diff-running between the two versions, I found this was added at the end of the ORM/Model::__construct() method:

    // make sure the primary keys are reset
    foreach (static::$_primary_key as $pk)
    {
        $this->_data[$pk] = null;
    }

    If I comment it out, everything works as before, but I don't like the idea of having to do that. Is there any other way to accomplish the same behaviour, being able to set a PK value at the time of forging a new object?

    Thanks in advance!
  • HarroHarro
    Accepted Answer
    This is by design, it is to prevent creating an ORM object in "new" state with a valid and already existing PK, which will cause an exception when you want to save the object.

    Instead, use 

    $order = Model_Order::forge()->from_array($values);


  • Thank you for the explanation, Harro. Coming from 1.7.2, the situation was managed in the code with a good old try-catch and gracefully displaying a message. I'll take note of the the above and proceed to modify my code accordingly so it can be 1.8.1 "compliant".
  • I started working on the changes today and, even with your suggestion, I'm having the same issue. Looking at the from_array() method, the condition to set the properties checks whether the passed property is a PK or not, and doesn't set it if it is:

    if (array_key_exists($property, static::properties()) and ! in_array($property, static::primary_key()))

    So, it seems like my only option is to explicitly set the PK, as follows:

    $order = Model_Order::forge($values);
    $order->set('id', $values['id']);

    Please correct me if I'm wrong.
  • I'm sure you're right. 

    I've never bumped into this situation myself, but I understand this is annoying for you. I think people using databases without auto-increment, like PostgreSQL, have the same issue.

    I need to have a think about how to address this, perhaps make the check configurable in the model so you can enable/disable PK checks on a per-model basis.
  • Thank you once again, Harro. The check should be either configurable in the Model (probably the best option, IMHO) or there should be a way to "skip" it, like passing a boolean to forge() and from_array().

    In the meanwhile, I'll have some fun adding all my explicit PK sets LOL
  • If you can wait a few hours, I can see what I can do and save you a lot of work. ;-)
  • I sure can! :)
  • HarroHarro
    Accepted Answer
    Pushed an update to 1.9/develop.

    You can now add

    protected static $block_set_pks = false;

    to your models and set PK values through forge() and from_array().
  • That's fantastic, thank you Harro!
  • Let me know if this works for you, then I can push it to the release.
  • Hopefully I'll be able to try this tomorrow but, looking at the code, it looks like it's going to work like a charm
  • Harro, I've been running my development version for the last couple of days with the update you pushed for me, and everything is working perfectly. Thank you very much once again!
  • Thanks for the feedback!

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

In this Discussion