phpregexformsnette

Nette, extract numbers from a textarea to perform a Calculation


Hello I have this issue where I want to take the input values from textarea1 which will be for example: "300pcs, 200$" on the first line and "500pcs, 400$" and so on, to perform an increase of price based on the number of pieces(I used to have it with inputs and it worked, but I was told I need a textarea). The result of the calculation would be something like : textarea2 "300pcs,220$" and line 2 "500pcs, 540$" increased by the appropriate percentage. My issue is, I need to extract the numbers from every line in the text area to perform the calculation and it doesn't seem to work as thought it would..

declare(strict_types=1);

namespace App\Presenters;


    use App\Forms\FormFactory;
    use Nette\Application\UI\Form;
    use Nette\Database\Context;
    use Nette\Utils\ArrayHash;

class HomepagePresenter extends BasePresenter
{

    /**
     * @var Context
     * @inject
     */
    public $database;

    /**
     * @var FormFactory
     * @inject
     */
    public $formFactory;

    protected function createComponentCalculationForm(): Form
    {
        $form = $this->formFactory->create();

        $form->addSelect('supplier', 'Dodavatel:', $this->database->table('suppliers')->fetchPairs('id', 'supp_name'));

        $form->addTextArea('user_input');

        $form->addSubmit('calculate', 'Spočítat');

        $form->addTextArea('result')
            ->setHtmlAttribute('class', 'totalPrice')
            ->setHtmlAttribute('readonly');

        $form->onSuccess[] = function (Form $form, ArrayHash $values): void {
            $selectedSupp = $values->supplier;
            $userInput = $values->user_input;
            $lines = $array = explode("\n", $userInput);
            foreach ($lines as $line) {
                preg_match_all('/[\d]+/', $line, $numbers);
                list($quantity, $price) = $numbers[0];
            }

            $modifier = $this->database->fetch('SELECT percentage FROM prices WHERE supplier_id = ? AND max >= ? AND min <= ?', $selectedSupp, $quantity, $quantity);
            $total = round($price + ($price / 100) * $modifier->percentage);
            $form['result']->setValue("$quantity Ks, $total Kč + DPH");
        };

        return $form;
    }

}

Solution

  • My guess is that you likely might want to write an expression with less boundaries, such as

    (?i)(\d+)\s*pcs\s*[,;]*\s*\$?\s*(\d+(?:\.\d*)?|(?:\.\d+))\s*\$?
    

    or if not, for just that same format in the question,

    (\d+)pcs,\s(\d+)\$
    

    might simply work.

    Demo

    For testing, you might want to write some function and call it in the loop you wish to do things, such as:

    Test

    $str = '
    300pcs, 200$
    301pcs, 201$
    301pcs, 201.5$
    301.2pcs, 201$
    300pcs, 200$
    500pcs, 400$
    310pcs  ,   220.22$
    550  PCS,   540.5$
    301pcs     220.$
    502 pcs,   .54 $
    303  PCS  ;   $220.6
    504 pcs,   $540.4
    500 pcs,   . $';
    
    function extractPiecesPrices($str)
    {
        $re = '/^(\d+)pcs,\s(\d+)\$$/m';
        preg_match_all($re, $str, $matches, PREG_SET_ORDER, 0);
    
        foreach ($matches as $key => $value) {
            if ($value[2] != "") {
                print($value[2] . " is price\n");
                // do some math on prices
            }
            if ($value[1] != "") {
                print($value[1] . " is pcs\n");
                // do some math on pieces
            }
        }
    
    }
    
    extractPiecesPrices($str);
    

    Output

    200 is price
    300 is pcs
    201 is price
    301 is pcs
    200 is price
    300 is pcs
    400 is price
    500 is pcs