Optimize cannot be blank

Hello folks, so I’m getting this error when I run the class:

<?php

/**
 * @link http://www.yiiframework.com/
 * @copyright Copyright (c) 2008 Yii Software LLC
 * @license http://www.yiiframework.com/license/
 */

namespace app\commands;

use app\components\IFoodAPI;
use app\models\User;
use app\helper\RequestRideHelper;
use yii\console\Controller;
use yii\db\Query;

/**
 * This command echoes the first argument that you have entered.
 *
 * This command is provided as an example for you to learn how to create console commands.
 *
 * @author Qiang Xue <qiang.xue@gmail.com>
 * @since 2.0
 */
class IFoodApiController extends Controller
{
    /**
     * This command echoes what you have entered as the message.
     * @param string $message the message to be echoed.
     */

    public function actionIndex($message = 'hello world')
    {
        $ifoodApi = new IFoodAPI();

        $eventList = $ifoodApi->request(
            'GET',
            '/order/v1.0/events:polling',
            [
                'types' => 'PLC,REC,CFM',
                'groups' => 'ORDER_STATUS,DELIVERY'
            ]
        );

        if (is_array($eventList)) {
            $ridesList = [];

            foreach ($eventList as $eventData) {
                // Ask client order details
                $orderData = $ifoodApi->request(
                    'GET',
                    sprintf('/order/v1.0/orders/%s', $eventData['orderId'])
                );

                if (isset($orderData['delivery']['deliveryAddress']['formattedAddress'])) {
                    $ifoodMerchantId = $eventData['merchantId'];
                    // Query database for merchantID client match.
                    $query = new Query();
                    $rows = $query
                        ->select(['*'])
                        ->from('business')
                        ->where(['merchant_id' => $ifoodMerchantId])
                        ->limit(1)
                        ->all();

                    if (!empty($rows)) {
                        $businessData = $rows[0];
                        $businessId = $businessData['user_id'] ?? null;

                        if (!isset($ridesList[$businessId])) {
                            $ridesList[$businessId] = [];
                        }

                        $ridesList[$businessId][] = [
                            'originAddress' => $businessData['address'],
                            'origin_latitude' => $businessData['latitude'],
                            'origin_longitude' => $businessData['longitude'],
                            'origin_note' => $businessData['addressNote'],
                            'destinationAddress' => sprintf('%s', $orderData['delivery']['deliveryAddress']['formattedAddress']),
                            'destination_latitude' => $orderData['delivery']['deliveryAddress']['coordinates']['latitude'],
                            'destination_longitude' => $orderData['delivery']['deliveryAddress']['coordinates']['longitude'],
                            'destination_note' => [],
                            'external_id' => $orderData['displayId'],
                            'date' => $orderData['createdAt'],
                            'measures_id' => [],
                            'note' => [],
                            //                            'receiver_phone' => $orderData['customer']['phone']['number'],
                            'receiver_phone' => '(79) 99153-1519',
                            'receiver_name' => $orderData['customer']['name'],
                            'receiver_intermediate' => $orderData['customer']['name'],
                            'food' => true,
                            'is_food' => 1,
                            'volume' => [
                                'length' => 0.25,
                                'height' => 0.25,
                                'width' => 0.25,
                                'weight' => 0.25,
                            ],
                            'type_of_content' => 1,
                            'num_volumes' => 1,
                            'vehicle_type' => 0,
                            'type' => 0,
                        ];
                    }
                }
            }

            // iFood API orders confirmation
            $ifoodApi->request('POST', '/order/v1.0/events/acknowledgment', $eventList);

            foreach ($ridesList as $businessId => $rideListFromMerchant) {

                $requestForm = new \stdClass();
                $requestForm->rides = $rideListFromMerchant;
                $requestForm->optimize = false;

                $user = User::findIdentity($businessId);

                var_dump($response = (new RequestRideHelper())->requestRide($requestForm, $user));
            }
        }
    }
}

Basically, the requestRide method is returning an error:

object(app\models\Errors)#154 (7) {
  ["errors"]=>
  array(1) {  
    [0]=>
    string(25) "Optimize cannot be blank."
  }
  ["_errors":"yii\base\Model":private]=>
  NULL
  ["_validators":"yii\base\Model":private]=>
  NULL
  ["_scenario":"yii\base\Model":private]=>
  string(7) "default"
  ["_events":"yii\base\Component":private]=>
  array(0) {
  }
  ["_eventWildcards":"yii\base\Component":private]=>
  array(0) {
  }
  ["_behaviors":"yii\base\Component":private]=>
  NULL
}

What I don’t understand is why the parameter was not sent in the request body. Can anyone help me with this one?

A problem of case sensitivity?

Or maybe some error in your RequestRideHelper::requestRide().

Where is the model hydrated? I don’t see the code for that.

This is the helper class used in the code above:

<?php

namespace app\helper;

use app\jobs\SearchDriverJob;
use app\models\Business;
use app\models\Error;
use app\models\Errors;
use app\models\Fare;
use app\models\forms\ApiBatchRequestForm;
use app\models\Ride;
use app\models\RideInsurance;
use app\models\RidePrice;
use app\models\RideStatus;
use app\models\RideVolume;
use app\models\Zone;
use yii\db\Exception;
use yii\console\Response as ConsoleResponse;
use Yii;
use function GuzzleHttp\json_encode;

class RequestRideHelper
{
    protected function setResponseStatusCode($statusCode)
    {
        if (!Yii::$app->response instanceof ConsoleResponse) {
            Yii::$app->response->statusCode = $statusCode;
        }
    }

    public function requestRide($data, $user)
    {

        $batchRequestRideForm = new ApiBatchRequestForm();
        $batchRequestRideForm->setAttributes($data);

        $transaction = Yii::$app->db->beginTransaction();

        try {
            if ($batchRequestRideForm->validate()) {
                $ride_type = 0;
                $ride_date = date('Y-m-d H:i:s');
                $num_waypoints = count($batchRequestRideForm->rides);
                $waypoint = 1;
                $parent_id = null;
                $previousRide = null;
                $index = 0;
                $values = null;

                // CHECK IF THE USER SELECTED OPTIMIZE OPTION AND HAS MULTIPLE RIDES
                if ($batchRequestRideForm->optimize && count($batchRequestRideForm->rides) > 1) {
                    $newRides = RideHelper::optimizeRide($batchRequestRideForm->rides);

                    if ($newRides['statusCode']) {
                        $transaction->rollBack();
                        $this->setResponseStatusCode(422);
                        return new Error("ERROR_OPTIMIZING_RIDES");
                    }

                    // SET THE NEW ORDER OF RIDES
                    $batchRequestRideForm->rides = $newRides;
                }

                $outputRides = array();
                foreach ($batchRequestRideForm->rides as $requestRideForm) {
                    $index++;

                    $requestRideForm = (object) $requestRideForm;

                    $requester = $user->getId();

                    if ($user->business_id != null && $requestRideForm->requester) {

                        $requesterId = SecurityHash::fromHashids($requestRideForm->requester);

                        if ($requester != $requesterId) {

                            if ($user->business_id != $requesterId) {

                                $transaction->rollBack();
                                $this->setResponseStatusCode(422);
                                return new Error("REQUESTER_NOT_FOUND");
                            } else {
                                $requester = $requesterId;
                            }
                        }
                    }

                    if (!$batchRequestRideForm->optimize || count($batchRequestRideForm->rides) <= 1) {
                        // // CHECK IF THERE`S A PREVIOUS RIDE ALREADY ASSIGNED
                        if (!is_null($previousRide)) {
                            // IF PREVIOUS RIDE ALREADY EXISTS, THIS RIDE ORIGN IS PREVIOUS RIDE DESTINATION
                            $requestRideForm->originAddress = $previousRide->destinationAddress;
                            $requestRideForm->origin_latitude = $previousRide->destination_latitude;
                            $requestRideForm->origin_longitude = $previousRide->destination_longitude;
                        }

                        $values = ApiServiceHelper::getDistance($requestRideForm->origin_latitude, $requestRideForm->origin_longitude, $requestRideForm->destination_latitude, $requestRideForm->destination_longitude, $requestRideForm->originAddress, $requestRideForm->destinationAddress);


                        if (isset($values['statusCode']) && $values['statusCode'] == 422) {
                            $transaction->rollBack();
                            $this->setResponseStatusCode(422);
                            return new Error("ROUTE_NOT_FOUND");
                        }

                        if (is_null($previousRide)) {
                            $requestRideForm->origin_latitude = $values['origin_latitude'];
                            $requestRideForm->origin_longitude = $values['origin_longitude'];
                        }

                        $requestRideForm->destination_latitude = $values['destination_latitude'];
                        $requestRideForm->destination_longitude = $values['destination_longitude'];

                        $zone = Zone::findBySql(
                            "select * from zone where available = 1 and size > getDistance(zone.origin_latitude, zone.origin_longitude, :origin_latitude, :origin_longitude) and size > getDistance(zone.origin_latitude, zone.origin_longitude, :dest_latitude, :dest_longitude)",
                            [
                                ":origin_latitude" => $requestRideForm->origin_latitude,
                                ":origin_longitude" => $requestRideForm->origin_longitude,
                                ":dest_latitude" => $values['destination_latitude'],
                                ":dest_longitude" => $values['destination_longitude']
                            ]
                        )
                            ->one();
                    } else {
                        $zone = Zone::findBySql(
                            "select * from zone where available = 1 and size > getDistance(zone.origin_latitude, zone.origin_longitude, :origin_latitude, :origin_longitude) and size > getDistance(zone.origin_latitude, zone.origin_longitude, :dest_latitude, :dest_longitude)",
                            [
                                ":origin_latitude" => $requestRideForm->origin_latitude,
                                ":origin_longitude" => $requestRideForm->origin_longitude,
                                ":dest_latitude" => $requestRideForm->destination_latitude,
                                ":dest_longitude" => $requestRideForm->destination_longitude
                            ]
                        )->one();
                    }

                    if (!$zone) {

                        $transaction->rollBack();
                        $this->setResponseStatusCode(422);
                        return new Error("UNAVAILABLE_ADDRESS");
                    }

                    $fare = Fare::findBySql(
                        "select * from fare where status = 1 and type_of_content = :type_of_content and vehicle_type = :vehicle_type and user_id = :requester",
                        [
                            ":type_of_content" => $requestRideForm->type_of_content,
                            ":vehicle_type" => $requestRideForm->vehicle_type,
                            ":requester" => $requester
                        ]
                    )->one();

                    if (!$fare) {

                        $fare = Fare::findBySql(
                            "select * from fare where status = 1 and type_of_content = :type_of_content and vehicle_type = :vehicle_type and zone_id = :zone_id",
                            [
                                ":type_of_content" => $requestRideForm->type_of_content,
                                ":vehicle_type" => $requestRideForm->vehicle_type,
                                ":zone_id" => $zone->id
                            ]
                        )->one();

                        if (!$fare) {
                            $transaction->rollBack();
                            $this->setResponseStatusCode(422);
                            return new Error("FARE_NOT_FOUND");
                        }
                    }

                    $isBusiness = Business::find()->where(['user_id' => $requester, 'active' => 1])->exists(); //TODO retornar erro amigável

                    if (!$isBusiness) {

                        $transaction->rollBack();
                        $this->setResponseStatusCode(422);
                        return new Error("USER_IS_NOT_BUSINESS");
                    }

                    $ride = new Ride();

                    $ride->setAttribute('requester_id', $requester);
                    if (!$batchRequestRideForm->optimize || count($batchRequestRideForm->rides) <= 1) {
                        $ride->setAttribute('distance', $values['distance']);
                        $ride->setAttribute('estimated_duration', $values['estimated_duration']);
                        $ride->setAttribute('destination_latitude', $values['destination_latitude']);
                        $ride->setAttribute('destination_longitude', $values['destination_longitude']);
                        $ride->setAttribute('path', $values['path']);
                    } else {
                        $ride->setAttribute('distance', $requestRideForm->distance);
                        $ride->setAttribute('estimated_duration', $requestRideForm->estimated_duration);
                        $ride->setAttribute('destination_latitude', $requestRideForm->destination_latitude);
                        $ride->setAttribute('destination_longitude', $requestRideForm->destination_longitude);
                        $ride->setAttribute('path', $requestRideForm->path);
                    }
                    $ride->setAttribute('destinationAddress', $requestRideForm->destinationAddress);
                    $ride->setAttribute('originAddress', $requestRideForm->originAddress);
                    $ride->setAttribute('origin_latitude', $requestRideForm->origin_latitude);
                    $ride->setAttribute('origin_longitude', $requestRideForm->origin_longitude);
                    $ride->setAttribute('origin_note', $requestRideForm->origin_note);
                    $ride->setAttribute('destination_note', $requestRideForm->destination_note);
                    $ride->setAttribute('external_id', $requestRideForm->external_id);
                    $ride->setAttribute('is_food', $requestRideForm->is_food != null ? intval($requestRideForm->is_food) : null);
                    $ride->setAttribute('is_integration', 1);

                    if (is_null($parent_id)) {

                        if ($requestRideForm->date) {
                            $ride->setAttribute('date', $requestRideForm->date);
                            $ride->setAttribute('type', 1);
                            $ride_type = 1;
                            $ride_date = $requestRideForm->date;
                        } else {
                            $ride->setAttribute('date', date("Y-m-d H:i:s"));
                            $ride->setAttribute('type', 0);
                            $ride_type = 0;
                            $ride_date = date("Y-m-d H:i:s");
                        }
                    } else {

                        if ($ride_type == 1) {
                            $ride->setAttribute('date', $ride_date);
                            $ride->setAttribute('type', 1);
                        } else {
                            $ride->setAttribute('date', date("Y-m-d H:i:s"));
                            $ride->setAttribute('type', 0);
                        }
                    }

                    $ride->setAttribute('payment_method', 3);
                    $ride->setAttribute('fare', $fare->id);
                    $ride->setAttribute('measures_id', $requestRideForm->measures_id);
                    $ride->setAttribute('note', $requestRideForm->note);
                    $ride->setAttribute('receiver_phone', $requestRideForm->receiver_phone);
                    $ride->setAttribute('receiver_name', $requestRideForm->receiver_name);
                    $ride->setAttribute('receiver_intermediate', $requestRideForm->receiver_intermediate);

                    $ride->setAttribute('vehicle_type', $requestRideForm->vehicle_type);
                    $ride->setAttribute('created_by', $user->getId());
                    $ride->setAttribute('num_waypoints', $num_waypoints);
                    $ride->setAttribute('waypoint', $waypoint++);
                    $ride->setAttribute('parent_id', $parent_id);

                    if ($requestRideForm->num_volumes) {
                        $ride->setAttribute('num_volumes', $requestRideForm->num_volumes);
                    }

                    if (!$ride->save()) {

                        $transaction->rollBack();
                        $this->setResponseStatusCode(400);
                        return new Errors($ride->getErrorSummary(true));
                    }

                    if (is_null($parent_id)) {
                        $parent_id = $ride->id;
                    }

                    if ($requestRideForm->volume) {

                        $rideVolume = new RideVolume();
                        $rideVolume->setAttribute('ride_id', $ride->id);
                        $rideVolume->setAttribute('length', $requestRideForm->volume['length']);
                        $rideVolume->setAttribute('width', $requestRideForm->volume['width']);
                        $rideVolume->setAttribute('height', $requestRideForm->volume['height']);
                        $rideVolume->setAttribute('weight', $requestRideForm->volume['weight']);

                        $calcWeight = doubleval($requestRideForm->volume['length']) * doubleval($requestRideForm->volume['width']) * doubleval($requestRideForm->volume['height']) * 300.0;
                        $calcWeight = HelperFunctions::toMoney($calcWeight);
                        $rideVolume->setAttribute('calc_weight', $calcWeight);

                        $rideVolume->save();
                    }

                    if ($ride_type == 0) {

                        $rideStatus = new RideStatus();
                        $rideStatus->setAttribute('status_id', 1);
                        $rideStatus->setAttribute('ride_id', $ride->id);
                        $rideStatus->setAttribute('created_by', $user->getId());

                        if (!$rideStatus->save(true)) {

                            $transaction->rollBack();
                            $this->setResponseStatusCode(400);
                            return new Errors($rideStatus->getErrorSummary(true));
                        }
                    } else {

                        $rideStatus = new RideStatus();
                        $rideStatus->setAttribute('status_id', 0);
                        $rideStatus->setAttribute('ride_id', $ride->id);
                        $rideStatus->setAttribute('created_by', $user->getId());

                        if (!$rideStatus->save(true)) {

                            $transaction->rollBack();
                            $this->setResponseStatusCode(400);
                            return new Errors($rideStatus->getErrorSummary(true));
                        }
                    }

                    if (!$batchRequestRideForm->optimize || count($batchRequestRideForm->rides) <= 1) {
                        $distancePrice = HelperFunctions::toMoney(doubleval($values['distance'] / 1000) * doubleval($ride->fare0->distance_value));
                    } else {
                        $distancePrice = HelperFunctions::toMoney(doubleval($requestRideForm->distance / 1000) * doubleval($ride->fare0->distance_value));
                    }

                    if ($distancePrice < $fare->minimum)
                        $distancePrice = $fare->minimum;

                    $volumePrice = 0;
                    if ($fare->type_of_content >= 1) {

                        if ($requestRideForm->is_food) {
                            $volumePrice = $fare->food != null ? $fare->food : 0;
                        } else {

                            if ($requestRideForm->volume) {

                                $weight = doubleval($requestRideForm->volume['weight']);
                                $calcWeight = doubleval($requestRideForm->volume['length']) * doubleval($requestRideForm->volume['width']) * doubleval($requestRideForm->volume['height']) * 300.0;

                                $maxWeight = max($weight, $calcWeight);
                                $discount = floor($maxWeight / 10.0) * 0.02;
                                $discount = min($discount, 0.20);
                                $volumeValue = doubleval($fare->volume_value) - $discount;

                                $volumePrice = HelperFunctions::toMoney($maxWeight * $volumeValue);
                            }
                        }

                        if ($volumePrice < $fare->minimum_volume)
                            $volumePrice = $fare->minimum_volume;
                    } else {
                        $volumePrice = doubleval($fare->volume_value);
                    }

                    //Mínimo de seguro
                    // $insuranceRate = Constants::INSURANCE_PRICE;
                    $insuranceRate = doubleval($fare->insurance_rate / 100);
                    $assuredPrice = Constants::MINIMUM_ASSURED_PRICE;

                    $insurancePrice = doubleval($assuredPrice) * doubleval($insuranceRate);

                    if ($requestRideForm->product_price != null && $requestRideForm->product_price > $assuredPrice) {

                        $assuredPrice = $requestRideForm->product_price;
                        $insurancePrice = doubleval($requestRideForm->product_price) * doubleval($insuranceRate);
                        $insurancePrice = HelperFunctions::toMoney($insurancePrice);
                    }

                    $rideInsurance = new RideInsurance();
                    $rideInsurance->setAttributes([
                        'ride' => $ride->id,
                        'product_price' => $assuredPrice,
                        'price' => $insurancePrice,
                        'tax_number' => $requestRideForm->tax_number
                    ]);

                    $rideInsurance->save();

                    $totalPrice = $distancePrice + $volumePrice + $insurancePrice;
                    $totalPrice = HelperFunctions::toMoney($totalPrice);

                    $driverPrice = HelperFunctions::toMoney(($distancePrice + $volumePrice) * 0.75);

                    $ridePrice = new RidePrice();
                    $ridePrice->setAttributes([
                        'ride_id' => $ride->id,
                        'distance_price' => $distancePrice,
                        'volume_price' => $volumePrice,
                        'insurance_price' => $insurancePrice,
                        'discount_price' => 0,
                        'total_price' => $totalPrice,
                        'driver_price' => $driverPrice
                    ]);

                    $url = "https://maps.googleapis.com/maps/api/staticmap?size=500x300&key=" . env("MAPS_API_KEY") . "&markers=color:red|label:O|" . $ride->origin_latitude . "," . $ride->origin_longitude . "&markers=color:blue|label:D|" . $ride->destination_latitude . "," . $ride->destination_longitude . "&path=color:red|weight:2|enc:" . $ride->path;

                    $fileName = SecurityHash::toHashids($ride->id) . '.png';
                    $image = file_get_contents(addcslashes($url, "\v"));

                    $fp = fopen("temp/" . $fileName, 'a');
                    fputs($fp, $image);
                    fclose($fp);

                    $result = S3Helper::uploadMapImageToS3($fp, $fileName);

                    if ($result['statusCode'] != null && $result['statusCode'] == 200) {

                        $ride->map = $result["effectiveUri"];
                        $ride->save();
                    }

                    // ASSIGN THE CURRENT RIDE AS PREVIOUS RIDE FOR THE NEXT RIDE
                    if (!$batchRequestRideForm->optimize || count($batchRequestRideForm->rides) <= 1) {
                        $previousRide = $requestRideForm;
                    }

                    if (!$ridePrice->save()) {

                        $transaction->rollBack();
                        $this->setResponseStatusCode(400);
                        return new Errors($ridePrice->getErrorSummary(true));
                    }

                    $outputRides[] = $ride;
                }
                echo "Depois da solicitação";
                $transaction->commit();

                if ($ride_type == 0) {

                    Yii::$app->queue->push(
                        new SearchDriverJob([
                            'currentTry' => 0,
                            'rideId' => $parent_id
                        ])
                    );
                }

                return [
                    "rides" => $outputRides
                ];
            } else {

                $transaction->rollBack();
                $this->setResponseStatusCode(400);
                \Yii::warning([
                    'msg' => "Erro ao solicitar corrida",
                    'extra' => json_encode($batchRequestRideForm->getErrorSummary(true)),
                ], 'testes');
                return new Errors($batchRequestRideForm->getErrorSummary(true));
            }
        } catch (Exception $e) {
            \Yii::warning([
                'msg' => "Erro ao solicitar corrida",
                'extra' => $e->getMessage(),
            ], 'testes');
            $transaction->rollBack();
            $this->setResponseStatusCode(400);
            return new Error("INTERNAL ERROR");
        }
    }
}

The $ApiBatchRequestForm() used by the $batchRequestRideForm is this one:

{
  public $rides;
  public $optimize;

  /**
   * @return array the validation rules.
   */
  public function rules()
  {
    return [
      [['optimize'], 'required'],
      [['optimize'], 'boolean'],
      ['rides', 'checkIsArray'],
      ['rides', 'validateRide']
    ];
  }

  public function validateRide($attribute, $params)
  {

    foreach ($this->$attribute as $ride) {
      $apiRequestRideForm = new ApiRequestRideForm();
      $apiRequestRideForm->setAttributes($ride);

      if (!$apiRequestRideForm->validate()) {
        $this->addErrors($apiRequestRideForm->errors);
      }
    }
  }

  public function checkIsArray($attribute, $params)
  {
    if (!is_array($this->$attribute) || array_values($this->$attribute) !== $this->$attribute) {
      $this->addError($attribute, $attribute . " must be array.");
    }
  }
}

To be honest I’m a bit lost with that code. Definitely you need to double check all the properties, if you are hydrating the proper models with all validation rules set.

I think you should use an array for setAttributes

Just make simple search and no where $rider model is setting optimize attribute
You should collect your attribute in one place and set them once into a model. That way it will be easy to just dump the array to see the missing piece!