-1

The problem here is that the viewauthor.php considered the $conn as an undefined variable. It also gives me an error that states mysqli_query() expects parameter 1 to be mysqli, null given in in the $results line. How can I make the viewauthor.php access the $conn in the dbconnect.php file?

this is the code in db.connect.php

   <?php
    class dbconn {
    public function dbcon() {
        global $conn;
        $conn = new mysqli('localhost','root','','bookinventory') or die 
        ('Error connecting to mysql' .mysqli_error());
        return $conn;

    }
}
?>

this is the code in viewauthor.php

    <?php
    require_once 'dbconnect.php';

    class author {
     $con = new dbconn();
     $conn = $con->dbcon();

    public function viewAuthor() {  
    $query = ("SELECT * FROM author");
    $results = mysqli_query($conn,$query);
    $authors = array();

            while($author = mysqli_fetch_object($results)) {
            $authors[] = $author;
      }
            return $authors;
    }
 }
 ?>
loke
  • 1
  • 2
  • Please read https://stackoverflow.com/questions/845021/how-to-get-useful-error-messages-in-php on how to print all error messages. There are some errors which aren't shown by PHP. – Progman Jul 01 '18 at 18:04
  • 1
    That `author` class is invalid PHP code… – deceze Jul 01 '18 at 18:25

1 Answers1

2

Found problems:

  • See $con = new dbconn(): To define properties of a class use one of the keywords public, protected, or private, static, constant, etc, followed by a normal variable declaration. See Properties.
  • See $con = new dbconn(): You can not create an object as part of a property definition. The property value must be a constant expression, not (for example) a variable, a property, or a function call. See Properties and Class Constants.
  • See $results = mysqli_query($conn, $query);: Why are you receiving the error "mysqli_query() expects parameter 1 to be mysqli, null given in ..."? Because you're trying to reference $conn, but it is neither defined as parameter in the definition of viewAuthormethod - like viewAuthor($conn) {...}, nor correctly defined as a class property - if it was you'd have to reference it like this: $results = mysqli_query($this->conn, $query);.

Now I'll try to give you two correct alternatives. But only the second one would be the recommended one. And I'll try to keep my explanations simple. Mind my naming and coding conventions, including the changed table name, the page names, the require statement for the connection page, etc. And don't forget to change the database credentials in the page connection.php with yours.

But, first, some recommendations:

  • Don't use a class for connecting to the database. Just create an including file with the proper connectivity code (see connection.php).
  • Create a constructor for each class needing to access the database and define a parameter for the connection object to be passed as argument. This passing step is called dependency injection.
  • Use require instead of require_once when you're including the connection.php.
  • Use the object oriented mysqli, not the procedural one. To each mysqli procedural function described on php.net there is an object oriented styled one too.
  • Important: Use prepared statements instead of just directly querying the database by using mysqli_query. See this too.
  • Important: Read this and this for properly applying error handling. E.g. to elegantly and safely get rid of die(...), mysqli_error(), etc.
  • Important: Implement an autoloader, or, a lot better, use the Composer library. Implement namespaces too. Read PSR-1, PSR-2, PSR-4 and, in time, the other recommendations from PHP-FIG as well.

Alternative 1:

In the codes bellow it becomes obvious, why this alternative is not really a good one:

  • An object of type Author - which should actually be the representation of only one table row - is used to fetch a collection of authors. Which are even fetched as a collection of objects of type stdClass. Bad.
  • An object of type Author is responsible for querying a database. Why should an object of type Author have something to do with a database, actually? Bad.

connection.php:

<?php

// Db configs.
define('HOST', 'localhost');
define('PORT', 3306);
define('DATABASE', 'tests');
define('USERNAME', 'root');
define('PASSWORD', 'root');

/*
 * Enable internal report functions. This enables the exception handling,
 * e.g. mysqli will not throw PHP warnings anymore, but mysqli exceptions
 * (mysqli_sql_exception).
 *
 * MYSQLI_REPORT_ERROR: Report errors from mysqli function calls.
 * MYSQLI_REPORT_STRICT: Throw a mysqli_sql_exception for errors instead of warnings.
 *
 * @link http://php.net/manual/en/class.mysqli-driver.php
 * @link http://php.net/manual/en/mysqli-driver.report-mode.php
 * @link http://php.net/manual/en/mysqli.constants.php
 */
$mysqliDriver = new mysqli_driver();
$mysqliDriver->report_mode = (MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);

/*
 * Create a new db connection.
 *
 * @see http://php.net/manual/en/mysqli.construct.php
 */
$connection = new mysqli(HOST, USERNAME, PASSWORD, DATABASE, PORT);

Author.php:

<?php

class Author {

    /**
     * Database connection.
     *
     * @var mysqli
     */
    private $connection;

    /**
     *
     * @param mysqli $connection Database connection.
     */
    public function __construct(mysqli $connection) {
        $this->connection = $connection;
    }

    /**
     * Get all authors.
     *
     * @return stdClass[] The authors list.
     */
    public function getAllAuthors() {
        /*
         * The SQL statement to be prepared.
         *
         * @link http://php.net/manual/en/mysqli.prepare.php
         */
        $sql = 'SELECT * FROM authors';

        /*
         * Prepare the SQL statement for execution.
         *
         * @link http://php.net/manual/en/mysqli.prepare.php
         */
        $statement = $this->connection->prepare($sql);

        /*
         * Execute the prepared SQL statement.
         * When executed any parameter markers which exist will
         * automatically be replaced with the appropriate data.
         *
         * @link http://php.net/manual/en/mysqli-stmt.execute.php
         */
        $statement->execute();

        /*
         * Get the result set from the prepared statement.
         *
         * NOTA BENE:
         * Available only with mysqlnd ("MySQL Native Driver")! If this
         * is not installed, then uncomment "extension=php_mysqli_mysqlnd.dll" in
         * PHP config file (php.ini) and restart web server (I assume Apache) and
         * mysql service. Or use the following functions instead:
         * mysqli_stmt::store_result + mysqli_stmt::bind_result + mysqli_stmt::fetch.
         *
         * @link http://php.net/manual/en/mysqli-stmt.get-result.php
         * @link https://stackoverflow.com/questions/8321096/call-to-undefined-method-mysqli-stmtget-result
         */
        $result = $statement->get_result();

        // Fetch the data into a stdClass[] array.
        $rows = [];
        while ($row = $result->fetch_object()) {
            $rows[] = $row;
        }

        return $rows;
    }

    /**
     * Get an author by id.
     *
     * @param int $authorId Author id.
     * @return stdClass The author.
     */
    public function getAuthorById(int $authorId) {
        /*
         * The SQL statement to be prepared. Notice the so-called markers,
         * e.g. the "?" signs. They will be replaced later with the
         * corresponding values when using mysqli_stmt::bind_param.
         *
         * @link http://php.net/manual/en/mysqli.prepare.php
         */
        $sql = 'SELECT *
                FROM authors
                WHERE id = ?
                LIMIT 1';

        $statement = $this->connection->prepare($sql);

        /*
         * Bind variables for the parameter markers (?) in the
         * SQL statement that was passed to prepare(). The first
         * argument of bind_param() is a string that contains one
         * or more characters which specify the types for the
         * corresponding bind variables.
         *
         * @link http://php.net/manual/en/mysqli-stmt.bind-param.php
         */
        $statement->bind_param('i', $authorId);

        $statement->execute();
        $result = $statement->get_result();

        // Fetch the data into a stdClass object.
        $row = $result->fetch_object();

        return $row;
    }

}

index.php:

<?php

require 'connection.php';
require_once 'Author.php';

$author = new Author($connection);

/*
 * ================================
 * Example 1: Get all authors.
 * ================================
 */

// Get all authors.
$theAuthors = $author->getAllAuthors();

// Print the results.
echo '<b>Example 1: The whole authors list:</b>';
echo '<br/></br/>';
foreach ($theAuthors as $theAuthor) {
    echo $theAuthor->id . ' - ' . $theAuthor->first_name . ', ' . $theAuthor->last_name . '<br/>';
}

echo '<br/><hr/><br/>';

/*
 * ================================
 * Example 2: Get an author by id.
 * ================================
 */

// Get an author by id.
$theAuthor = $author->getAuthorById(2);

// Print the results.
echo '<b>Example 2: One selected author:</b>';
echo '<br/><br/>';
echo $theAuthor->id . ' - ' . $theAuthor->first_name . ', ' . $theAuthor->last_name . '<br/>';

Alternative 2:

Let's change the code above to make more semantical and structural sense. For this, think of an object of type Author as an entity whose only purpose is to hold the characteristics of an author and to manipulate them on demand. This type of objects are known as domain objects and are only responsible with the business logic. See this answer. So, an Author object should have nothing to do with a database, or with any other persistence layer (session, file system, etc). It should actually be completely unaware of the place and fashion in which its properties are fetched.

The responsibility of querying the database, fetching the author characteristics (e.g. the field values of a specific row in the authors table) and assigning them to an Author object should therefore be deferred to a so-called data mapper.

So, the code in your case would look like this:

connection.php:

The same as above.

Author.php:

<?php

class Author {

    /**
     * Author id.
     *
     * @var int
     */
    private $id;

    /**
     * First name.
     *
     * @var string
     */
    private $firstName;

    /**
     * Last name.
     *
     * @var string
     */
    private $lastName;

    /**
     * Get the name as 'John, Doe'.
     *
     * @return string The name.
     */
    public function getName() {
        return $this->firstName . ', ' . $this->lastName;
    }

    /**
     * Get the id.
     *
     * @return int
     */
    public function getId() {
        return $this->id;
    }

    /**
     * Set the id.
     *
     * @param int $id Id.
     * @return $this
     */
    public function setId($id) {
        $this->id = $id;
        return $this;
    }

    /**
     * Get the first name.
     *
     * @return string
     */
    public function getFirstName() {
        return $this->firstName;
    }

    /**
     * Set the first name.
     *
     * @param string $firstName First name.
     * @return $this
     */
    public function setFirstName($firstName) {
        $this->firstName = $firstName;
        return $this;
    }

    /**
     * Get the last name.
     *
     * @return string
     */
    public function getLastName() {
        return $this->lastName;
    }

    /**
     * Set the last name.
     *
     * @param string $lastName Last name.
     * @return $this
     */
    public function setLastName($lastName) {
        $this->lastName = $lastName;
        return $this;
    }

}

AuthorMapper.php:

<?php

require_once 'Author.php';

class AuthorMapper {

    /**
     * Database connecton.
     *
     * @var mysqli
     */
    private $connection;

    /**
     * Authors collection.
     *
     * @var Author[]
     */
    private $authorsCollection = [];

    /**
     *
     * @param mysqli $connection Database connection.
     */
    public function __construct(mysqli $connection) {
        $this->connection = $connection;
    }

    /**
     * Get all authors.
     *
     * @return array Authors list.
     */
    public function getAllAuthors() {
        $sql = 'SELECT * FROM authors';

        $statement = $this->connection->prepare($sql);
        $statement->execute();
        $result = $statement->get_result();

        // Fetch the data into a stdClass[] array.
        $rows = [];
        while ($row = $result->fetch_object()) {
            $rows[] = $row;
        }

        // Fill and return the authors collection.
        return $this->createAuthorsCollection($rows);
    }

    /**
     * Get an author by id.
     *
     * @param int $authorId Author id.
     * @return Author The author.
     */
    public function getAuthorById(int $authorId) {
        $sql = 'SELECT *
                FROM authors
                WHERE id = ?
                LIMIT 1';

        $statement = $this->connection->prepare($sql);
        $statement->bind_param('i', $authorId);
        $statement->execute();
        $result = $statement->get_result();

        // Fetch the data into a stdClass object.
        $row = $result->fetch_object();

        // Crete and return an Author object.
        return $this->createAuthor($row);
    }

    /**
     * Create an Author from the given stdClass object:
     *
     * - Create an Author object.
     * - Assign a property value to the Author object for each property of the given stdClass object.
     * - Return the Author object.
     *
     * @param stdClass $row The row object.
     * @return Author The author.
     */
    public function createAuthor(stdClass $row) {
        $author = new Author();

        $author
                ->setId($row->id)
                ->setFirstName($row->first_name)
                ->setLastName($row->last_name)
        ;

        return $author;
    }

    /**
     * Create an Author[] list from the given stdClass[] list:
     *
     * - Iterate through the given stdClass[] list.
     * - Create an Author object for each list item.
     * - Assign a property value to the Author object for each property of the given stdClass object.
     * - Push the Author object to the authors collection.
     * - Return the content of the collection.
     *
     * @param array $rows Rows list as a stdClass[] list.
     * @return Author[] The authors list as an Author[] list.
     */
    public function createAuthorsCollection(array $rows = []) {
        foreach ($rows as $row) {
            $this->authorsCollection[] = $this->createAuthor($row);
        }

        return $this->authorsCollection;
    }

}

index.php:

<?php

require 'connection.php';
require_once 'AuthorMapper.php';

// Create an author data mapper.
$authorMapper = new AuthorMapper($connection);

/*
 * ================================
 * Example 1: Get all authors.
 * ================================
 */

// Get all authors.
$authors = $authorMapper->getAllAuthors();

// Print the results.
echo '<b>Example 1: The whole authors list:</b>';
echo '<br/></br/>';
foreach ($authors as $author) {
    echo $author->getId() . ' - ' . $author->getName() . '<br/>';
}

echo '<br/><hr/><br/>';

/*
 * ================================
 * Example 2: Get an author by id.
 * ================================
 */

// Get an author by id.
$author = $authorMapper->getAuthorById(2);

// Print the results.
echo '<b>Example 2: One selected author:</b>';
echo '<br/><br/>';
echo $author->getId() . ' - ' . $author->getName();

As you see, an AuthorMapper queries the database and fetches the table rows into a collection of objects of type stdClass. Then it maps these objects to corresponding objects of type Author, whose properties are printed, or used by certaing methods (like getName()) in order to achieve certain results.

The output of each alternative:

The output

Used data:

CREATE TABLE `authors` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `first_name` varchar(100) DEFAULT NULL,
  `last_name` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `authors` (`id`, `first_name`, `last_name`)
VALUES
    (1,'Johny','John'),
    (2,'Samantha','Sam'),
    (3,'Maria','Mar');

List of resources:

dakis
  • 225
  • 1
  • 6
  • 32
  • Wow, this is a well written explanation. I'm gonna have to try this one. Thank you so much – loke Jul 05 '18 at 05:39
  • @loke You are welcome. I just added a _"List of resources"_ too (at the end of my answer). Important: OOP and the SOLID principles. Optional: MVC. – dakis Jul 05 '18 at 10:59