Complex forms with multiple models

When dealing with some complex data, it is possible that you may need to use multiple different models to collect the user input. For example, you have an order form with user information such as first name, last name, and phone number; you also have a delivery address and some kind of product.

You would like to save all this data in one form. With Yii models and support forms, you can easily do this. Assuming that the user info will be stored in the user table and in the order form, we will save product information and the user_id of the user who has ordered a product. We also have a product table with some information in it.

Getting ready

  1. Create a new application by using the Composer package manger, as described in the official guide at http://www.yiiframework.com/doc-2.0/guide-start-installation.html.
  2. Create migrations for contest and prize tables with the following commands:
    ./yii migrate/create create_order_tables
  3. Update the newly-created migration's up() and down() methods with the following code:
    <?php
    use yiidbSchema;
    use yiidbMigration;
    use appmodelsProduct;
    class m150813_161817_create_order_form_tables extends Migration
    {
        public function up()
        {
            $tableOptions = null;
            if ($this->db->driverName === 'mysql') {
                $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_general_ci ENGINE=InnoDB';
            }
            $this->createTable('user', [
                'id' => Schema::TYPE_PK,
                'first_name' => Schema::TYPE_STRING . ' NOT NULL',
                'last_name' => Schema::TYPE_STRING . ' NOT NULL',
                'phone' => Schema::TYPE_STRING . ' NOT NULL',
            ], $tableOptions);
            $this->createTable('product', [
                'id' => Schema::TYPE_PK,
                'title' => Schema::TYPE_STRING . ' NOT NULL',
                'price' => Schema::TYPE_FLOAT . '(6,2) ',
            ], $tableOptions);
            $this->createTable('order', [
                'id' => Schema::TYPE_PK,
                'user_id' => Schema::TYPE_INTEGER . ' NULL',
                'address' => Schema::TYPE_STRING . ' NOT NULL',
                'product_id' => Schema::TYPE_INTEGER . ' NOT NULL',
            ], $tableOptions);
            $product1 = new Product();
            $product1->title = 'Iphone 6';
            $product1->price = 400.5;
            $product1->save();
            $product3 = new Product();
            $product3->title = 'Samsung Galaxy Note 5';
            $product3->price = 900;
            $product3->save();
            $this->addForeignKey('fk_order_product_id', 'order', 'product_id', 'product', 'id');
        }
        public function down()
        {
            $this->dropTable('order');
            $this->dropTable('user');
            $this->dropTable('product');
        }
    }
  4. Then, install migration with the following command:
    ./yii migrate/up
  5. With Gii, generate user, order, and product models.

How to do it...

  1. Create @app/controllers/TestController with the following code:
    <?php
    namespace appcontrollers;
    use appmodelsOrder;
    use appmodelsUser;
    use Yii;
    use yiiwebController;
    class TestController extends Controller
    {
        public function actionOrder()
        {
            $user = new User();
            $order = new Order();
            if ($user->load(Yii::$app->request->post()) && $order->load(Yii::$app->request->post())) {
            if ($user->validate() && $order->validate()) {
                $user->save(false);
                $order->user_id = $user->id;
                $order->save(false);
                $this->redirect(['/test/result', 'id' => $order->id]);
                }
            }
            return $this->render('order', ['user' => $user, 'order' => $order]);
        }
        public function actionResult($id)
        {
            $order = Order::find($id)->with('product', 'user')->one();
            return $this->renderContent(
                'Product: ' . $order->product->title . '</br>' .
                'Price: ' . $order->product->price . '</br>' .
                'Customer: ' . $order->user->first_name . ' ' . $order->user->last_name . '</br>' .
                'Address: ' . $order->address
            );
        }
    }
  2. Then create a view file, @app/views/test/order.php, and add the following code:
    <?php
    use yiihelpersHtml;
    use yiiwidgetsActiveForm;
    use appmodelsProduct;
    use yiihelpersArrayHelper;
    /**
    * @var $user appmodelsUser
    * @var $order appmodelsOrder
    */
    $form = ActiveForm::begin([
        'id' => 'order-form',
        'options' => ['class' => 'form-horizontal'],
    ]) ?>
    <?= $form->field($user, 'first_name')->textInput(); ?>
    <?= $form->field($user, 'last_name')->textInput(); ?>
    <?= $form->field($user, 'phone')->textInput(); ?>
    <?= $form->field($order, 'product_id')->dropDownList(ArrayHelper::map(Product::find()->all(), 'id', 'title')); ?>
    <?= $form->field($order, 'address')->textInput(); ?>
    <?= Html::submitButton('Save', ['class' => 'btn btn-primary']) ?>
    <?php ActiveForm::end() ?>

How it works...

You can see the form at http://yii-book.app/index.php?r=test/order. Our form collects information from the user and order models.

Let's fill out our form:

How it works...

After saving, you will see the following result:

How it works...

In the controller, we validate and store it. Of course, this example is very simple. In real projects, you may have more than one model and you will be able to use this approach for them. This approach is very useful when you want to create or update more than one instance in the same form.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.224.149.242