PHP OOP: Duplicate Code in a Class - php

I have a PHP class with two methods. One connects to a MySQL database for output, and the other connects to a MySQL database for input.
My question is, for both functions, I repeated the code for connecting to the database. What would be a better way to maybe have a third function in the class to connect to the DB and have the other two call the function to establish the connection, rather than repeat the code twice? I'm a PHP n00b trying to improve my OOP coding. Notice how I connected to the DB twice--using the exact same code:
class output_mysql {
var $db_name = 'database';
var $db_username = 'name';
var $db_password = 'mypassword';
function print_table_cell($tbl_name, $colm_name, $array_index_num) {
try {
$pdo = new PDO("mysql:host=localhost;dbname=$this->db_name", $this->db_username, $this->db_password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch (PDOException $e) {
$error = 'Unable to connect to the database server.';
include 'output_mysql_error.php';
exit();
}
try {
$sql = "SELECT $colm_name FROM $tbl_name";
$result = $pdo->query($sql);
}
catch (PDOException $e) {
$error = 'Error fetching content: ' . $e->getMessage();
include 'output_mysql_error.php';
exit();
}
while ($row = $result->fetch()) {
$all_content[] = $row["$colm_name"];
}
echo $all_content[$array_index_num];
}
function update_content($tbl_name, $colm_name, $error_message_text, $id_num) {
try {
$pdo = new PDO("mysql:host=localhost;dbname=$this->db_name", $this->db_username, $this->db_password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch (PDOException $e) {
$error = 'Unable to connect to the database server.';
include 'output_mysql_error.php';
exit();
}
try {
$sql = 'UPDATE website_content SET
content = :content,
date_added = CURDATE()
WHERE id = :id';
$s = $pdo->prepare($sql);
$s->bindValue(':content', $error_message_text);
$s->bindValue(':id', $id_num);
$s->execute();
}
catch (PDOException $e) {
$error = 'Error: ' . $e->getMessage();
include 'output_mysql_error.php';
exit();
}
}
}

This question is tagged [oop], but the code in it is far from OOP.
Your methods are doing waaaaaaaaaaaaay too much. What you should do is inject the database connection into the constructor of the output_mysql class (which is a terrible name btw).
namespace App\Page;
class Content
{
private $dbConnection;
public function __construct(\PDO $dbConnection)
{
$this->dbConnection = $dbConnection
}
public update($id, $content)
{
$stmt = $this->dbConnection->prepare('UPDATE website_content SET content = :content, date_added = CURDATE() WHERE id = :id');
$stmt->execute([
'id' => $id,
'content' => $content,
]);
}
}
$dbConnection = new \PDO("mysql:host=localhost;dbname=$this->db_name", $this->db_username, $this->db_password);
$dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$dbConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$pageContent = new \App\Page\Content($dbConnection);
$pageContent->update(1, 'new content');
If you have a method called print_table_cell you are probably doing OOP wrong, because it probably means you code is doing too much and probably violates the Single Responsibility Principle. I mean a class in almost all circumstances would never need to be able to access any column of just any table.

class Model
{
protected $pdo;
/**
* Inject the pdo driver in the model.
*/
public function __construct(PDO $pdo)
{
$this->pdo = $pdo;
}
public function print_table_cell($tbl_name, $colm_name, $array_index_num)
{
// Use the pdo object $this->pdo
}
}
// Create the connection
$dbName = '';
$dbUsername = '';
$dbPassword = '';
$pdo = new PDO("mysql:host=localhost;dbname=$dbName", $dbUsername, $dbPassword);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// Create your model and inject the pdo object.
$model = new Model($pdo);
$model->print_table_cell() ...
As said above you need to use prepared statements, because PDO will escape the values which prevents SQL injections. But anyway all input data must be filtered : you have some basic filters http://php.net/manual/fr/function.filter-var.php.
The model class should only interact with the database, and doesn't print anything.
For priting output you can use a so called View class that get data from the model and displays it.
class View
{
protected $model;
public function __construct(Model $model)
{
$this->model = $model;
}
public function render()
{
echo $this->model->getData();
}
}
class Model
{
protected $pdo;
public function __construct(PDO $pdo)
{
$this->pdo = $pdo;
}
public function getData()
{
// Do your query here with $this->pdo and prepared statement.
// and return the data
}
}
$pdo = new PDO(...);
$model = new Model($pdo);
$view = new View($model);
$view->render();

Related

Class 'Db' not found

When I attempt to connect to my SQL database with my pdo_object.php file, my model.php returns this error:
Fatal error: Class 'Db' not found in /path/model.php on line 8
I made sure all of the permissions are correct and credentials are correct for all of my files. Here are the two files in question.
Not really sure what the issue is here so any help would be awesome.
pdo_object.php
<?php
$user = 'someusername';
$pass = 'somepassword';
$db_info='somehost';
try {
$db = new PDO($db_info, $user, $pass);
} catch (PDOException $e) {
print "Error!: " . $e->getMessage() . "<br/>";
die();
}
?>
and then model.php
<?php
include('pdo_object.php');
class Model{
public $db;
public function __construct(){
$this->db = Db::getDb();
}
public function getAllRecords($sql, $parameters = null){
$stm = $this->db->prepare($sql);
$stm->execute($parameters);
return $stm->fetchAll();
}
public function getOneRecord($sql, $parameters = null){
$stm = $this->db->prepare($sql);
$stm->execute($parameters);
return $stm->fetch();
}
}
?>
Where is class Db { //blah }? Nowhere. But you HAVE defined $db in the first file.
I also recommend dependency injection, rather than calling static class methods inside your class. Essentially, pass the $db in in the constructor:
public function __construct(PDO $db)
{
$this->db = $db;
}
And instantiate like so:
$model = new Model($db);
The Db class was not present in the pdo_object.php file, thus resulting in the index.php file throwing an error when referencing a non existing class.
class Db {
private static $db;
public static function getDb() {
if(!self::$db) {
try {
$dsn = 'somehost; dbname=somedbname';
self::$db = new PDO($dsn, 'username', 'password');
self::$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
self::$db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
} catch (PDOException $e) {
die('Connection error: ' . $e->getMessage());
}
}
return self::$db;
}
}

PHP PDO class use in different class (doesn't work)

I wanna get data on table and write a class. But this class doesn't work because pdo doesn't access. How can I get table data with this class?
$db = new PDO("mysql:host=localhost;dbname=xxx;charset=utf8", "xxx", "xxx");
class uye extends PDO{
var $id;
var $kadi;
function cek($id){
$query = $db->query("SELECT * FROM btc WHERE id='{$id}'", PDO::FETCH_ASSOC);
if ( $query->rowCount() ) {
foreach( $query as $row ){
$this->id=$row["id"];
$this->kadi=$row["kadi"];
}
}
}
}
$bilgiler=new uye;
$bilgiler->cek(1);
echo $bilgiler->kadi;
So I'm running this off of fetching all data as I dont know where you're getting $id from.
I generally break my code up into files and folders as I found this easier to work with and others to work on.
// database connection file (dbc.php)
class Database
{
private $host = "127.0.0.1";
private $db = "";
private $user = "";
private $password = "";
public $conn;
public function dbConnect()
{
$this->conn = null;
try
{
$this->conn = new PDO("mysql:host=" . $this->host . ";dbname=" . $this->db, $this->user, $this->password);
$this->conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch (PDOException $exception)
{
echo "Connection error: " . $exception->getMessage();
}
return $this->conn;
}
}
I then make a common file, this is where you can store all of your frequently used functions or your static functions
// Common file (common.php)
require_once('dbc.php');
class DBCommon
{
private $conn;
public function __construct()
{
$database = new Database();
$db = $database->dbConnect();
$this->conn = $db;
}
public function run($sql)
{
$stmt = $this->conn->prepare($sql);
return $stmt;
}
}
So to explain this a little more, you will see a function of run() this is just to save the tedious $this->conn->prepare on every query.. Now you can run $this->run()
The next would be your class file.. this is where your logic goes:
// your class file... (class.btc.php)
require_once "common.php";
class BTC extends DBCommon
{
public function getQuery()
{
$stmt = $this->run("SELECT * FROM `btc`");
$stmt->execute();
while ($row = $stmt->fetch(PDO::FETCH_OBJ))
{
$rows[] = $row;
}
return $rows;
}
}
Self explanatory..
And then your calling method.. Lets say index.php
// File you're calling your class from (index.php)
require_once "class.btc.php";
$fetch = new BTC();
$returnData = $fetch->getQuery();
foreach ($returnData as $data)
{
echo
"<p>$data->something</p>
<p>$data->somethingElse</p>";
}
It seems a little long winded I know, but the time you'll save overall will help!

Undefined function getTeam()

So what I want to do is to show who's in a team. I've created a function called getTeam().
class admin
{
private $db;
public function __construct($conn)
{
return $this->db;
}
public function getTeam($teamname)
{
try
{
$sql = "SELECT * FROM `tbl_players` WHERE EXISTS (SELECT id FROM `tbl_teams` WHERE team_name=:team_name)";
$stmt = $this->db->prepare($sql);
$stmt->bindparam(":team_name", $teamname);
$stmt->execute();
return $stmt;
}
catch(PDOException $e)
{
echo $e->getMessage();
}
}
}
Here is my dbconnect I'm using
session_start();
$DB_host = "localhost";
$DB_user = "root";
$DB_pass = "";
$DB_name = "project_fifa";
try
{
$conn = new PDO("mysql:host={$DB_host};dbname={$DB_name}",$DB_user,$DB_pass);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch(PDOException $e)
{
echo $e->getMessage();
}
include ('assets/classes/admin.php');
$user = new admin($conn);
So now I'm trying to use the function here
require('../dbconnect.php');
if(isset($_POST['findteam'])){
$teamname = $_POST['teamname'];
getTeam($teamname);
}
It can't find the function and I don't know why.
If you are doing code with OOPS, First you have to learn some basics about it Read it
Object(new) :
To create an instance of a class, the new keyword must be used. An object will always be created unless the object has a constructor defined that throws an exception on error. Classes should be defined before instantiation (and in some cases this is a requirement).
If a string containing the name of a class is used with new, a new instance of that class will be created. If the class is in a namespace, its fully qualified name must be used when doing this.
$adminObject = new admin();
$adminObject->getTeam($teamname);

Select PHP PDO best way to make

I have a question on how to draw a connection to a select box that is inside a function.
I call this way:
Function MySQL:
mysql.php
function conectar() {
try {
$dbh = new PDO("mysql:host=localhost;dbname=adm-new", 'root', '');
} catch (PDOException $dbe) {
echo $dbe->getMessage();
}
return $dbh;
}
$conn = conectar();
Function select:
menu.php
function z_menu_todos() {
global $conn;
$z_menu = "SELECT *
FROM z_menu
ORDER BY posicao ASC";
return $conn->prepare($z_menu);
}
I did not want to call the variable global $conn.
What would be the best way to do?
I would create a DatabaseFactory class which would serve for creating database connection, like this:
ConnectionFactory.php
class ConnectionFactory {
private $_connection;
public function __construct($dbName, $dbUser, $dbPassword, $dbHost = 'localhost'){
try {
$this->_connection = new PDO("mysql:host=$dbHost;dbname=$dbName", $dbUser, $dbPassword);
$this->_connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e){
throw new DatabaseFactoryException('Could not create connection:' . $e->getMessage());
}
}
public function getConnection(){
return $this->_connection;
}
}
After that I would create MenuRepository class which would server for executing queries associated with Menu, like this:
MenuRepository.php
class MenuRepository {
private $_connection;
public function __construct(PDO $connection){
$this->_connection = $connection;
}
public function getMenus(){
$stmt = $this->_connection->prepare("SELECT * FROM z_menu ORDER BY posicao ASC");
$stmt->execute();
return $stmt->fetchAll();
}
}
I would create configuration in separate file, like this:
config.php
define('DB_NAME', 'adm-new');
define('DB_USER', 'root');
define('DB_PASS', '');
After that I would use:
index.php
require __DIR__ . '/config.php';
require __DIR__ . '/ConnectionFactory.php';
require __DIR__ . '/MenuRepository.php';
$connectionFactory = new ConnectionFactory(DB_NAME, DB_USER, DB_PASS);
$connection = $connectionFactory->getConnection();
$menuRepository = new MenuRepository($connection);
$menus = $menuRepository->getMenus();
class Database
{
protected $conn;
public function __construct()
{
try {
$this->conn = new PDO("mysql:host=localhost;dbname=adm-new", 'root', '');
} catch (PDOException $dbe) {
echo $this->conn->getMessage();
}
}
public function z_menu_todos()
{
$z_menu = "SELECT *
FROM z_menu
ORDER BY posicao ASC";
return $this->conn->prepare($z_menu);
}
}
Usage
$database = new Database();
$stmt = $database->z_menu_todos();
Modify this as you require, this is a very basic example of how to do this, do not just copy and paste it.
In this case, you should avoid using global variables, because you can easily pass the connection to method as method argument, like this:
function conectar() {
try {
$dbh = new PDO("mysql:host=localhost;dbname=adm-new", 'root', '');
} catch (PDOException $dbe) {
echo $dbe->getMessage();
}
return $dbh;
}
$conn = conectar();
function z_menu_todos($conn) {
$z_menu = "SELECT * FROM z_menu ORDER BY posicao ASC";
return $conn->prepare($z_menu);
}
However, it might be a good idea to create a separate class for managing your database connection and other stuff purely related to database and another class for executing SQL queries against your menu table.

undefined method PDO lastInsertId

I have an insert query, and I want to get the ID from the table. I have been searching, and I found lastInsertId() for PDO. When I want to use it, I get PHP errors.
This is my code:
$db = new database();
$naam = $db->quoteQuery($_POST['naam']);
$barcode = $db->quoteQuery($_POST['barcode']);
$sql = "INSERT INTO products(name, barcode) VALUES (".$name.",".$barcode.")";
$results = $db->executeQuery($sql);
$lastid = $results->lastInsertId();
But this gives an error, this one:
Fatal error: Call to undefined method PDOStatement::lastInsertId() in /home/onlineweuh/domains/onlinewebapps.nl/public_html/vsb/admin/add-product.class.php on line 297
My database class:
class database
{
private $handleDB;
public function __construct()
{
$host = ;
$user = ;
$database = ;
$password = ;
try
{
$this->handleDB = new PDO('mysql:host='.$host.';dbname='.$database, $user, $password);
}
catch (PDOException $e)
{
print_r($e);
}
$this->handleDB->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
}
I hope someone can help me solve it, I want the ID which is given at the insert Query.
You get the lastinsertid from the PDO object and not your results object.
Try $db->lastInsertId()
edit below.
Your database class is encapsulating your handleDB / PDO object. Since the handleDB variable is private, you cannot access this outside your class. You would need to either make it public like so;
class database
{
public $handleDB;
public function __construct()
{
$host = 'removed';
$user = 'removed';
$database = 'removed';
$password = 'removed';
try
{
$this->handleDB = new PDO('mysql:host='.$host.';dbname='.$database, $user, $password);
}
catch (PDOException $e)
{
print_r($e);
}
$this->handleDB->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
}
}
Now you can call $db->handleDB->lastInsertId();
Or you could expose the handleDB->lastInsertId() as a function like:
class database
{
private $handleDB;
public function __construct()
{
$host = 'remove';
$user = 'removed';
$database = 'removed';
$password = 'removed';
try
{
$this->handleDB = new PDO('mysql:host='.$host.';dbname='.$database, $user, $password);
}
catch (PDOException $e)
{
print_r($e);
}
$this->handleDB->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
}
public function lastInsertId(){
return $this->handleDB->lastInsertId();
}
}
You would call using $db->lastInsertId();
lastInsertId is a method of PDO, not PDOStatement. Therefore:
$db->lastInsertId();
your database class needs to be a subclass of PDO by extending PDO
class database extends PDO
that way all the methods in PDO are available to your subclass.

Categories