# yii2-ledap

## Install

The preferred way to install this extension is through [composer](http://getcomposer.org/download/).

Either run:

```bash
composer require --prefer-dist ethercap/yii2-ledap "dev-master"
```

Or add to the require section of your `composer.json` file:

```
"ethercap/yii2-ledap": "dev-master"
```

## Usage

copy layout. you can edit the layout after copy.

```bash
cp vendor/ethercap/yii2-ledap/src/gii/layout.php xxx/views/layouts/main.php
```

### Code generator

the use of code generator is similar to gii/crud, let's begin:

```bash
php yii gii/ledapCrud --controllerClass="\frontend\controllers\TestController" --modelClass="common\models\Test" --searchModelClass="\frontend\forms\TestSearch"
```

After run, you can access the page. the page will be follow:

1. **xxController :** yii2 Controller to process http request.
2. **views/xx/\*.php :** the template file, which to rendering html.
3. **views/xx/\*.api :** the api file, which to rendering api.
4. **xx/web/xx/\*.js :** the js file of the view。it view be rendering in html with a hash.

the file structure as the following picture.

![](/files/-LloBhiYAwYE-nKKFmOE)

### List View

the javascript has a dataProvider(Note. it's not the php DataProvider) which  to control the page.&#x20;

#### 1.refresh on input

we can add an event on form-item to refresh on inputing. thus, when we input, the table will auto search and refresh.

```markup
<form-item :model="dp.searchModel" attr="name" @input="refresh('')"></form-item>
```

#### &#x20;2. Some DataProvider api

{% code title="index.js" %}

```javascript
// to get an DataProvider
this.dp = ledap.App.getWebDataProvider({

    httpOptions:{
        url:'/test/xxx',
        params:'ddd',
    }
    // can be ignore. the key to removal duplicate models 
    primaryKey: 'id',
    // can be ignore. to prevent a lot of http request, the min interval between two request
    // 0 represent no interval
    timeWait : 600,
});

// a dataprovider contains 4 sub object
// the search params of list page
console.log(this.dp.searchModel)
// the items show in list page
console.log(this.dp.models);
// the sort of list page
console.log(this.dp.sort);
// the pagination of list page
console.log(this.dp.pager);

//change any params and refresh
this.dp.searchModel.name = 'xxx';
this.dp.refresh();

// change params and refresh
this.dp.changeParams({name:"xxx"});

// changePage
this.dp.changePage(page)
this.dp.nextPage();
this.dp.prePage();

// we may want refresh as mobile
this.dp.refresh("header");
this.dp.refersh("footer");

// we may want sort table
this.dp.sort = "id, -name";
this.dp.refresh();
// we can also use function
this.dp.setSort("id,-name");

// we may want sort locally
this.dp.sortModels("name", asc=true);

// we can use isLoading to show loading status
this.dp.isLoading
// we can also use event to do something
this.dp.on(ledap.WebDataProvider.EVENT_BEFOREGETDATA, function(){
});
this.dp.on(ledap.WebDataProvider.EVENT_AFTERGETDATA, function(){
});
```

{% endcode %}

#### &#x20;3. grid

grid is a ledap component, which render by columns and dataProvider.

{% code title="index.js" %}

```javascript
columns : {
    'id',
    {
        'attribute' : 'id',
        'label' : 'ID',
        //if use sort, we can click header to sort table
        'userSort' : true, 
    },
    {
        'attribute' : 'name',
        'value' : function() {
            // vm refer to current vue component
            // value,model, index, attribute and dataProvider can be use in the template
            return '<a @click="vm.xxx(model)"></a>';
        },
        'format': 'html',
    }
}
```

{% endcode %}

if you're not satisfied with the default content. you can change the grid content by Vue scoped slot. the component will transfer 4 args to scoped slot:&#x20;

* **model**. current model, refer to the row of grid.
* **column**. current colomn, refer to the col of grid.
* **index**.  the index of dp.models. dp.model\[index] = model
* **value**. the result of the column calculate with the model.

{% code title="index.php" %}

```markup
<grid class="table" :data-provider="dp" :columns="columns">
    <template v-slot:label="p">
        <th class="xxx">{{p.value}}{{p.model}}{{p.index}}{{p.column}}</th>
    </template>

    <template v-slot:default="p">
        <td class="xxx">{{p.value}}{{p.model}}{{p.index}}{{p.column}}</td>
    </template>
</grid>
```

{% endcode %}

you can also use dataProvider without grid. like dataProvider with "list", or components all by self.

{% code title="index.php" %}

```markup
<input type="xxx" v-model="dp.searchModel.name" @input="dp.refresh('')" />
<div v-for="model in dp.models">
    <div class="">{{model.id}}</div>
    <div class="xxx">{{model.img}}</div>
</div>
<div class="pager">
    <div>total:{{dp.pager.currentPage}}|{{dp.pager.totalCount}}</div>
    <a @click="dp.prePage()">PrePage</a>
    <a @click="dp.nextPage()">NextPage</a>
</div>
```

{% endcode %}

### View\&Update\&Create

type is the switch of the page. it can be set to an item of \["view", "update", "create"].

#### 1.model

the model corresponding to the yii2  Form Model. let's begin:

{% code title="view\.js" %}

```javascript
//generate a model
let model = ledap.App.getModel(data);

// change model's value
model.name = "xxx";
// get label of attribute
model.getAttributeLabel("name");
// get hint of attribute
model.getAttributeHint("name");
// get error of attribute
model.getErrors("name");
// get first error of attribute
model.getFirstError("name");
// get All error of a model
model.getErrors();

// validate the value of model.if not correct, return false.
// we can use getErrors to show the error
model.validate();

```

{% endcode %}

#### 2.detail

detail is similar to grid. we can use columns to show a detail.the rule is  same to the grid.

{% code title="view\.js" %}

```javascript
columns : {
    'id',
    {
        'attribute' : 'id',
        'label' : 'ID',
        //if use sort, we can click header to sort table
        'userSort' : true, 
    },
    {
        'attribute' : 'name',
        'value' : function() {
            // vm refer to current vue component
            // value,model, index, attribute and dataProvider can be use in the template
            return '<a @click="vm.xxx(model)"></a>';
        },
        'format': 'html',
    }
}
```

{% endcode %}

&#x20;like grid, we can also use scoped slot to change the default view.

#### 3. form-item

when we want't to show form, the form-item is very import. the form-item contains 4 parts:

* label
* hint
* input
* error

we cant use like this:

{% code title="\_form.php" %}

```markup
<!-- 
    normal input
    validator: the event to validator,
 default is blur. 
    tag: the tag, default is div
-->
<form-item :model="model" attr="name" :validator="['input', 'blur', 'focus']" :tag="div">
</form-item>

<!-- we can also use scoped slot to change the default view-->
<form-item :model="model" attr="name">
    <template v-slot:label="p">
        <label> {{p.model.getAttributeLabel(p.attr)}}{{p.model.isRequired(p.attr) ? '*' : ''}}</label>
    </template>
    <template v-slot="p">
        <baseinput type="password" v-bind="p"></baseinput>
    </template>
    <template v-slot:error="p">
        <p v-show="p.showError">{{p.showError}}</p>
    </template>
</form-item>

<!-- some other input -->
<!-- 
    groupinput need DictValidator. you should add a rule in model like this:
    ['name', \ethercap\common\validators\DictValidator::className(), [0 => 'xxx', 1=> 'xxx', ...]],
    dropdown also need DictValidator.
    ajax select you should follow next chapter
-->
<form-item :model="model" attr="name">
    <template v-slot="p">
        <groupinput v-bind="p"></groupinput>
    </template>
</form-item>
<form-item :model="model" attr="name">
    <template v-slot="p">
        <dropdown v-bind="p"></dropdown>
    </template>
</form-item>
```

{% endcode %}

Sometimes, we may want use Other's Vue Component. So I did an example in this package.

I use an [vue2-datepickerr ](https://www.npmjs.com/package/vue2-datepicker) to show the code.

{% code title="\_form.php" %}

```php
<?php
// or we can use register
// $this->registerJs("http://xxxx.js", ['depends' => '\ethercap\ledap\assets\VueAsset'])
\ethercap\ledap\assets\DatePickerAsset::register($this);
?>

<form-item :model="model" attr="time">
    <template v-slot="p">
        <date-picker v-model="p.model[p.attr]" :value-type="'format'"></date-picker>
    </template>
</form-item>

```

{% endcode %}

we should register the Component in view\.js

{% code title="view\.js" %}

```javascript
Vue.Comonpoent("date-picker", DatePicker.default);
```

{% endcode %}

### Other

#### 1.select2 & SearchAction

sometimes we want use a ajax suggestion like select2. the package offer you follows:

* SearchAction: a php Action to process the request.

```php
<?php
namespace frontend\controllers;
use Yii;
class xxController extends Controller
{
    // ....
    
    public function actions()
    {
        return [
            'search' => [
                'class' => \ethercap\ledap\actions\SearchAction::className(),
                'processQuery' => function($model) {
                     $query = xxx::find()->select(['id', 'name as text'])->asArray();
                     if($model->id) {
                         return $query->where(['id' => $model->id]);
                     }
                     if($model->keyword){
                         $query->andWhere(['like', 'name', $model->keyword]);                         
                     }
                     return $query;
                },
                // you can ignore this config
                $dataConfig => [
                    'id',
                    'text'
                ]
            ],
        ];
    } 

}
```

after all this config, we have an api "/xx/search" to search data from database.

* select2 component: vue component to send http request.

{% code title="\_form.php" %}

```markup
<form-item :model="model" attr="search">
    <template v-slot="p">
        <select2 v-bind="p" :data-provider="dp"></select2>
    </template>
</form-item>
```

{% endcode %}

{% code title="view\.js" %}

```javascript
{
    data:{
        dp: App.ledap.getWebDp({
            httpOptions:{
                "url" : '/xx/search'
            }
        });
    }
}
```

{% endcode %}

#### 2.upload & UploadAction

to be continued.

### Tips

1. be aware of Vue.
2. do not use yii2 widget.
3. all component you use should register first.  App.register(\['xxx'], Vue);
4. you can use other component.&#x20;
5. you can change the request by replace AppAsset.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ethercap.gitbook.io/ledap/yii2-ledap.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
