2

I developed an invoice template designer as part of a project which can be used to design invoice templates. Once the invoice template is created its html is saved to the database ready to be used.

Now a user can create an invoice using the template but that is where my problem comes in. My invoice template is created with place holders and its a table. please check screenshot enter image description here

How can I replace the table cell values since it was created dynamically and there is no way I can access the table cells with a PHP loop. I really need ideas with possibly an example. This is my code:

if (!empty($_GET['invoice_id']) && $_GET['invoice_id']) {
    $invoice_id = $_GET['invoice_id'];
    $invoiceValues = getInvoice($invoice_id);       
    $invoiceItems = getInvoiceItems($invoice_id);   
}

$invoiceDate = date("d/M/Y, H:i:s", strtotime($invoiceValues['order_date']));

$template_name = getinvoicetemplatename();

$template = get_template($template_name[0]);

//replace template var with value
$token = array(
    '[Business_Name]'  => 'http://www.codexworld.com',
    '[Business_Address_1]' => 'CodexWorld',
    '[City]' => $userName,
    '[State]'=> $userEmail,
    '[Postal_Code]'  => 'http://www.codexworld.com',
    '[Business_Phone_Number]' => 'CodexWorld',
    '[Business_Email_Address]' => $userName,
    '[Client_Name]'=> $userEmail,
    '[Client_Address_line_1]'  => 'http://www.codexworld.com',
    '[Invoice_Number]' => 'CodexWorld',
    '[Date]' => $invoiceDate
);

foreach ($token as $key => $value){
    $output = str_replace($key, $value, $template[0]);
}

$i = 0; 
foreach ($invoiceItems as $invoiceItem) {
    $i++;

    $output = str_replace("[course_no_{$i}]", $invoiceItem["item_code"], $output);
    $output = str_replace("[product_{$i}]", $invoiceItem["item_name"], $output);
    $output = str_replace("[delegates_no_{$i}]", $invoiceItem["order_item_quantity"], $output);
    $output = str_replace("[price_{$i}]", $invoiceItem["order_item_price"], $output);
    $output = str_replace("[total_{$i}]", $invoiceItem["order_item_final_amount"], $output);
}

template html string

<div id="items-list">
    <table id="table-invoice" class="table table-bordered table-condensed  items-table" width="100%">
        <thead>
            <tr id="table_invoice_header">
                <th id="table_invoice_header1">Course No</th>
                <th id="table_invoice_header2">Course Name</th>
                <th id="table_invoice_header3">No of Delegates</th>
                <th id="table_invoice_header4" width="100">Price</th>
                <th id="table_invoice_header5" width="100">Total</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td class="total-rown">[course_no_0] </td>
                <td class="total-rown">[product_0] </td>
                <td class="total-rown">[delegates_no_0] </td>
                <td class="total-rown">[price_0] [curr]</td>
                <td class="total-rown">[total_0] [curr]</td>
            </tr>
            <tr>
                <td class="total-rown">[course_no_1] </td>
                <td class="total-rown">[product_1] </td>
                <td class="total-rown">[delegates_no_1] </td>
                <td class="total-rown">[price_1] [curr]</td>
                <td class="total-rown">[total_1] [curr]</td>
            </tr>
            <tr>
                <td class="total-rown">[course_no_2] </td>
                <td class="total-rown">[product_2] </td>
                <td class="total-rown">[delegates_no_2] </td>
                <td class="total-rown">[price_2] [curr]</td>
                <td class="total-rown">[total_2] [curr]</td>
            </tr>
            <tr>
                <td class="total-rown">[course_no_3] </td>
                <td class="total-rown">[product_3] </td>
                <td class="total-rown">[delegates_no_3] </td>
                <td class="total-rown">[price_3] [curr]</td>
                <td class="total-rown">[total_3] [curr]</td>
            </tr>
            <tr>
                <td class="total-rown">[course_no_4] </td>
                <td class="total-rown">[product_4] </td>
                <td class="total-rown">[delegates_no_4] </td>
                <td class="total-rown">[price_4] [curr]</td>
                <td class="total-rown">[total_4] [curr]</td>
            </tr>
        </tbody>
        <tfoot>
            <tr class="totals-row">
                <td colspan="3" class="wide-cell"></td>
                <td id="tableheader"><strong>Sub Total</strong></td>
                <td class="total-rown sub-total" coslpan="2">[sub_total] [curr]</td>    
            </tr>
            <tr class="totals-row">
                <td colspan="3" class="wide-cell"></td>
                <td class="total-rown" id="tableheader">Tax Rate</td>
                <td class="total-rown tax-rate" coslpan="2">[tax_rate]&nbsp;%</td>
            </tr>
            <tr class="totals-row">
                <td colspan="3" class="wide-cell"></td>
                <td class="total-rown">Tax Amount</td>
                <td class="total-rown tax-amount" coslpan="2">[tax_amount] [curr]</td>
            </tr>
            <tr class="totals-row">
                <td colspan="3" class="wide-cell"></td>
                <td id="tableheader1"><strong>Total</strong></td>
                <td class="total-rown invoice-total" coslpan="2">[total] [curr]</td>
            </tr>
        </tfoot>
    </table>
</div>
mickmackusa
  • 43,625
  • 12
  • 83
  • 136
Landry
  • 21
  • 2
  • 1
    _"and there is no way i can access the table cells with a php loop"_ - of course you can - use a DOM parser, then you can find/select/manipulate all the elements. – CBroe Aug 24 '22 at 08:14
  • 1
    The other alternative would be to use regular expressions to parse all those `[...]` placeholders, so that you can "translate" their content into a variable name / array keys. – CBroe Aug 24 '22 at 08:16
  • Show the code which is generating HTML – Shibon Aug 24 '22 at 08:56
  • 1
    @CBroe using regular expression maybe a great idea but the thing is the number of rows will not always be the same as on the template. For example i may have just two invoice items i want to invoice and the template has 6 placeholders some of the rows has to be stripped off. – Landry Aug 24 '22 at 09:05
  • Would probably make more sense to do it the other way around - have only _one_ row in your template, and then clone/duplicate that as many times as needed. But then it would really make more sense to use a DOM parser. – CBroe Aug 24 '22 at 09:13
  • @CBroe what dom parser can i use and how will it work? can you write some code – Landry Aug 24 '22 at 09:22
  • Show the template's html string, then show sime sample data for `$invoiceItems`, then we can show you how to use DOMDocument and mayble XPath (if needed). `strtr()` will consume `$token` quite happily. – mickmackusa Aug 24 '22 at 09:35
  • @mickmackusa i have edited the question adding $invoiceItems and html template string. Please check above – Landry Aug 24 '22 at 09:50
  • I think you need to change logic of loop `foreach ($token as $key => $value){ $template = str_replace($key, $value, $template); } $output = $template;` – maddy23285 Aug 24 '22 at 10:09
  • 1
    @Landry This whole task can be achieved by populating a single associative array with placeholders as keys and replacement values as values. You have already demonstrated that you know how to dynamically create enumerated strings to represent repeatable placeholders -- you just need to push them into the aforementioned array. Then you only need to feed the array to `strtr()`. I could post this as an answer, BUT 1. this is probably already demonstrated in a few other Stack Overflow pages and 2. I don't know if your looped data ALWAYS has the perfect number of rows to match the template. – mickmackusa Aug 24 '22 at 12:23
  • What is the result if there are less rows of data versus template placeholders? Conversely, what if you have more rows of data than the template accommodates? These details are critical. It is no good for contributors to answer, then you say ... oh, by the way, there are a couple fringe case scenarios that your answer doesn't cater for. Please craft a through [mcve] which clearly represents all edge cases. (By the way, `coslpan` is a typo in your template.) – mickmackusa Aug 24 '22 at 12:26
  • See the second snippet [here](https://stackoverflow.com/a/18272025/2943403). I still need to see sample data for `$invoiceItems`. – mickmackusa Aug 24 '22 at 12:41

0 Answers0