• 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Cancel $model->save($data) operation using $beforeInsert

#1
Hi everyone !

I have a controller, that checks if a record already exists in the database. If it does, it performs an update instead of an insertion.

But I want to take full advantages of all the models' features. So I'm trying to do the same thing, but with a function called using $beforeInsert.

My problem is that I don't know how to cancel the insertion, as CI expects an array... Someone has any clue on how I can do this ?

Here is the code I have in my model:

PHP Code:
  protected $beforeInsert = ['uniqueTokenPerUser'];

  protected function uniqueTokenPerUser(array $data)
  {
    if (! isset($data['data']['user']) ) { return $data; }

    // We check if a row already exists
    $currentToken $this->where('user',$data['data']['user'])->first();
    // If the row exists
    if( $currentToken !== FALSE ) {
      // We set the ID
      $data['data']['id'] = $currentToken['id'];
      // And perform an "update" using "save()" (could have been "update()" too)
      $this->save($data['data']); // THIS IS WORKING
      // And we stop the insertion
      return FALSE// THIS IS NOT WORKING -> ARRAY EXPECTED -> WHAT CAN I DO ?
    }
  


Thank you in advance for your help !
Reply

#2
I looked the model class and they are using the method trigger to do the event callback.

Take a look at the model and take a look at the insert, update and delete method's.

They are using a before and after trigger should get you going in the right direction.
What did you Try? What did you Get? What did you Expect?

Joined CodeIgniter Community 2009.  ( Skype: insitfx )
Reply

#3
Hello,

Thank you for your answer.

I saw this part of the code. But I couldn't find a way to make the trigger stop the rest of the code, without touching/extending core files.


So far, here is the "dirty" solution I found... (for those would might read this post later)


PHP Code:
  protected $beforeInsert = ['uniqueTokenPerUser'];

  protected function uniqueTokenPerUser(array $data)
  {
    if (! isset($data['data']['user']) ) { return $data; }

    // We check if a row already exists
    $currentToken $this->where('user',$data['data']['user'])->first();
    // If the row exists
    if( $currentToken !== FALSE ) {
      // We set the ID
      $data['data']['id'] = $currentToken['id'];
      // And perform an "update" using "save()"
      $this->save($data['data']);
      // And we stop the insertion with a "hard" redirection
      header('location: '.base_url('app/profile')); // Using "header" because "route()" doesn't want to work :-)
      exit; // Hard break
    }
  



I don't really like it, because it is now complicated to return the errors to the controller and the view. I am probably going to manage this in the controller (as I was doing originally). That is too much work for a simple operation. I thought maybe someone had a "miracle" solution :-)

Thank you anyway ;-)
Reply

#4
@littlej you cannot cancel an insert, partly because Events are potentially a chain spa ll need to return the data, transformed or not, for the next event. If I were you, I would extend the model and make my own insert() method something like this:
PHP Code:
public function insert($data nullbool $returnID true)
{

try
{
parent::insert($data$returnID);
}
catch (
CancelEventException $e)
{
return 
false;
}



And then you can define your own exception CancelEventException and throw it from uniqueTokenPerUser()

Sorry about the formatting, the forum software is freaking out on me.
Reply

#5
Thank you for your time, and for this answer which seems to be more suitable to me. I will dig into this in more detail :-)
Reply

#6
In the model, set the protected $primaryKey to the primary key of your table.

Then when you use the $model->save( $data ) method - if there is a value set for an array element in the $data that matches the $primaryKey the model will update the record if it does not exist the save method will insert a record.

Another method is to call either $model->insert($data) or $model->update( $yourPrimaryKey, $data ) depending on whether the record exists or not

Hope that helps.
Dirk B.
No SEO spam - see forum guidelines
Reply

#7
Thank you for your answer, but this i not exactly the problem ;-)

The problem is that each token has a unique ID (primary key). The "token" is a public string given to the user, and it can change. Unlike the ID, which never changes, and which is not secured enough (as the user could guess all combinations by trying 1, 2, 3...).

So I wanted to perform the exact same thing you say, but based on another data. And without giving/knowing the primary key. 

I did it "easily" inside the controller (by checking before updating). But I wanted to take full advantages of models, and keep the controller very simple. That is how I ended up trying to do this in $beforeInsert.

Thanks anyway :-)
Reply


Digg   Delicious   Reddit   Facebook   Twitter   StumbleUpon  


  Theme © 2014 iAndrew  
Powered By MyBB, © 2002-2020 MyBB Group.