1

What I am trying to do is write a "search" class that can search for a list of products and store them in an array.

I already have a "product" class that can be used to get the details of a specific product.

Here is my code:

class Product {

    public $name;
    public $price;
    public $description;

    public function getProductById ($id) {

        $sql = 'SELECT name, price, description FROM product WHERE id = ' . $id;

        $row = /* MySQL functions here to execute SQL statement and get a matching row */

        $this->name = $row['name'];
        $this->price = $row['price'];
        $this->description = $row['description'];
        return TRUE;
    }
}

class Search {

    public $results;
    public $totalResults;

    function __construct() {
        $this->results = array ();
        $this->totalResults = 0;
    }

    public function doSearch ($name) {

        $sql = 'SELECT id FROM product WHERE name LIKE "%' . $name . '%"';

        $rows = /* MySQL functions here to execute SQL statement and get a list of matching product ID's */

        foreach ($rows as $row) {
            $product = new Product;
            $product->getProductById ($row['productid']);
            $this->results[] = $product;
        }
        return TRUE;
    }
}

$search = new Search;
$search->doSearch ('Fresh Flowers');

The problem with the above is that every matching record in the doSearch method will execute a query in the getProductById method. If there are 100 matching products, there will be 100 individual queries carried out in the Product class.

However, if I get the products directly in the doSearch method using a single query, this will then bypass the Product class altogether.

When a "product" is an object, what's the most appropriate way to write a search class that can return a list of "product" objects without the overhead of what I'm doing above?

3
  • read up on what a join is in sql. Commented Nov 24, 2012 at 19:02
  • @rambocoder JOIN is of little to no use here. Commented Nov 24, 2012 at 19:04
  • oh, i didnt notice the same table was being used in both queries. Commented Nov 24, 2012 at 19:10

4 Answers 4

1

Add a constructor to the Product class which takes name, price and description as parameters (or an assoziative array), to populate the object with the necessary values, decoupled of the database query.

Within doSearch, you can then create a SELECT which not only gets the ID but all relevant fields from the products table, and create the populated product objects immediately with new Product($name, $price, $description) or new Product($row), without calling getProductById for each product.

Sign up to request clarification or add additional context in comments.

Comments

0

Create a class that populates instances of Product with data from the database.

The class can then create one or multiple instances of the Product class depending on how much data is being fetched.

Conclusion: Extract the getProductById from your Product class and put it somewhere else. It is a specialised method that only populates one instance.

Comments

0

Just grab what you want in the first place.

public function doSearch ($name) {

        $sql = 'SELECT id, name, price, description FROM product 
           WHERE name LIKE "%' . $name . '%"';

// now just return the array    

}

Or use PDO to return result sets as objects.

$result->setFetchMode(PDO::FETCH_INTO, new animals);

as discussed here: How can I simply return objects in PDO?

Comments

0

Your Product class shouldn't know anything about a database. It should contain the values representing a product, nothing more. Extract all stuff dealing with the database out of this class.

Searching for products is one way to access a list of products. Your next class should be a list of products then. Only when accessing one single product you'd not have to deal with a list, but this is probably less often than you think.

Ok, you have the product and the list of products, you now can go one step forward and add database access. You need a class that deals with giving you both one product (when searching by id) and lists of products (when searching by some text or other stuff). Only this class allows you to deal with the queries needed to access the database. The result sets of each query may directly be used inside the "list of products" class, probably by inheriting all the stuff that is defined in the general "list of products" class and adding dealing with database results.

So in the end you'll end up having:

Product -> ListOfProducts -> ProductDatabase -> DatabaseAccessLayer

1 Comment

I marked Wolfgang Stengel's answer as the correct one as it gave the most direct answer to the example given. I tried what you are suggesting and couldn't quite get my head around it, but that's probably down to my level of expertise. I see where you're coming from though and would like to experiment with your idea further.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.