-1

I am saving a customer class with some variables and methods to a session.

How do I manage to get all it's methods to work when fetching it back from a session? (Like an exact original if possible)

Is is what I have done so far:

<?php
namespace MyApp\Models;
use MyApp\Core\Database;
use MyApp\Helpers\Session;
use MyApp\Core\Config;

class Customer {

    private $db;

    public $host;

    public $dbName; 

    public $type;


    public function __construct($customerName = NULL)
    {
        # Get database instance
        $this->db = Database::getInstance();

        # If customer name passed as a variable 
        if ( $customerName ) {

            # Get Customer data from db
            $data = $this->customerDataByName($customerName);

            if ($data) {
                # Set data to $this Obj
                $this->setCustomerData($data['db_host'], $data['db_name'], $data['system_type']);
                # Set $this Obj to Session
                $this->setCustomerToSession();
            } else {
                return false; 
            }
        } 
    }


    public function setCustomerData($host, $dbName, $type)
    {
        # Set customer host in object
        $this->host     = $host;
        # Set customer name in object
        $this->dbName   = $dbName;
        # Set customer type in object
        $this->type     = $type;
    }


    public function setCustomerToSession()
    {
        Session::put(Config::$customer, $this); 
    }


    public function customerDataByName($customer_name) 
    {
        return $this->db->row("SELECT `db_name`, `db_host`, `system_type` FROM customers WHERE customer_name = :customer_name", array('customer_name' => $customer_name));
    }



    public function __sleep()
    {
        return array('host', 'dbName', 'type', 'customerDataByName()', 'setCustomerData()' );
    }

    public function __wakeup()
    {
        $this->db = Database::getInstance();
    }

}

The "host", "dbName", and "type" are restored properly using the __sleep() method, I tried to add the functions in a few different ways and no luck.. I would want it to be able to connect to the database too.

And also tried using an other method:

public function setCustomerToSession()
{
    $serialized = serialize($this);
    Session::put(Config::$customer, $serialized); 
}

Without the __wakup and __sleep, Then tried:

$a = unserialize($_SESSION['customer']);
var_dump($a);

and got this error:

PHP Fatal error: Uncaught PDOException: You cannot serialize or unserialize PDO instances in...

Pointing to the line of $serialized = serialize($this);

Imnotapotato
  • 5,308
  • 13
  • 80
  • 147
  • That warning doesn't seem to come from this class. It says it comes from `/www/myapp/core/Controller.php` while the posted code is `Customer` – M. Eriksson Dec 11 '18 at 16:12
  • @MagnusEriksson I have figured the warning thing.. i removed this question from my post – Imnotapotato Dec 11 '18 at 16:14
  • 1
    You're storing the "repository" class containing the actual object plus dependencies in a session. You should try to decouple the actual result (that's your actual Customer!) and store that instead. – Kasper Agg Dec 12 '18 at 00:30
  • Furthermore you're also violating the Single Responsibility Principle (SRP). The whole session handling should be taken care by another class entirely. I assume you want to store the actual Customer data in session, not your repository code. In that case I would advise you to split this class into (at least) three classes: a repository responsible for fetching data, a Customer class with customer-like properties and a Session service. – Kasper Agg Dec 12 '18 at 00:36
  • @KasperAgg Thank you for your comments! You mean after I run `$customer = new Customer($name);` I should save the `$customer` object to the session? (I tried this and got the same result) - regarding the SRP, thank you for noticing! So I might use the session assignment where I create the object (as mentioned in this comment). – Imnotapotato Dec 12 '18 at 10:23
  • That sounds correct. But the Customer class should in that case not contain a database manager (that is only used in the 'repository' part). I assume you only want to store the actual Customer values, in that case I would only accept the corresponding properties to be part of the class (things like $customerId, $name, $etc.). Hope that helps! – Kasper Agg Dec 12 '18 at 10:37
  • 1
    As an additional note: be aware that you cannot deserialize any serialized objects once the class has been changed! This makes such an approach 'brittle'. I would suggest to only store scalar types in session. – Kasper Agg Dec 12 '18 at 10:39
  • @KasperAgg I'm not sure if i understand right, you mean, when running something like `echo $_SESSION['customer']->host;` i wont get any result? (because this is exactly what happened to me now :< ) – Imnotapotato Dec 12 '18 at 11:11
  • No, you need to deserialize first: deserialize($_SESSION['customer']); – Kasper Agg Dec 12 '18 at 11:19
  • http://php.net/manual/en/function.unserialize.php .... `$customer = unserialize($_SESSION['customer']);` results: `PHP Warning: unserialize() expects parameter 1 to be string, object given in /www/myapp/core/Config.php on line 157` @KasperAgg – Imnotapotato Dec 12 '18 at 11:23
  • Uhm, in that case it seems you're not serializing it at all. If you do get an object back, you should be able to read property 'host'. Are you sure the property is set? – Kasper Agg Dec 12 '18 at 11:25
  • If I use `var_dump($_SESSION['customer'])` i do see the variables... What do you mean I'm not "serializing" when saving the object i just `$customer = new Customer($name); $_SESSION['customer'] = $customer;` – Imnotapotato Dec 12 '18 at 11:28
  • @KasperAgg `$_SESSION['customer'] = serialize($customer);` Solved it. So @Banujan Balendrakumar answer might have worked. Why this doesn't work inside the class `serialize($this);` (in main post - second approach) – Imnotapotato Dec 12 '18 at 11:33
  • 1
    Because you cannot serialize PDO objects. That's why I mentioned the SRP to split up classes. Glad it works now! – Kasper Agg Dec 12 '18 at 11:35
  • @KasperAgg Because... When I serialize from outside the class it doesn't fetch the pgo($db) variable? – Imnotapotato Dec 12 '18 at 11:47
  • If you have separated the classes in that way, then yes. Maybe you can add your new classes to your initial question. – Kasper Agg Dec 12 '18 at 11:52

1 Answers1

1

You should use the function serialize() to returns a string containing a byte-stream representation of value, In reverse you can use unserialize(). Because you can not store object in PHP SESSION.

The code should be,

session_start();

$a = your_object;
$b = serialize($a);

$_SESSION["serialized_data"] = $b; 
# To store in Session

$unserialized_data = unserialize($_SESSION["serialized_data"]); 
# To get from Session as Object
BadPiggie
  • 5,471
  • 1
  • 14
  • 28
  • This was my first try. I keep getting `PHP Fatal error: Uncaught PDOException: You cannot serialize or unserialize PDO instances` because of the `$this->db` variable.. i guess. Unless there is something else to do this this kind of situation. – Imnotapotato Dec 11 '18 at 16:19
  • @RickSanchez why are you trying to store `PDO Object` in `SESSION` ? – BadPiggie Dec 12 '18 at 10:37
  • I thought it would be good to fetch the object from the session and be able to run methods that depend on the $db connection... anyway your code doesn't work.. – Imnotapotato Dec 12 '18 at 11:12
  • review my post, i have edited it in regard of your answer – Imnotapotato Dec 12 '18 at 11:18