php oop, pdo and ajax instance issue

I'm using php oop with connection pdo. I need help how to call function from class via ajax

For example, let say that I want to call printBooks by ajax

  1. class - entity book:

    class Book{
        private $id;
        public function setID();
        public function getID();
        public function setName();
        public function getName();
    }
    
  2. class - controller books:

    class book_controller{
        private  $books;
        private  $conn;
        public function __construct()
        {
            $database = new Database();
            $db = $database->dbConnection(); 
            $this->conn = $db;
        }
        public function getAllBooks(){
           $stmt = $conn->query("SELECT * FROM books");
           $stmt->execute();
           while($row = $stmt->fetch(PDO::FETCH_ASSOC)){
              $b = new book();
              $b->setID($row['id']);
              $b->setName($row['name']);
              $this->books[] = $b;
            }
        }
        public function printBooks(){
          for($i=0; $i<sizeof($this->books);$i++){
            echo $this->books[$i]->getName();
        }
        }
    
  3. index file

        <?php
              $bo = new book_controller();
              echo "<button id='callToprintBooks'>";
        ?>
    
  4. ajax call

        $.ajax({ 
                url:book_controller.php, 
                type: 'POST', 
                success : function( data ) { 
                    $('#DescModal').html(data); 
                    $('#DescModal').modal("show"); 
                } 
             });
    

For simplicity, I want to call printBooks function on button click by ajax from the index.php file after I make the new book_controller instance. I tried to save the var "$bo" in session but I got an error

You cannot serialize or unserialize PDO instances in

I tried to use $_GET call but I don't want to create a new instance (cause then I'll need to build the book array again)

I hope I've been able to explain myself so that you can help me

2 answers

  • answered 2018-06-25 05:25 dakis

    At first, a general overview of the steps to follow (roughly) for processing the HTTP requests:

    • Parse each request through index.php. The file index.php is the entry point of your MVC application.
    • Read the URI path from the REQUEST_URI value of the $_SERVER global variable and the HTTP method from REQUEST_METHOD.
    • Save them together with the values of the other global variables ($_POST, $_GET, etc) into a Request object (e.g. an instance of a class named, for example, Request).
    • Get a router like FastRoute and build your routes list - read the docs please. Each route is defined as an object with a HTTP method, a pattern, and a handler (e.g. a controller method, e.g. an action) as properties.
    • Compare the request components (the HTTP method and the URI path from the Request object) with the components of each route object (the HTTP method and the pattern properties) in the routes list.
    • If a match is found, e.g. if the request components are the same as the ones of a route, then create a controller instance and call its action, e.g. the corresponding route handler.
    • Pass the Request object as argument, in order to be able to read the POST, GET, etc values from it.
    • The controller action loads a corresponding template file, renders its content, and returns it.
    • Print the returned content (with an echo [here the content string];).

    Step 1:

    Let's now say that your url is http://localhost/get-books and the HTTP method is GET. And that, in the routes list of the router, you have added a route object with the following properties:

    • HTTP method: GET,
    • pattern: /get-books,
    • route handler: book_controller::getAllBooks.

    After processing all the steps above, the printed content will look something like this:

    index.php:

    <!DOCTYPE html>
    <html>
        <head>
            <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
            <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=yes" />
            <meta charset="UTF-8" />
            <!-- The above 3 meta tags must come first in the head -->
    
            <title>Demo</title>
    
            <script src="https://code.jquery.com/jquery-3.2.1.min.js" type="text/javascript"></script>
    
            <script type="text/javascript">
                $(document).ready(function () {
                    $('#printBooksButton').on('click', function () {
                        $.ajax({
                            /*
                             * This value ('/print-books') corresponds to a
                             * route definition in the predefined routes list.
                             */
                            url: '/print-books',
                            /*
                             * This value ('POST') corresponds to the HTTP method
                             * of a route definition in the predefined routes list.
                             */
                            method: 'POST',
                            dataType: 'html',
                            data: {},
                            success: function (response, textStatus, jqXHR) {
                                $('#books').html(response);
                            },
                            error: function (jqXHR, textStatus, errorThrown) {
                                alert('Error. Sorry!');
                                //...
                            },
                            complete: function (jqXHR, textStatus) {
                                //...
                            }
                        });
                    });
                });
            </script>
        </head>
        <body>
    
            <form action="" method="post">
                <button type="button" id="printBooksButton" name="printBooksButton" value="printBooks">
                    Print all books
                </button>
            </form>
    
            <div id="books">
                Here comes the books list.
            </div>
    
        </body>
    </html>
    

    Step 2:

    In the moment of clicking the button printBooksButton, the ajax request is executed and parsed throw the index.php. But this time the request has the HTTP method POST and the url is http://localhost/print-books. Going from the fact that you've already defined another route in your routes list with the following properties:

    • HTTP method: POST,
    • pattern: /print-books,
    • route handler: book_controller::printBooks,

    and that the general steps in the index.php are processed, the action printBooks of the book_controller is executed. But the returned content will not represent a whole webpage structure. Instead it will only be the html code for representing the books list. This html code is "received" by the success callback of the ajax request as the response argument. Therefore, at last, it's filled into the div with the id books.

    <ul class="books-list">
        <li>Book 1</li>
        <li>Book 2</li>
        <li>Book 3</li>
        <li>Book 4</li>
    </ul>
    

    EDIT 1:

    Note: In my answer I supposed earlier that you are implementing an MVC application. Later, after your question edits, I realized that it may not be 100% the case. But it was too late (regarding the late hour) for me to change anything. So, please answer me to a question: Are all HTTP requests to your application redirected to only one page, e.g. to index.php? I will wait an answer and, for now, I will maintain my MVC supposition for the further explanations.

    The FastRoute library has the role of a so called router. It essentially does two things:

    1. It holds a collection of routes - defined by the user.
    2. It provides a routing mechanism. E.g. it dispatches a URI. E.g. it matches the components of the request (e.g. the HTTP method and the URI path) against the components of each route (e.g. the route's HTTP method and pattern), in order to JUST extract the route handler (which can be a string like "controller::action", or a closure, etc) and the parameters list (e.g. a map of placeholder names, as defined in the route's pattern, to their values, as given by the user in the URI).

    So, the router does NOT (and should not) call any controller action, but only extracts it from the handler property of a matched route object. Based on this controller action definition you, the dev, have to instantiate the controller, call the action (by also passing the values from the parameters list as action arguments) and print the results of this call to the user.

    All these things happen in one file, be it index.php. So, your controller class is instantiated in index.php, AFTER the router dispatches the URI and returns the controller name, the action name and the parameters list.

    In index.php happens also the creation of a database connection (e.g. of a PDO instance in your case), which should be passed as argument to the controller constructor.

  • answered 2018-06-25 05:25 themahabbat

    Create a file like index.php which you call new book_controller class' getAllBooks() method. But in getAllBooks() method at the end of function return $this->books[] as JSON. Then you can call this php file from AJAX and return data as JSON. You can append to html with jQuery's each() function