KoolReport's Forum

Official Support Area, Q&As, Discussions, Suggestions and Bug reports.
Forum's Guidelines

How do I connect textbox Input to existing search functionality #2177

Closed Niall McGuirk opened this topic on on Jul 1, 2021 - 11 comments

Niall McGuirk commented on Jul 1, 2021

I'm trying to create a report which shows a table, that is exact match searchable using a Textbox. I have used the OrderList example as a template, and am trying to convert it from using the Multi Select to using a Simple Textbox input.

The orderList report, seems to use an array to store the input, but I'm not sure how to have it usea variable, and use the variable to search on.

Here's the Report.php

<?php

require_once "../../../load.koolreport.php";

use \koolreport\KoolReport;

class OrderList extends KoolReport
{
    use \koolreport\inputs\Bindable;
    use \koolreport\inputs\POSTBinding;

    protected function defaultParamValues()
    {
        return 
		
		array(
			//creates array I need to make a Textbox useable variable
            "customers"=>array(),
        );
    }

    protected function bindParamsToInputs()
    {
        return array(
            "customers"=>"customers",
        );
    }

    public function settings()
    {
        $config = include "../../../config.php";
        return array(
            "dataSources"=>array(
                "automaker"=>$config["automaker"],
				"delv"=>$config["delv"]
            )
        );
    }   
    protected function setup()
    {
        $this->src('automaker')
        ->query("
		
		
            SELECT
                customers.customerName,
                orders.orderNumber,
                products.productName,
                orderdetails.quantityOrdered*orderdetails.priceEach as amount,
                orders.orderDate,
                orders.status
            FROM 
                orders
            JOIN 
                customers
            ON 
                customers.customerNumber = orders.customerNumber
            ".
            (($this->params["customers"]!=array())?"AND customers.customerNumber IN (:customers)":"")
            ."
            JOIN 
                orderdetails
            ON 
                orders.orderNumber = orderdetails.orderNumber
            JOIN 
                products
            ON
                products.productCode = orderdetails.productCode

        ")
        ->params(array(
            ":customers"=>$this->params["customers"]
        ))
        ->pipe($this->dataStore("result"));

        $this->src("automaker")->query("
            SELECT
                customerNumber,
                customerName
            FROM
                customers
            ORDER BY customerName
        ")
        ->pipe($this->dataStore("customers"));
    } 
}

Here is the View.php

<?php 
    use \koolreport\widgets\koolphp\Table;
    use \koolreport\inputs\DateRangePicker;
    use \koolreport\inputs\MultiSelect;
	use \koolreport\inputs\TextBox;
?>
<div class="report-content">
    <div class="text-center">
        <h1>List of order</h1>
        <p class="lead">Choose date ranges and customer to view orders</p>
    </div>
    <form method="post">
        <div class="row">
            <div class="col-md-8 offset-md-2">
                
				//I'm trying to convert the Multiselect functionality to this Textbox
				<div class="col-md-6 form-group">
                <strong>TextBox</strong>
                <?php TextBox::create(array(
                    "name"=>"customers",
                    "dataStore"=>$this->dataStore("customers"),
                    "attributes"=>array(
                        "class"=>"form-control",
                        "placeholder"=>"Enter any text"
                    )
                ));?>
            </div>
                <div class="form-group">
                <?php
                MultiSelect::create(array(
                    "name"=>"customers",
                    "dataStore"=>$this->dataStore("customers"),
                    "dataBind"=>array(
                        "text"=>"customerName",
                        "value"=>"customerNumber",
                    ),
                    "attributes"=>array(
                        "class"=>"form-control",
                        "size"=>10,
                    )
                ));
                ?>
                </div>
                <div class="form-group text-center">
                    <button class="btn btn-success"><i class="glyphicon glyphicon-refresh"></i> Load</button>
                </div>
            </div>
        </div>
    </form>


    <?php
    if($this->dataStore("result")->countData()>0)
    {
        Table::create(array(
            "dataStore"=>$this->dataStore("result"),
            "removeDuplicate"=>array("customerName","orderNumber"),
            "cssClass"=>array(
                "table"=>"table table-bordered"
            ),
            "columns"=>array(
                "customerName"=>array(
                    "label"=>"Customer",
                ),
                "orderNumber"=>array(
                    "label"=>"#Order",
                    "type"=>"string",
                ),
                "productName"=>array(
                    "label"=>"Product"
                ),
                "amount"=>array(
                    "label"=>"Amount",
                    "prefix"=>"$",
                ),
                "status"=>array(
                    "label"=>"Status",
                )

            )
        ));
    }
    else
    {
    ?>
        <div class="alert alert-warning">
            <i class="glyphicon glyphicon-info-sign"></i> Sorry, we found no orders found
        </div>
    <?php    
    }
    ?>
</div>

I've been trying to reverse engineer how it works and swap it to a the Textbox, but have not had much success.

Niall McGuirk commented on Jul 1, 2021

I've used the code from the MultiSelect for the Textbox, but I get a Notice in the Textbox about Array to string conversion.

<div class="form-group">
				<?php TextBox::create(array(
					"name"=>"customers",
                                        "dataStore"=>$this->dataStore("customersData"),
                                        "dataBind"=>array(
                                        "text"=>"customerName",
                                        "value"=>"customerNumber",
                                        ),
                                        "attributes"=>array(
                                        "class"=>"form-control",
                                        "size"=>10,
                    )
					));?>
				</div>

Is there an easy way to use a string variable instead of the array?

Sebastian Morales commented on Jul 2, 2021

If you use a TextBox input, its value and default value should be string instead of array. So I would change the defaultParameterValues method:

protected function defaultParamValues()
    {
        return 
		
		array(
			//creates array I need to make a Textbox useable variable
            "customers"=>"", //use an empty string or any default string value you like
        );
    } 

and the sql query as well:

 $this->src('automaker')
        ->query("
		
		
            SELECT
                customers.customerName,
                orders.orderNumber,
                products.productName,
                orderdetails.quantityOrdered*orderdetails.priceEach as amount,
                orders.orderDate,
                orders.status
            FROM 
                orders
            JOIN 
                customers
            ON 
                customers.customerNumber = orders.customerNumber

           AND customers.customerNumber = :customers
         
            JOIN 
                orderdetails
            ON 
                orders.orderNumber = orderdetails.orderNumber
            JOIN 
                products
            ON
                products.productCode = orderdetails.productCode

        ")
        ->params(array(
            ":customers"=>$this->params["customers"]
        ))
Niall McGuirk commented on Jul 2, 2021

Thanks. It works! I added your code, as well this to the query.

    protected function setup()
    {
        $this->src('automaker')
        ->query("
            SELECT
                customers.customerName,
                orders.orderNumber,
                products.productName,
                orderdetails.quantityOrdered*orderdetails.priceEach as amount,
                orders.orderDate,
                orders.status
            FROM 
                orders
            JOIN 
                customers
            ON 
                customers.customerNumber = orders.customerNumber

            JOIN 
                orderdetails
            ON 
                orders.orderNumber = orderdetails.orderNumber
            JOIN 
                products
            ON
                products.productCode = orderdetails.productCode
				
     /*  ADDEDLINE*/ " .(($this->params["customers"]!=array())?" and customers.customerName in (:customers)":""))
        ->params(array( //^^ Shows data when Textbox variable (customers) in customerName in Table. Exact Matching
            ":customers"=>$this->params["customers"]

It now shows the data when using the exact name in the search which is good. However, it doesn't show any data until you search for a customerName. How can I make the table show all data at the start, then search exact match, as it does now?

I've tried to use the initial variable, but that doesn't work. Is there a way to select all data initially, without generating the whole table again when searching? As there are 6 million rows in the data set I'm going to use.

Sebastian Morales commented on Jul 5, 2021

If you want to show some data but not all (6 millions) rows initially pls check to see if $this->params["customers"] is emtpy. If it is you use a sql query to get a limited number of rows:

    if (empty($this->params["customers"])) {
        $query = "SELECT ... LIMIT 100"; // the LIMIT keyword works for MySQL, other database types have other limit keyword
    } else {
        // Build sql query use "customers" parameter
    }
Niall McGuirk commented on Jul 5, 2021

Thanks for the help. Where do I place the if statement above, in my code? Does it go under the setup () function in MyReport.php? or somewhere in the view.php?

Sebastian Morales commented on Jul 5, 2021

Pls put it in the report's setup() function where you pipe your data. Tks,

Niall McGuirk commented on Jul 5, 2021

Hi Sebastian, I don't understand where specifically to insert the if statement, as I run the Query first, then concatenate the customers (Textbox) variable into the sql statement. I tried to put the if statement above the ->query, but the if was a syntax error. Which occurrence of the $this->params["customers"] do I place the if statement into, and would I need to duplicate the existing sql. Where is the ->query line in relation to the beginning of the if statement?

I can't place the if statement before the query is run, or it has a syntax error due to the IF statement. I've show the two possible locations by "HERE'S"

<?php

require_once "../../../load.koolreport.php";

use \koolreport\KoolReport;

class OrderList extends KoolReport
{
    use \koolreport\inputs\Bindable;
    use \koolreport\inputs\POSTBinding;

	protected function defaultParamValues()
    {
        return 
		
		array(
			//creates array I need to make a Textbox useable variable
			
            "customers"=>"", //use an empty string or any default string value you like
        );
    } 

    protected function bindParamsToInputs()
    {
        return array(
            "customers"=>"customers",
        );
    }

    public function settings()
    {
        $config = include "../../../config.php";
        return array(
            "dataSources"=>array(
                "delv"=>$config["delv"]
            )
        );
    }   
    protected function setup()
    {
        $this->src('delv')
        ->query("
SELECT 
tblsourcesupplier.DelvRef,
tblsourcetype.SourceType,
tblsupplierinvoice.TotalInvoiceAmount AS Invoice_Value,
(tblsupplierinvoice.TotalInvoiceAmount)+ (tblsupplierinvoice.Penalty) + (tblsupplierinvoice.Interest) as ClaimTotal,
year(paymentdate) AS PaymentYear

FROM Delv.tblsupplierinvoice
Inner Join tblsourcesupplier on tblsourcesupplier.ID = tblsupplierinvoice.SupplierID
left outer join tblsource on tblsource.id = tblsourcesupplier.sourceid
left outer join tblsourcelocation on tblsourcelocation.id = tblsource.locationid
-- include below join to have only unique suppliers.
-- left outer join tblduplicatesuppliers on tblduplicatesuppliers.SupplierID = tblsupplierinvoice.SupplierID
left outer join tblsourcetype on tblsourcetype.ID = tblsource.SourceType
    Where PaymentDate >= '2015-04-01' and  PaymentDate < DATE_ADD(curdate(), Interval -1 Year) and TimetoPayInvoice > 30 
				
        " .((*HERE*$this->params["customers"]!=array())?" and tblsourcesupplier.DelvRef in (:customers)":""))
        ->params(array( //^^ Shows data when Textbox variable (customers) in customerName in Table. Exact Matching
	
          ":customers"=>*OR HERE*$this->params["customers"]
        ))
		
        ->pipe($this->dataStore("result"));

/*         $this->src("delv")->query("
            SELECT
                count(DelvRef)
                customerName
            FROM
                customers
            ORDER BY customerName
        ")
        ->pipe($this->dataStore("customersData")); */
    } 
}

Sebastian Morales commented on Jul 6, 2021

It should be something like this:

function setup()
{
    if (isset($this->params["customers"])) {
        $customerCondition = "tblsourcesupplier.DelvRef in (:customers)";
        $params = [
            ":customer" => $this->params["customers"]
        ];
    } else {
        $customerCondition = "1=1";
        $params = [];
    }
    
    $query = "select ... where ... and " . $customerCondition;

    $this->src('delv')
    ->query($query)
    ->params($params)
    ...
Niall McGuirk commented on Jul 6, 2021

Hi Sebastian, I've added the if statement, but it just runs the same as before; returning no data unless you search. If I set the

 if (isset($this->params["customers"])) {

to NOT isset:

 if (!isset($this->params["customers"])) { 

and hard code the

else {
		$customerCondition = "tblsourcesupplier.DelvRef = 'DELV006"; 

it then it inverts it, showing data before you search, but nothing if you enter something and search.

So the else condition is never used, even if the customers variable (Searchbox) is not set. That's why the code is the same as before, not showing data unless searching. How do I ensure it uses the else condition when the searchbox is not used?

This is the code so far:

protected function setup()
    {
		//KoolReport Forum code: Show data before search
		if (isset($this->params["customers"])) {
        $customerCondition = "tblsourcesupplier.DelvRef in (:customers)";
        $params = [
            ":customers" => $this->params["customers"]
        ];
		} 	else {
			$customerCondition = "1=1  limit 10";
			$params = [];
		}
    
		$query = "SELECT 
				tblsourcesupplier.DelvRef,
				tblsourcetype.SourceType,
				tblsupplierinvoice.TotalInvoiceAmount AS Invoice_Value,
				(tblsupplierinvoice.TotalInvoiceAmount)+ (tblsupplierinvoice.Penalty) + (tblsupplierinvoice.Interest) as ClaimTotal,
				year(paymentdate) AS PaymentYear

				FROM Delv.tblsupplierinvoice
				Inner Join tblsourcesupplier on tblsourcesupplier.ID = tblsupplierinvoice.SupplierID
				left outer join tblsource on tblsource.id = tblsourcesupplier.sourceid
				left outer join tblsourcelocation on tblsourcelocation.id = tblsource.locationid
				-- include below join to have only unique suppliers.
				-- left outer join tblduplicatesuppliers on tblduplicatesuppliers.SupplierID = tblsupplierinvoice.SupplierID
				left outer join tblsourcetype on tblsourcetype.ID = tblsource.SourceType
					Where PaymentDate >= '2015-04-01' and  PaymentDate < DATE_ADD(curdate(), Interval -1 Year) and TimetoPayInvoice > 30  and " . $customerCondition;

		$this->src('delv')	
        ->query($query)
        ->params($params)
		
        ->pipe($this->dataStore("result"));
Sebastian Morales commented on Jul 7, 2021

Sorry, it should not be isset but !empty because by default the parameter still exists as an empty string:

    if (!empty($this->params["customers"])) { //if param "customers" doesn't exist or exists as an empty value
        $customerCondition = "tblsourcesupplier.DelvRef in (:customers)";
        $params = [
            ":customer" => $this->params["customers"]
        ];
    } else {
        $customerCondition = "1=1";
        $params = [];
    } 

Pls try it and let us know the result. Tks,

Niall McGuirk commented on Jul 7, 2021

That's great. It works how I wanted it to. Thanks for all the help!

Build Your Excellent Data Report

Let KoolReport help you to make great reports. It's free & open-source released under MIT license.

Download KoolReport View demo
help needed
solved

Inputs