PDA

View Full Version : Double Dependency Injection?



Whiskas
19th November 2016, 21:12
Maybe someone smart can help figure it out for me.

I am making some website with accounts etc. On the index page, there is a form to login. After clicking Sign in button, this is executed:

$userService = new UserService($mysqli, $_POST['identity_number'], $_POST['password']);
if ($userService->login()) {
$_SESSION[user] = $userService->getUser();
header("Location: home.php");
}

I am creating object of UserService class, which looks like this:



class UserService
{
protected $_id;
protected $_passwd;

public $_db;
public $_user;

public function __construct(mysqli $db, $id, $passwd)
{
$this->_db = $db;
$this->_id = $id;
$this->_passwd = $passwd;
}

public function login()
{
$user = $this->_checkCredentials();
if ($user) {
$this->_user = new User($this->_db, $user->iduzytkownika, $user->imie, $user->nazwisko, $user->idgrupy, $user->idpodgrupy);
print_r($this->_db);
print_r($this->_user);
return $user;
}
return false;
}

protected function _checkCredentials()
{
$this->_id = $this->_db->real_escape_string($this->_id);
$this->_passwd = $this->_db->real_escape_string($this->_passwd);
$result = $this->_db->query("SELECT * FROM uzytkownicy WHERE iduzytkownika = $this->_id AND passwd = '$this->_passwd'");

if($result)
return $result->fetch_object();

return false;
}

public function getUser()
{
return $this->_user;
}
}

Everything is working fine, if the id and password is properly, new User class object is created, which looks like this:



class User
{
public $_id;
public $_name;
public $_lastname;
public $_groupID;
public $_subgroupID;
public $_db;

public function __construct(mysqli $db, $id, $name, $lastname, $groupID, $subgroupID)
{
$this->_db = $db;
$this->_id = $id;
$this->_name = $name;
$this->_lastname = $lastname;
$this->_groupID = $groupID;
$this->_subgroupID = $subgroupID;
}

public function __toString()
{
return $this->_name . " " . $this->_lastname;
}

public function getUserGroups()
{
print_r($this->_db); // For the debug purposes
}
}


And there comes the problem with $db mysqli object, which despites having proper structure (of mysqli class), all the values are empty. print_r from getUserGroups() returns:


mysqli Object
(
[affected_rows] =>
[client_info] =>
[client_version] => 50012
[connect_errno] => 0
[connect_error] =>
[errno] =>
[error] =>
[error_list] =>
[field_count] =>
[host_info] =>
[info] =>
[insert_id] =>
[server_info] =>
[server_version] =>
[stat] =>
[sqlstate] =>
[protocol_version] =>
[thread_id] =>
[warning_count] =>
)

I would like to note that mysqli object in UserService ain't empty.

Anyone got a clue to fix it or even properly name that problem. Cause I have trouble finding similar posts to mine.

Thanks in advance,

Whisky

kung foo man
20th November 2016, 00:42
$_SESSION[user] = $userService->getUser();


A session entry is a serialized piece of data, which cannot hold any resource variables. Either read the stuff you need directly at login time and serialize it into $_SESSION (when the resource is still valid), or, better way IMHO, read the stuff you need every time a user opens the page, so you don't have any out-of-sync data.

Whiskas
20th November 2016, 12:20
$_SESSION[user] = $userService->getUser();


A session entry is a serialized piece of data, which cannot hold any resource variables.


Thanks this is the thing I needed to know. I was wrongly thinking that mysqli object was the main problem.



read the stuff you need every time a user opens the page, so you don't have any out-of-sync data.


I wanted to make global user class object that would have functions (with mysql queries) returning appropriate data.

Like $user->getSomething(); and it would return information from the database about that something (groups this user belongs etc).

So, now my problem is finding a way to make global object.
Attempt:

index.php


global $user;

if (isset($user)) {
header("Location: home.php");
}

if (isset($_POST['btn-login'])) {

$userService = new UserService($mysqli, $_POST['identity_number'], $_POST['password']);
if ($userService->login()) {
$user = $userService->getUser();
header("Location: home.php");
}
}


home.php

global $user;

if (!isset($user))
header("Location: index.php");


After moving to home.php variable $user isn't set..

Reading most comments over this problem directs to Singleton Pattern, but personally I have no clue, how to pass parameters to the instance, so it could contain $id, $name etc.



class Singleton {
private static $instance;

private function __construct() {}
private function __clone() {}

public static function getInstance() {
if (!Singleton::$instance instanceof self) {
Singleton::$instance = new self();
}
return Singleton::$instance;
}

public function DoSomething() {
...
}
}


Any known sollution to make class object globl score?

Thanks again for your help.

EDIT:

I found sollution:



<?php

/**
* Created by PhpStorm.
* User: Meh
* Date: 20.11.2016
* Time: 12:51
*/
class DB extends MySQLi {
private static $instance = null ;

private $host = 'localhost';
private $user = "root";
private $password = "Wilki0101";
private $database = "mydb";

public function __construct($host, $user, $password, $database){
parent::__construct($host, $user, $password, $database);
}

public static function getInstance(){
if (self::$instance == null){
self::$instance = new self('localhost', "user", "pass", "db");
}
return self::$instance ;
}
}


Now, when the Class user needs to make queries, it just get's an instance like that:



include "DB.php";

class User
{
//private static $instance;
public $_id;
public $_name;
public $_lastname;
public $_groupID;
public $_subgroupID;
protected $_db;

public function __construct($id, $name, $lastname, $groupID, $subgroupID)
{
$this->_id = $id;
$this->_name = $name;
$this->_lastname = $lastname;
$this->_groupID = $groupID;
$this->_subgroupID = $subgroupID;
}

public function __toString()
{
return $this->_name . " " . $this->_lastname;
}

public function getUserGroups()
{
$this->_db = DB::getInstance();

$result = $this->_db->query("select p.idpodgrupy, p.nazwapodgrupy from podgrupy p
join grupy_podgrupy g
on p.idpodgrupy=g.idpodgrupy
join grupy gp
on gp.idgrupy = g.idgrupy
join uzytkownicy u
on u.idgrupy = gp.idgrupy
where u.iduzytkownika = 16");

print_r($result);
}
}


And the $results aren't empty.

Thanks anyway kung for your tip with $_SESSION!

kung foo man
20th November 2016, 13:38
What you try is not possible with PHP, the interpreter is basically resetted for every page request. That's why you need to reinitialize the needed data at every page request via new database queries.

When you need "sticky" variables, you could try node.js http server. The interpreter isn't "detached" behind by e.g. a FastCGI wall from the web server.

For PHP, just make a table relation between the $_COOKIE["PHPSESSID"] and the stuff you want to cache (e.g. which groups the user belongs to). Normally tho you just save the most important stuff like the session expiration time of the session and the user id, so the home.php has a way to know that the user is logged in via checking the cookie session ID against the session table.

You are welcome ^^