0

I have this function:

public function insert_task_in_table_finished(int $city_id, string $street, string $phone, string $date, int $price, string $comment, int $operator_id, int $task_id, int $status_id, int $team_id, string $started_on, string $finished_on): int
{
        $connection = $this->get_db_connection();

        $stmt = $connection->prepare(
            "INSERT INTO "
            . "`tasks_finished`"
            . "(`city_id`, `street`, `phone`, `date`, `price`, `comment`, `operator_id`, `task_id`, `status_id`, `team_id`, `started_on`, `finished_on`)"
            . " VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");

        $stmt->execute([$city_id, $street, $phone, $date, $price, $comment, $operator_id, $task_id, $status_id, $team_id, $started_on, $finished_on]);
        $result = $stmt->rowCount();
        $stmt = null;
        return $result;
}

What I am looking to do is - get the ID of the element that I have just inserted with this query.

I have done my research and found that there exists PDO::lastInsertId function or mysqli_insert_id both of which return id used in the latest query.

This would seem like something I would need, however, my main concern is the following situation:

Let's say I have many users on my website and few of them decided to finish a task simultaneously so 3 of them press corresponding buttons.

The idea is that each user should receive an ID of the task that He has finished, but considering that those function return that ID of the last inserted row, I think that it is possible that it could lead to a situation where a user receives ID of task inserted by someone else in case when there are many simultaneous finishes.

Edit: The questions are:

  • For those who have more experience working with PDO/MySQL - is the scenario I described possible?
  • If it is, what would be the correct approach to guarantee that each user receives the id of the task that he himself has inserted? (Besides the obvious SELECT method)

Edit 2:

Here is how my get_db_connection() looks:

class DB
{
    private function get_db_connection(): PDO
    {
        $dsn = "mysql:host=127.0.0.1:3306;dbname=crm;charset=utf8mb4";
        $username = 'root'; // TODO -> replace with proper one when moving to producction
        $password = ''; // TODO -> replace with proper one when moving to producction

        $options = [
            PDO::ATTR_EMULATE_PREPARES => false, // turn off emulation mode for "real" prepared statements
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, //turn on errors in the form of exceptions
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, //make the default fetch be an associative array
        ];

        try {
            $pdo = new PDO($dsn, $username, $password, $options);
        } catch (Exception $e) {
            error_log($e->getMessage());
            exit('Unknown error: PDO Creation');
        }

        return $pdo;
    }

All the actions that are related with DB changes are made only through my repository which has each function create its own instance of DB class and then call DB functions from there.

Like this: (2 functions from my repository)

function get_user_by_id(int $id)
{
    $DB = new DB();
    $user = $DB->select_user_by_id($id);

    if (empty($user)) {
        return false;
    }

    return $user;
}

function create_new_task(string $table, string $street, string $phone, string $date, int $price, string $comment, string $operator_id): bool
{
    $DB = new DB();
    $result = $DB->insert_task_in_table($table, $street, $phone, $date, $price, $comment, $operator_id);

    if (empty($result)) {
        return false;
    }

    return true;
}

I guess this approach guarantees that each user has his own connection, even more so, each function has its own connection, correct?

Vitaliy-T
  • 733
  • 6
  • 23
  • From my knowledge is `PDO::lastInsertId` bound to the pdo (so basicly to the referenced object, in your case its `$stmt`). Maybe someone could confirm that. Otherwise this function would have been pointless (since it would produce random results). Please read the [manual](https://www.php.net/manual/en/pdo.lastinsertid.php). There are important notes, such as this: *"This method may not return a meaningful or consistent result across different PDO drivers, because the underlying database may not even support the notion of auto-increment fields or sequences."* – Definitely not Rafal Dec 10 '20 at 14:10
  • 2
    The last insert ID is kept _per connection_, so assuming you have a “normal” setup where each of those requests by your three different users establishes its own database connection, there is nothing to worry about at all. – CBroe Dec 10 '20 at 14:19
  • https://stackoverflow.com/questions/17112852/get-the-new-record-primary-key-id-from-mysql-insert-query – Felippe Duarte Dec 10 '20 at 14:22
  • BTW, there is no point in returning the rowCount. It will always return 1 no matter that, hence it's just pointless. You can return said insert id instead – Your Common Sense Dec 10 '20 at 14:24
  • @CBroe could you please take a look at `Edit 2` I made to my post. I added a bit more information on how everything works in my code. – Vitaliy-T Dec 10 '20 at 14:42
  • yes, this approach guarantees that each function has its own connection and that's what you should absolutely NOT to do. – Your Common Sense Dec 10 '20 at 14:51
  • see [how to use pdo in your code](https://stackoverflow.com/a/43631201/285587) – Your Common Sense Dec 10 '20 at 14:52
  • @YourCommonSense Thanks a lot for the link. – Vitaliy-T Dec 10 '20 at 15:32
  • @YourCommonSense one last question I have is: If I make my `get_db_connection` staic and then in each function simply do `self::get_db_connection` I believe that would ensure that I have a single instance that is simply reused, am I correct? – Vitaliy-T Dec 10 '20 at 15:38
  • not at all. static or not static, it creates a new connection every time it's called. Besides, using such a function will be against OOP principles. You have to make your mind, whether your code is OOP or procedural – Your Common Sense Dec 10 '20 at 15:41
  • @YourCommonSense I got it, cheers – Vitaliy-T Dec 10 '20 at 15:41
  • @YourCommonSense Hello again. I'd like to ask you for an advice. I am looking to learn OOP PHP and I know, there is plenty information online, but since you seem to know PHP quite well, perhaps you could give me some suggestions on where could I start if that isn't too much to ask. – Vitaliy-T Jan 24 '21 at 14:51
  • Hi. I know PHP but I don't know much tutorials. Based on the author's reputation I would recommend this one https://laracasts.com/series/object-oriented-bootcamp-in-php – Your Common Sense Jan 26 '21 at 18:22

0 Answers0