简体   繁体   中英

PHP Best Practices for querying a group of class objects with summarized data

This is a pretty broad question but I'm hoping I could get a bit of guidance.

I'm building a reporting system for my company. I have classes for Customer, Order, Invoice, and Item. They work great for individual objects. However, this is a reporting system and I will need to query and summarize these objects in a variety of ways.

For example, a single Order object will have a total dollar value for that one order. But if I'm generating a report for the month, I want to summarize a group of orders that match whatever parameters I pass my query (such as a date range and/or customer number).

This typically involves additional work such as accumulating running totals for month to date or year to date comparisons. This is where things get a little fuzzy for me. Does that logic belong in the Order class? If not, then where? Note I will also have to do the same for my Invoice class.

Here's a simplified version of what I'm doing now with my Order class. I use one function (getOrders) that returns an array of Order objects, and another function (getOrderGroup) that returns an array of grouped results (not objects).

It's the getOrdersGroup() function I'm most unclear about. If there is a better practice for reporting on grouped results, along with counts, sums and running totals, please point me down the better path!

<?php
class Order {
    public $number;
    public $customer;
    public $date_ordered;
    public $date_shipped;
    public $salesperson;
    public $total;

    public function __construct(array $data = array()) {
        $this->number = $data['number'];
        $this->customer = $data['customer'];
        $this->date_ordered = $data['date_ordered'];
        $this->date_shipped = $data['date_shipped'];
        $this->salesperson = $data['salesperson'];
        $this->total = $data['total'];      
    }

    /**
     * Returns an array of order objects
     */         
    public static function getOrders(array $options = array()) {
        $orders = array();

        // Build query to return one or more orders
        // $options parameter used to form SQL query
        // ......

        $result = mysql_query($query);
        while ($row = mysql_fetch_array($result, MYSQL_ASSOC)) {
            $order = new Order($row);
            $orders[] = $order;
        }
        return $orders;
    }

    /**
     * Returns an array of grouped order results (not objects)
     */         
    public static function getOrdersGroup(array $options = array()) {
        $group = array();

        // Build query that contains COUNT() and SUM() group by functions
        // ......

        $running_total = 0;
        $result = mysql_query($query);
        while ($row = mysql_fetch_array($result, MYSQL_ASSOC)) {

            // Accumulate running total for the month
            $running_total += $row['sum_total'];

            // Build the group array with a listing of summarized data
            // Note: The order class is never actually instantiated here
            // Also, in this example we're grouping by date_ordered...
            // but in reality the result should be able to be grouped by a
            // dynamic field, such as by customer, or by salesperson,
            // or a more detailed breakdown with year, month, day and a running
            // total break at each level
            $group[] = array(
                "date_ordered" => $row["date_ordered"],
                "count_customers" => $row["count_customers"],
                "count_orders" => $row["count_orders"],
                "count_salespersons" => $row["count_salesperson"],
                "sum_total" => $row["sum_total"],
                "running_total" => $running_total);
        }
        return $group;
    }

    /**
     * Queries to get ordered items if drilling down to item level...
     */             
    public function getItems() {
        // blah
    }
}
?>

There are a number of tasks to be done and, yes, some of them are specific to each class. Especially when it comes to knowing which columns there are and how to treat them. But on the other hand there is the abstract logic of 'grouping something' and of building search patterns (and this includes of course also a range of date handling functions). These two can/should be placed in separate objects/functions which can be called from both classes, orders and invoices .

A similar thing goes for putting together the result arrays. Here we need to be able to adapt to all sorts of different grouping conditions. The column names are class specific but the general logic can be put in separate classes or functions.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM