Assign resource to a class property from trait method - php

I've decided to write a trait that will be responsable to connect and disconnect from ftp using the php built in functions. I want to login, connect and disconnect to the host by using trait methods.
I need to use $this->conn from inside the instance of the class to use the ftp functions. The variable will hold the ftp connection. I want to assign to $this->conn the value returned from the connect trait method. I want to know if there is a way to call it inside the class.
I'm unable to get the $this variable inside the class that will use the trait. How can I access it inside the class?
<?php
trait ConnectionHelper
{
public function connect(string $host, string $user, string $pwd)
{
$this->conn = ftp_connect($host);
if ($this->conn && ftp_login($this->conn, $user, $pwd)) {
ftp_pasv($this->conn, true);
echo "Connected to: $host !";
}
return $this->conn;
}
public function disconnect()
{
return ftp_close($this->conn);
}
}
class FTPManager
{
use ConnectionHelper;
private $url;
private $user;
private $password;
/* Upload */
public function upload(array $inputFile, string $dir = null)
{
if (!is_null($dir)) {
ftp_chdir($this->conn, "/$dir/");
}
$upload = ftp_put($this->conn, $inputFile['name'], $inputFile['tmp_name'], FTP_BINARY);
if ($upload) {
echo 'File uploaded!';
}
}
}
?>
NB: Can be a good solution to call the connect method of the trait inside the class constructor?
<?php
class myclass{
use mytrait;
public function __construct(){
$this->conn = $this->connect($host, $user, $pass);
}
}
?>

Traits can be used to do what you want, but it would be better to actually use traits for what they can do: assign and read from class properties.
In the trait, when you assign to $this->conn:
$this->conn = ftp_connect($host);
The property is defined for the class instances that use the trait. As such, no need to use $this->conn = $this->connect() because $this->conn will already contain the connection resource.
So in the constructor, simply call the connect method:
public function __construct()
{
$this->connect($host, $user, $pass);
// $this->conn will now contain the connection made in connect()
}
No need to return $this->conn; in the trait. To make sure you free your resource, call disconnect() from FTPManager's destructor:
public function __destruct()
{
$this->disconnect();
}
That being said, it is a rather quirky way of managing this. Having to manually call connect() in every class that use the trait is error prone, and might lead to maintainability issue (every one of those class need to be aware of ftp credentials, for instance, tightly coupling them to configuration).
Thinking about it, these class instances are not dependant upon ftp credentials, they are dependant upon an active ftp connection. As such, it's way cleaner to actually ask for the ftp connection in the class's constructor, and not bother about calling connect() and disconnect() in every class that actually needs the ftp connection.
We could think of a connection wrapper class that would greatly simplify things here:
class FTPWrapper {
private $connection;
public function __construct(string $host, string $user, string $pwd)
{
$this->connect($host, $user, $pwd);
}
public function __destruct()
{
$this->disconnect();
}
public function getConnection()
{
return $this->connection;
}
private function connect(string $host, string $user, string $pwd): void
{
$this->connection = ftp_connect($host);
if ($this->connection && ftp_login($this->connection, $user, $pwd)) {
ftp_pasv($this->connection, true);
echo "Connected to: $host !";
}
}
private function disconnect(): void
{
ftp_close($this->conn);
}
}
Then, inject that wrapper into whatever class that needs to use it.

Related

How to extend PDO class with a new method and use that method in another class?

I once used to have my database connection in a file and included it on the pages that I needed it. Inside of this file, I also extended the PDO class with a new method, run(), which allows me to write shorthand PDO queries and worked fine:
class MyPDO extends PDO {
public function run($sql, $bind = NULL) {
$stmt = $this->prepare($sql);
$stmt->execute($bind);
return $stmt;
}
}
$conn = new MyPDO("mysql:charset=utf8;host=$host;dbname=$name", $user, $pass);
I'm now trying to neaten up my files and the code within them, by using classes. So, this database connection file became two classes:
class MyPDO extends PDO {
public function run($sql, $bind = NULL) {
$stmt = $this->prepare($sql);
$stmt->execute($bind);
return $stmt;
}
}
class Connection {
private $_config = NULL;
public $conn = NULL;
public $error = NULL;
public function __construct(array $config) {
$this->_config = $config;
$this->getPDOConnection();
}
private function getPDOConnection() {
if ($this->conn == NULL) {
$this->conn = new MyPDO("mysql:charset=utf8; host=".$this->_config['host']."; dbname=".$this->_config['name']."", $this->_config['user'], $this->_config['pass']);
[...]
}
}
[...]
}
At this point in time, I'm not using an autoload function to load the classes. There are only two classes needed for this particular file, so I'm requiring them manually. I'm also led to believe that including the connection class manually, allows the PDO class to be extended with MyPDO.
require API_ROOT . 'core/database/connection.class.php';
require API_ROOT . 'core/users/user.class.php';
I've tested the connection and it has indeed connected.
The problem I'm having, is using the new MyPDO method named run() inside of another class, in this case user.class.
Inside of user.class, I'm simply trying to authenticate a user and therefore need to use the run() method.
I call the user class like this:
$db = new Connection($config['database']);
$user = new User($db, $config);
And inside of the user.class, I want to use run() and do so by calling $this->db->run:
class User {
private $db = NULL;
private $config = NULL;
public function __construct($db = NULL, $config = NULL) {
$this->db = $db;
$this->config = $config;
}
public function login($email = '', $password = '', $remember_me = '') {
$user_profile = $this->db->run(" <--------------
[...]
", [$email])->fetch(PDO::FETCH_ASSOC);
}
}
But I receive the following error when I run this:
Uncaught Error: Call to undefined method Connection::run()
I understand what the error means, that there is no method called run() inside of my connection class but why does it think that method is in there? What am I doing wrong here?
#Quasimodo'sclone is correct, you need to fetch it from the conn variable as they demonstrated. If it's not working, you are doing something wrong on the implementation elsewhere because run() is a method of conn because conn is the class MyPDO which defines the run() method:
$this->db equals class Connection which creates instance of MyPDO in the __construct() and assigns it to $this->conn in the getPDOConnection() method – therefore $this->db->conn->run() is what you are looking for.
Your getPDOConnection() should maybe be renamed to setPDOConnection() then have the getPDOConnection() retrieve $this->conn:
public function getPDOConnection()
{
return $this->conn;
}
Then your User class would actually use:
$this->db->getPDOConnection()->run(...etc);
It would make it a little clearer.

php prevent database connection in each request

I have a method in connection class which returns a dbconnection instance so I can make query with that.
class Connection
{
public $dbh; // handle of the db connexion
private static $instance;
public $resultBool;
public $connectedDbName;
public $resultString;
public $directed;
public static $deviceid;
private function __construct()
{
$this->dbh = new PDO('mysql:host=localhost;dbname=webfilter;port=3306;connect_timeout=15', 'root', 'company');
$this->dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->dbh->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
$this->directed = false;
$this->resultBool = true;
}
public static function getConnection()
{
if (!isset(self::$instance))
{
$object = __CLASS__;
self::$instance = new $object;
}
...
return self::$instance;
}
At first request, there is a connection required so I step into this connection function that's ok. but why I need to make connection again even there is so obvious I will use same connection.. it seems cause performance issue..
here is my function which makes real job. I use dbObject to make queries on db, but for each time I need to connection instance(getconnection) to do it.
$dbObject = Connection::getConnection();
$request = $dbObject->dbh->prepare($sql);
$request->bindParam(':username', $username, PDO::PARAM_STR);
is it possible to save existing connection for next request of same users or another way to pass connection operation
You already use the singleton pattern. This is only working for multiple connections in one request. For every request this class creates a new object of the connection class. A PDO instance can't be serialized or unserialized or saved on a session. I think there is no way at the moment to do this.

Classes using mysqli

I am building an API in PHP and I have a question. I'm using classes, and some of these classes need to access my database. However, I don't want to define variables for the database in every single class in order to open it, or have to send my mysqli object as a parameter of every single class constructor.
What would be the best way to go about this? Do I define a global variable of some kind?
A classic solution would be as follows
Create an instance of dbatabase handler class, either raw mysqli (worse) or better abstraction class (way better)
In the constructor of your application class take this db class instance as a parameter and assign it to a local variable
Use this variable with your class.
A quick example:
class Foo()
{
protected $db;
function __construct($db);
{
$this->db = $db;
}
function getBar($id)
{
return $this->db->getOne("SELECT * FROM bar WHERE id=?i", $id);
}
}
$db = new safeMysql();
$foo = new Foo($db);
$bar = $foo->getBar($_GET['id']);
How about using a static classes?
class mysqli_wrapper {
private static $db = null;
public static function open() {
GLOBAL $opts; // this can be global or setup in other ways
if (!self::$db) {
self::close();
self::$db = null;
}
self::$db = #mysqli_connect('p:'.$opts['hn'], $opts['un'], $opts['pw'], $opts['db']);
return self::$db;
}
public static function query($qry) {
return mysqli_query ( self::$db, $qry );
}
public static function affected_rows() { return #mysqli_affected_rows(self::$db); }
public static function error() { return #mysqli_error(self::$db); }
public static function close() { #mysqli_close(self::$db); }
} // end mysqli_wrapper
mysqli_wrapper::open(); // Here's how to call it
In a system I maintain my app needs to access its own MySQL db, as well as remote Oracle and SQL Server databases, and I use a trait for it. Here's a simplification of my code, just using MySQL:
dbaccess.php
trait DatabaseAccess {
protected $db;
private $host = 'host', $dbName = 'db', $username = 'username', $password = 'pword';
public function connectToMysql() {
$this->db= new mysqli(......);
}
}
then in myclass.php
require 'dbaccess.php';
class MyClass {
use DatabaseAccess;
//class code.....
}
All elements of DatabaseAccess will be available as if you hand-typed them in MyClass.
Note: if you're using PHP < 5.4, then this solution won't be possible.

Enforce Method Call Required by Object

I created an ssh2 wrapper. I have read that a constructor should not fail, so the ssh2 connection is not done in the wrapper, but by a method connect(). My question is: how do I make sure that connect() is called? I also really only need it to be called once.
class uploader {
private $user; private $pass; private $host;
private $ssh = null; private $sftp = null;
public function __construct($host, $user, $pass) {
$this->host = $host; $this->user = $user; $this->pass = $pass;
}
public function connect() {
if ($this->ssh === null) {
$this->ssh = ssh2_connect($this->host);
ssh2_auth_password($this->ssh, $this->user, $this->pass);
$this->sftp = ssh2_sftp($this->ssh);
}
}
}
What is the best way to ensure that connect() is called? Should the application call it?
$ssh = new uploader('host', 'user', 'pass');
$ssh->connect();
Or in the class methods?
...
public function upload($source, $dest, $filename) {
$this->connect();
...
}
public function delete($file) {
$this->connect();
...
}
Neither of these seems ideal.
I also thought about making a static method that would wrap the constructor and connect, but then the constructor would have to be private and I have also read that static methods are undesirable (mostly just for unit testing).
I have also read that static methods are undesirable (mostly just for unit testing).
Static methods are undesirable for some things, but factory methods isn't one of them. They make perfect sense there and do not impact unit testing. So, go ahead and make a static factory method.
The easiest way is to call connect() in your constructor and be sure to make a destructor function to disconnect your connection.

PHP: Utilizing singleton pattern correctly?

I've trying to learn PHP OOP and have made some research on how to make a global database class to use around in my project. From what I've seen the most appropriate pattern available is a singleton which would ensure that only one database connection are present at all times. However as this is my first time working with the Singleton pattern, I am not sure that I have made it right.
Is this a proper singleton? Will this code ensure one database connection only? Is there any way I can test this? (Learn a man to fish and he will have food for the rest of his life...)
I am using redbean as my ORM and here's how I set it up plainly:
require_once PLUGINPATH.'rb.php';
$redbean= R::setup("mysql:host=192.168.1.1;dbname=myDatabase",'username','password');
I've made the following script based upon this source, as my own singleton Database class;
class database {
private $connection = null;
private function __construct(){
require_once PLUGINPATH.'rb.php';
$this->connection = R::setup("mysql:host=192.168.1.1;dbname=myDatabase",'username','password');
}
public static function get() {
static $db = null;
if ( $db === null )
$db = new database();
return $db;
}
public function connection() {
return $this->connection;
}
}
Thanks!
The instance variable needs to be a static member of the class. I haven't tested this code, but it should work. Connection should probably be static too. With this code, you will have one instance of your database class, and one instance of the connection. It is possible to do this without connection being static, but making it static will ensure there is only one connection instance. I also changed the literal names of the class to php magic constants. This make your code more maintainable. If you change the name of your class down the road, you won't have to go and find all of the literal instances of the old class name in your code. This may seem like overkill now, but trust me, as you work on more and more complex projects, you will appreciate the value.
class database {
private static $connection = null;
private static $db;
private function __construct(){
require_once PLUGINPATH.'rb.php';
self::$connection = R::setup("mysql:host=192.168.1.1;dbname=myDatabase",'username','password');
}
public static function get() {
if ( !(self::$db instanceof __CLASS__) ) {
$klass = __CLASS__; // have to set this to a var, cant use the constant with "new"
self::$db = new $klass();
}
return self::$db;
}
public function connection() {
return self::$connection;
}
}
You're singleton is almost correct.
The private member (no pun intended) $connection needs to be static as well. You might go with the following too:
class database {
private static $instance = NULL;
protected $conn;
private function __construct() {
$this->conn = mysql_connect( ... );
}
public static function init() {
if (NULL !== self::$instance)
throw new SingletonException();
self::$instance = new database();
}
public static function get_handle() {
if (NULL === self::$instance)
; // error handling here
return self::$instance->conn;
}
}

Categories