Yii2 Rest API Displaying Data with Search Capability

Assume we have GET REST API end-point, and want to display it in our Yii2 and when the data consist of much entries of course we need search data capability to the ‘similar’ end-point.

Most of tutorial we found in the net re GET REST API are only display list of data from any end-point, and fortunately I got from reading a book that explain how we can create search capability to any GET REST API data in yii2 client app.

In this article, I have an end-point with return a results in json like below if I type text adi:

{
“results”: [
{
“Number”: “ID0015”,
“Course”: “Sport Climbing Level-1”,
“Name”: “Adie Setiawan”,
“Gender”: “Male”,
“Citizen”: “Indonesia”
},
{
“Number”: “ID0203”,
“Course”: “Sport Climbing Level-2”,
“Name”: “Adie Setiawan”,
“Gender”: “Male”,
“Citizen”: “Indonesia”
},
]
}

In this tutorial there are two parts we have to consider: view and controller.

1. View Part

I have made view with file name find-one.html as below:

<?php

use yii\helpers\Html;
use yii\widgets\ActiveForm;
use yii\grid\GridView;

/* @var $this yii\web\View /
/
@var $model frontend\models\search\CertificatesSearch /
/
@var $form yii\widgets\ActiveForm */

$this->title = ‘Issued Certificates List’;
$this->params[‘breadcrumbs’][] = $this->title;
?>

<h1><?= Html::encode($this->title) ?></h1>

<?php $form = ActiveForm::begin(); ?>

<div class='row pull-right' style='width:50%'>
    <div class="col-auto input-group">
            <?= $form->field($model, 'name')->textInput(['autofocus' => true, 'placeholder'=>'Type name'])->label(false) ?>
            <span class='input-group-btn'>
                <?= Html::submitButton('<i class="fa fa-search fa-md fa-fw" aria-hidden="true" style="color:white"></i>', ['class' => 'btn btn-warning']) ?>
                <?= Html::a('Back', ['find-one'], ['class' => 'btn btn-success']) ?>
            </span>
                <br>
    </div>
</div>

<?php ActiveForm::end(); ?>
<?php
if(!empty($results)){ 
    echo "<table class='table table-bordered table-striped'>";
    foreach($results as $key => $result){
        //print_r($result); 
        echo '<tr>';
        echo '<th>#</th>';
        echo '<th>Number</th>';
        echo '<th>Name</th>';
        echo '<th>Gender</th>';
        echo '<th>Citizen</th>';
        echo '<th>Course Title</th>';
        echo '</tr>';
        echo '<span>Showing '.count($result).' searched results</span>';
             $no = 0;
             foreach($result as $key => $value ){
                $no++;
                echo '<tr>';
                echo '<td>' . $no . '</td>';
                echo '<td>' . $value->Number . '</td>';
                echo '<td>' . ucwords(strtolower($value->Name)). '</td>';
                echo '<td>' . $value->Gender . '</td>';
                echo '<td>' . $value->Citizen . '</td>';
                echo '<td>' . $value->Course . '</td>';
                echo '</tr>';
           }
      }
    echo "</table>";
}
elseif(empty($results)) 
{
?>
    <?= GridView::widget([
    'dataProvider' => $dataProvider,
    'columns' => [
        ['class' => 'yii\grid\SerialColumn'],

        'Number',
        'Name',
        'Citizen',
    ],
]); 

}

?>

In the top most please add with this line:

use yii\grid\GridView;

We can see the actual view like this.

Back button is my trick to echo GridView if(empty($results))) it is deem as default if search box got no name on the list.

I use //print_r($result); to view detail of search box $result it will display json data like this:

Array ( [0] => stdClass Object ( [Number] => 009 [Course] => Sport Climbing Instructor Cat-1 [Name] => Name of Person [Gender] => Male [Citizen] => Indonesia ) )

If we type text adi in the seacrh box will display like this

Showing 20 results.

2. Controller Part
The code of the controller that serve this view contructed like this

public function actionFindOne() {
   $client_1 = new Client();

    $response_1 = $client_1->createRequest()
      ->setUrl('END_POINT_ADDRESS_1')
      ->send();
      
    $data = Json::decode($response_1->content);
    
    if ($response_1->isOk) {
        $hasil = $data['results'];
    } 

    $dataProvider = new ArrayDataProvider([
        'allModels' => $hasil,
        'pagination' => [
            'pageSize' => 10,
        ],
    ]);

   $model = new \yii\base\DynamicModel([
       'name',
   ]);

   $model->addRule(['name'], 'string'); 

   $hasil = [];
   if ($model->load(Yii::$app->request->post())) {
       $client = new Client();
       $response = $client->createRequest()
            ->setMethod('get')
            ->setUrl(END_POINT_ADDRESS_2')
            ->setData([
               'name' => $model->name,
                ])
            ->send();

            if ($response->isOk) {
                $hasil = json_decode($response->content);
            } 
    }
    return $this->render('find-one',[
        'model'=>$model,
        'results'=>$hasil,
        'dataProvider' => $dataProvider,
    ]); 
}   

You have to modify the END_POINT_ADDRESS_1 and END_POINT_ADDRESS_2 on the above code.

and at the top most must be add with these

use yii\httpclient\Client;
use yii\helpers\Json;
use yii\data\ArrayDataProvider;

END_POINT_ADDRESS_1 is end-point to display all data, END_POINT_ADDRESS_2 is end-point to display searched data only base on name.

In my case I have END_POINT_ADDRESS_1 as below:

public function actionList()
{

    \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;

    $query = new Query; 
    $query->select(['tabel_1.nocertificate AS Number', 'tabel_3.title AS Course', 'tabel_2.name AS Name', 'tabel_1.sex AS Gender', 'tabel_1.nationality AS Citizen'])  
            ->from('tabel_1')
            ->leftJoin('tabel_2', 'tabel_2.idcourse = tabel_1.course_id')
            ->leftJoin('tabel_3', 'courses.type = tabel_3.stdid')
            ->where(['tabel_1.approval'=>'Approved', 'tabel_1.result'=>'Pass', 'tabel_2.status' => 'Closed', 'tabel_1.fed_id' => 99])
            ->orderBy('tabel_2.date DESC');
                    
    $command = $query->createCommand();
    $certificates = $command->queryAll();
    
    $count = count($certificates);
    if($count>0){
        return array('status'=>true, 'results'=>$certificates);
    }
            
}

And END_POINT_ADDRESS_2 is as below:

public function actionView($name=0)
{

    \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;

    $query = new Query; 
    $query->select(['tabel_1.nocertificate AS Number', 'tabel_3.title AS Course', 'tabel_1.name AS Name', 'tabel_1.sex AS Gender', tabel_1.nationality AS Citizen'])  
            ->from('tabel_1')
            ->leftJoin('tabel_2', 'tabel_2.idcourse = tabel_1.course_id')
            ->leftJoin('tabel_3', 'tabel_2.type = tabel_3.stdid')
            ->where(['tabel_1.approval'=>'Approved', 'tabel_1.result'=>'Pass', 'tabel_2.status' => 'Closed', 'tabel_1.fed_id' => 99]) //, 
            ->andWhere(['LIKE', 'tabel_1.name', strtr($name,['%'=>'\%', '_'=>'\_', '\\'=>'\\\\']).'%', false]);
                    
    $command = $query->createCommand();
    $certificates = $command->queryAll();

    $count = count($certificates);
    if($count>0){
        return array('results'=>$certificates); 
    }         
}

You can see that the code ->andWhere([‘LIKE’, ‘tabel_1.name’, strtr($name,[’%’=>’%’, ‘_’=>’_’, ‘\’=>’\\’]).’%’, false]) is a condition that will make us could key in only part of name in the search box.

That’s it. Good luck…