PHP Design Pattern for using instantiated classes - php

We are trying to understand the best way to use mysqli/other classes in multiple custom classes so that we don't instantiate a new object every time.
Is the code below the best/correct way of doing this?
The functions are only examples.
Thank you :)
<?php
class Base {
public function __get($name) {
if($name == 'db'){
$db = new mysqli('**', '*s', '*', '*');
$this->db = $db;
return $db;
}
if($name == 'blowfish'){
$blowfish = new PasswordHash(8, true);
$this->blowfish = $blowfish;
return $blowfish;
}
}
}
class A extends Base {
public function validate($username, $password) {
$query = $this->db->query("SELECT * FROM users");
return $query->num_rows;
}
public function password($password)
{
return $this->blowfish->HashPassword($password);
}
}
class PasswordHash {
public function __construct($iteration_count_log2, $portable_hashes) { }
public function HashPassword($password) {
return $password;
}
}
$a = new A;
echo $a->validate('test','test'); // returns number rows count as expected
echo $a->password('password123'); // returns password123 as expected
?>

You are/should probably be more interested in Dependency Injection instead of creating a tight coupling of Base|A and the MySQL database.

Related

Mockery does not mock propeties of class

i have test:
class ContacsBLOTest extends TestCase
{
public function testsearch()
{
$Ctrl= new ContactsBLO;
$data=['id'=>1,'name'=>'The Manh','phone'=>'123456566','address'=>'180 cao lo','note'=>''];
$data=[(object)$data];
$mock_data=\Mockery::mock('DB');
$mock_data->shouldReceive('all')->andReturn($data);
$mock_ctrl= new ContactsBLO;
$mock_ctrl->select=$mock_data;
$result=$mock_ctrl->search('manh');
$this->assertNotNull($result);
}
and this is ContacsBLO class:
class ContactsBLO
{
public $db,$not_allow,$Validation;
public function __construct(){
$this->db=new DB;
$this->not_allow=['"','\'','%'];
$this->Validation = new ContactValidation;
}
public function search($request=null){
$length=strlen($request);
for ($i=0;$i<$length;$i++) {
$forbidden=$this->not_allow;
if(in_array($request[$i],$forbidden)){
return (['messenger'=>'We are not allow special character in your request','old_input'=>$request]);
}
else{
return $data=$this->db->select('*',$request);
}
}
}
}
DB::class(i define connect to data base and define select method:
class DB
{
public $obj = null;
public $table = 'contacts';
public function __construct(){
$dsn="mysql:host=".HOST."; dbname=".DB_NAME;
$this->obj = new \PDO($dsn, DB_USER, DB_PASS);
$this->obj->query("set names 'utf8' ");
}
public function select($row=null,$query=null) {
$sql='SELECT '.$row.' FROM '.$this->table.' '.$query;
$data = $this->obj->prepare($sql);
$data->execute();
return $data->fetchAll(\PDO::FETCH_CLASS);
}
}
But when i run xdebug and run this test, $forbidden is null,it mean mock method return real data, not mock data. i dont know why.
Anyone can help me! Please!
You never inserted your mock into your class, besides when using the new keyword to create a class instance it's difficult to mock. Your only chance in such cases is to use class alias.
To avoid all this you can pass in the database instance through the ContactsBLO constructor.
class ContacsBLOTest extends TestCase
{
public function testSearch()
{
$data = ['id'=>1,'name'=>'The Manh','phone'=>'123456566','address'=>'180 cao lo','note'=>''];
$data = json_decode(json_encode($data));
$mock_contact = \Mockery::mock(DB::class);
$mock_contact->shouldReceive('select')->andReturn($data);
$Ctrl = new ContactsBLO($mockDB);
$result = $Ctrl->search('manh');
$this->assertNotNull($result);
}
}
class ContactsBLO
{
public $db;
public $not_allow;
public $Validation;
public function __construct(DB $db) {
$this->db = $db;
$this->not_allow = ['"','\'','%'];
$this->Validation = new ContactValidation;
}
public function search($request=null){
$length=strlen($request);
for ($i=0;$i<$length;$i++) {
$forbidden = $this->not_allow;
if(in_array($request[$i],$forbidden)){
return (['messenger'=>'We are not allow special character in your request','old_input'=>$request]);
}
else{
return $data = $this->db->select('*',$request);
}
}
}
}
I tested it with this code and it worked fine. Please check if the DB class is imported at the top of your test file. You also have to append Test to all test file names and classes (see above).
I was change it to:
$mock_data=\Mockery::mock('DB');
$mock_data->shouldReceive('select')->andReturn($data);
$mock_ctrl= new ContactsBLO;
$mock_ctrl->db=$mock_data;
$result=$mock_ctrl->search();
And it is working for me, thank for all help

(PHP) Should I create "triggers" in classes to access protected/private function?

I didn't find an answer to this question no where, so here it goes:
I normally create a protected/private function and public function as well to access the protected/private as a "trigger", is this a good practise or just a pointless excess of code?
Here is an example of what I'm talking about...
public function addData($data_c, $data_a)
{
if ($this->isUser()) {
$this->addDataDB($data_c, $data_a);
} else {
die;
}
}
private function addDataDB($data_c, $data_a)
{
$connect = self::connect_data();
$sql = "INSERT INTO `accounts`(...) VALUES (...)";
$s_network = $data_c['s_network'];
$country = $data_c['country'];
$group_name = $data_c['group_name'];
foreach ($data_a as $login_password) {
$account = explode(':', $login_password);
if (isset($account[0]) && !empty($account[0]) && isset($account[1]) && !empty($account[1])) {
$login = $this->encryptData($account[0]);
$password = $this->encryptData($account[1]);
if (!$this->checkDuplicates($login)) {
if ($stmt = $connect->prepare($sql)) {
$stmt->bind_param("sssssss", ...);
$stmt->execute();
}
$stmt->close();
}
}
}
$connect->close();
}
Thats not a bad idea, but the better way would be to create a new decorator class, which handles the secure access. In addition, it's a bad idea, to die - instead, you should throw an exception.
class A {
function addData(...) {
// ...
}
}
class SecureA extends A {
function addData {
if (...) {
throw new NotAllowedException(...);
}
parent::addData(...);
}
}
If you want to go a step further and make you code more cleaner, you should use an interface and don't extend from class A
interface InterfaceA {
function addData(...);
}
class A implements InterfaceA {
function addData(...) {
// ...
}
}
class SecureAccessA implements InterfaceA {
/**
* #var InterfaceA
*/
private $a;
public function __construct(InterfaceA $a) {
$this->a = $a;
}
function addData(...) {
if (...) {
throw new NotAllowedException(...);
}
$this->a->addData(...);
}
}
Doing this forces you to modify SecureAccessA, if you change the interface of InterfaceA. So you can't silently add functions to A, which are allowed to call, because you forgot to override them in the child class.

moving from procedural code to oop

Im relatively new to programming, with about 1 years part-time learning experience, im very new to PHP, only about a few weeks and using w3schools to help me
Im now trying to make the switch to OOP style and just cant understand the concept, or rather how and when to apply it and have thus turned here, where I have been a long time lurker instead of contributor for some help and advice.
I would like some help / short explanation how I would write the folloing in a PHP oop way
$sql="SELECT name, lastname, member_nr, joindate, order, creditCardInfo
from members
WHERE member_nr = $'member_nr'";
$result = mysql_query($sql) or die("error");
while($row = mysql_fetch_array){
echo '<h3>Personal Profile</h3>';
echo $name = $row['name'];
echo $lastName = $row['lastname'];
:
:
}
My problem is I dont know if I should create a class for the above, personal profile can be seen as a person right which is an object...? But do I include the HTML part and the mysql_query part etc in my class...Ive just got so many questions when it comes to OOP, its very hard to learn on your own thats why im really appreciate any drop of help or advice I can get on here
Thank you
First you should use mysqli, as all mysql_* are deprecated and are removed from PHP in the future.
Here a basis class with some functions, but you should expand it for your use! And learn what the functions do which got no comments on your own, to learn more.
This makes multiple connections to the database, so reading some stuff about singleton would be good for you too!
<?php
class dbconnection {
private $dbHostname;
private $dbName;
private $dbUsername;
private $dbUserpassword;
private $error;
private $querysuccess;
private $connected;
private $mysqli;
public function __construct() {
$this->dbHostname = 'localhost';
$this->dbName = 'databasename';
$this->dbUsername = 'username';
$this->dbUserpassword = 'password';
$this->connected = false;
}
public function __destruct() {
$this->mysqli->Close();
}
public function connect() {
//establishing a database connection
$this->mysqli = new mysqli($this->dbHostname, $this->dbUsername, $this->dbUserpassword, $this->dbName);
if($this->mysqli->connect_errno) {//When there was an error during the connecting
echo 'Connection Error:<br>'.$this->mysqli->connect_error;
$this->connected = false;
} else {
$this->connected = true;
}
if(!$this->mysqli->set_charset('utf8')) {//Need to be done for some functions!
echo 'Error during seting the charset: <br>'.$this->mysqli->error;
}
}
public function doquery($query_str) {
//method which executes the query
$returnval = false;
if($this->connected && $query_str != '') {
//only when connected AND the query is not empty
$res = $this->mysqli->query($query_str);//this is the equivalent of mysql_query
if($this->error_get() == '') {//Check for an error
$this->querysuccess = true;
} else {
$this->querysuccess = false;
}
$returnval = $res;
} else {
echo 'No database connection, this needs some!';
}
return $returnval;
}
public function query_success() {
return $this->querysuccess;
}
public function affected_rows_get() {
return $this->mysqli->affected_rows;
}
public function error_get() {
return $this->mysqli->error;
}
public function insert_id_get() {
return $this->mysqli->insert_id;
}
public function escape_str($str) {
return $this->mysqli->real_escape_string($str);
}
public function is_connected() {
return $this->connected;
}
public function fetch_assoc(&$res){
return $res->fetch_assoc();
}
public function fetch_assoc_array(&$res){
return $res->fetch_array(MYSQLI_ASSOC);
}
}
This case wouldn't be a good example. You want a class when you want to encapsulate logic of one entity to simplify its use outside the class.
For example:
class Member {
private $id, $name,
$lastname, $member_nr, $joindate, $order, $creditCardInfo;
public function __construct($id = 0) {
if($id != null) $this->loadFromDB();
}
private function loadFromDB() {
//Do db load here...
}
public function Update(){
//Do db update
}
public function Delete() {
//Do db delete...
}
public function GetFromMemberNR($nr) {
//Do select
}
//Additional Functions Verfication
}
In the end you'll have fairly complex code here. But to use it outside you just include the class's php file.
include 'member.php';
$member = new Member();
$member->GetFromMemberNR(2); //Does everything for you inside the function..
There are plenty of tools to help you do database operations easier, but that is the basis of OOP. The main idea is Encapsulation for reusability.

oop structure for make class such as PDO class structure

How to make class structure like PDO or ORM
$query = DB::table('users')->select('name');
$users = $query->addSelect('age')->get();
OR
$stmt = $pdo->prepare($sql);
$stmt->bindvalue(':u',intval($_SESSION['userId']),PDO::PARAM_INT);
$stmt->execute();
What is returned in to $query or $stmt?
how to design class structure like them?
Thank you
EDIT
$query = DB::table('users')->select('name');
meaning :
function select(){
//
return $this;
}
what's returned in to $query for this structure :
$query->addSelect('age')->get();
PDO is done by returning a new class (PDOStatement) with its own methods (read more about it), but it would be the same as:
<?php
class ClassOne
{
private $connection;
public function __construct($database_stuff)
{
$this->connection = $database_stuff;
}
public function prepare($sql)
{
// Code that does something with the $sql
// Then return a new class
return new ClassTwo($this);
}
}
class ClassTwo
{
private $ClassOne;
public function __construct(ClassOne $Class)
{
$this->ClassOne = $Class;
}
public function execute()
{
// Code that does something with ClassOne
}
}
# Start that initial class
$Class = new ClassOne('database:type;host=example;etc=yadayada');
# Do class one method
$query = $Class->prepare("SELECT * FROM fake_table");
# $query is now ClassTwo, so you do method from ClassTwo
$query->execute();
The ability to chain methods together is achieved because the current method returns the object back in the form of $this:
<?php
class DBClass
{
protected $connection,
$value;
public function __construct($connection)
{
$this->connection = $connection;
}
public function prepare($value)
{
$this->value = $value;
# Return the object
return $this;
}
public function execute()
{
echo $this->value;
# Return the object
return $this;
}
}
$con = new DBClass("login creds");
$con->prepare("update stuff if stuff = 'things'")->execute();
?>

Using SQL function from SQL handling class in other functions

I have created an SQL function SQLquery in a class called SQLHandling
It looks like this:
/***********************************************************
* SQLquery takes a full SQL query and runs it
* If it fails it will return an error otherwise it will return
* the SQL query as given.
************************************************************/
function SQLquery($query) {
$q = mysql_query($query);
if(!$q) {
die(mysql_error());
return false;
} else {
return $q;
}
}
Is there anyway I can use this function in other classes functions without adding
$db = new SQLHandling();
$db->SQLquery($sql);
In every function where I will use it.
I know I can run SQLHandling::SQLquery($sql); but I am trying to avoid that.
use inheritance
refer:
http://php.net/manual/en/language.oop5.inheritance.php
but still you will need to use parent::fun() or $this->fun()
or put it as a public function then use any where.
example:
<?php
function c()
{
echo "moi";
}
class b extends a
{
public function d(){
parent::c();//Hai
$this->c();//Hai
c();//moi
}
}
class a{
public function c(){
echo "Hai";
}
}
$kk = new b();
$kk -> d();
?>
You could instantiate SQLHandling on class level, like so:
private $db;
public function __construct()
{
$this->db = new SQLHandling();
}
public function x()
{
$this->db->query('X');
}

Categories