After Width: | Height: | Size: 49 KiB |
After Width: | Height: | Size: 39 KiB |
After Width: | Height: | Size: 39 KiB |
After Width: | Height: | Size: 84 KiB |
After Width: | Height: | Size: 53 KiB |
After Width: | Height: | Size: 59 KiB |
After Width: | Height: | Size: 55 KiB |
After Width: | Height: | Size: 64 KiB |
After Width: | Height: | Size: 50 KiB |
After Width: | Height: | Size: 32 KiB |
@ -0,0 +1,213 @@
|
||||
创建表单 |
||||
==== |
||||
|
||||
基于活动记录(ActiveRecord)的表单:ActiveForm |
||||
----------------------- |
||||
在yii中使用表单的主要方式是通过[[yii\widgets\ActiveForm]]。当某个表单是基于一个模型时,应该首选这种方式。此外,在[[yii\helpers\Html]]中有很多实用的方法为表单添加按钮和帮助文档。 |
||||
|
||||
在客户端显示的表单,大多数情况下都有一个相应的[模型](structure-models.md),用来在服务器上验证其输入的数据(可在[输入验证](input-validation.md)一节获取关于验证的细节)。当创建一个基于模型的表单时,第一步是定义模型本身。该模型可以是一个基于[活动记录](db-active-record.md)的类,表示数据库中的数据,也可以是一个基于通用模型的类(继承自[[yii\base\Model]]),来获取任意的输入数据,如登录表单。 |
||||
|
||||
> Tip: 如果一个表单的输入域与数据库的字段不匹配,或者它存在只适用于它的特殊的格式或者方法,则最好为它创建一个单独的继承自[[yii\base\Model]]的模型。 |
||||
|
||||
在接下来的例子中,我们展示了通用模型如何用于登录表单: |
||||
|
||||
```php |
||||
<?php |
||||
|
||||
class LoginForm extends \yii\base\Model |
||||
{ |
||||
public $username; |
||||
public $password; |
||||
|
||||
public function rules() |
||||
{ |
||||
return [ |
||||
// 在这里定义验证规则 |
||||
]; |
||||
} |
||||
} |
||||
``` |
||||
|
||||
在控制器中,我们将传递一个模型是实例到视图,其中[[yii\widgets\ActiveForm|ActiveForm]]小部件将用来显示表单。 |
||||
|
||||
```php |
||||
<?php |
||||
use yii\helpers\Html; |
||||
use yii\widgets\ActiveForm; |
||||
|
||||
$form = ActiveForm::begin([ |
||||
'id' => 'login-form', |
||||
'options' => ['class' => 'form-horizontal'], |
||||
]) ?> |
||||
<?= $form->field($model, 'username') ?> |
||||
<?= $form->field($model, 'password')->passwordInput() ?> |
||||
|
||||
<div class="form-group"> |
||||
<div class="col-lg-offset-1 col-lg-11"> |
||||
<?= Html::submitButton('Login', ['class' => 'btn btn-primary']) ?> |
||||
</div> |
||||
</div> |
||||
<?php ActiveForm::end() ?> |
||||
``` |
||||
|
||||
### 用 `begin()` 和 `end()` 包裹 <span id="wrapping-with-begin-and-end"></span> |
||||
|
||||
在上面的代码中,[[yii\widgets\ActiveForm::begin()|ActiveForm::begin()]] 不仅创建了一个表单实例,同时也标志的表单的开始。所有在[[yii\widgets\ActiveForm::begin()|ActiveForm::begin()]]与[[yii\widgets\ActiveForm::end()|ActiveForm::end()]]之中的内容都会被HTML中的 `<form>`标签包裹。与其他小部件一样,你可以制定一些选项,通过传递数组到到 `begin` 中来配置小部件。在这种情况下,一个额外的CSS类和ID会在 `<form>` 标签中使用。要查看更多可用的选项,请查看API文档的 [[yii\widgets\ActiveForm]]。 |
||||
|
||||
### ActiveField <span id="activefield"></span> |
||||
|
||||
为了在表单中创建表单元素与元素的标签,以及任意适用的Javascript验证,需要使用[[yii\widgets\ActiveForm::field()]|ActiveForm::field()]方法,其返回一个[[yii\widgets\ActiveField]]实例。当直接输出该方法时,结果是一个普通的(文本)输入。要自定义输出,可以附加上[[yii\widgets\ActiveField|ActiveField]]的其他方法来一起调用: |
||||
|
||||
```php |
||||
// 密码输入框 |
||||
<?= $form->field($model, 'password')->passwordInput() ?> |
||||
// 增加提示与自定义标签 |
||||
<?= $form->field($model, 'username')->textInput()->hint('Please enter your name')->label('Name') ?> |
||||
// 创建一个HTML5邮件输入元素 |
||||
<?= $form->field($model, 'email')->input('email') ?> |
||||
``` |
||||
|
||||
它会通过[[yii\widgets\ActiveField|ActiveField]]中定义的表单字段来创建`<label>`,`<input>`以及其他标签。input输入框的name属性会自动的根据[[yii\base\Model::formName()| form name]] 以及属性来来创建。例如,对于上面例子中的`username`输入字段的name属性将是`LoginForm[username]`。这种命名方式会使登录表单的所有属性在服务器端的`$_POST['LoginForm']`数组中是可用。 |
||||
|
||||
> Tip:如果你在一个表单中只有一个模型,并且想要简化input输入名称,你可以覆盖模型的[[yii\base\Model::formName()|formName()]]方法,使其返回一个空的字符串,以此来跳过数组部分。这在[GridView](output-data-widgets.md#grid-view)的过滤模型创建更好的URLs时是非常有用的。 |
||||
|
||||
指定模型是属性时可以以更复杂的方式来完成。比如,当上传多个文件时,或者选择多个多个项目时,可能会需要一个数组值,你可以通过附加`[]`来指定它的属性名称: |
||||
|
||||
```php |
||||
// allow multiple files to be uploaded: |
||||
echo $form->field($model, 'uploadFile[]')->fileInput(['multiple'=>'multiple']); |
||||
|
||||
// allow multiple items to be checked: |
||||
echo $form->field($model, 'items[]')->checkboxList(['a' => 'Item A', 'b' => 'Item B', 'c' => 'Item C']); |
||||
``` |
||||
|
||||
命名表单元素,如提交按钮时需要小心。在[JQuery](https://api.jquery.com/submit/)中有一些保留名词,可能会导致冲突: |
||||
|
||||
> 表单和它们的子元素不应该使用与表单的属性冲突的input name或id,例如submit,length,或者 method。 要检查你的标签是否存在这些问题,一个完整的规则列表详见 DOMLint。 |
||||
|
||||
将额外的HTML标签添加到表单中可以通过使用纯HTML或者使用[[yii\helpers\Html|Html]]的方法,比如上述例子中的帮助类的做法[[yii\helpers\Html::submitButton()|Html::submitButton()]]。 |
||||
|
||||
> Tip:如果你的应用程序正在使用Twitter的Bootstrap CSS样式,你可以选择使用[[yii\bootstrap\ActiveForm]]代替[[yii\widgets\ActiveForm]],这个表单继承自后者,并且使用Bootstrap特有的样式初始化表单的输入框。 |
||||
|
||||
> Tip: 为了使用星号对必填字段进行样式,你可以使用下面的CSS样式: |
||||
> |
||||
> ```css |
||||
> div.required label.control-label:after { |
||||
> content: " *"; |
||||
> color: red; |
||||
> } |
||||
> ``` |
||||
|
||||
创建列表 <span id="creating-activeform-lists"></span> |
||||
----------------------- |
||||
|
||||
这里有3中类型的列表: |
||||
|
||||
- 下拉列表 |
||||
- 单选列表 |
||||
- 多选列表 |
||||
|
||||
为了创建列表,你必须先为它准备选项。这些选项可以手动准备如下: |
||||
|
||||
```php |
||||
$items = [ |
||||
1 => 'item 1', |
||||
2 => 'item 2' |
||||
] |
||||
``` |
||||
|
||||
或者直接从数据库中检索: |
||||
|
||||
```php |
||||
$items = Category::find() |
||||
->select(['label']) |
||||
->indexBy('id') |
||||
->column(); |
||||
``` |
||||
|
||||
这些 `$items` 必须能被不同的列表组件处理。列表输入框的值(以及当前选中的选项)将会根据当前`$model`的属性的值而自动的生成。 |
||||
|
||||
#### 创建一个下拉选择列表 :<span id="creating-activeform-dropdownlist"></span> |
||||
|
||||
我们可以使用活动领域的[[yii\widgets\ActiveField::dropDownList()]] 方法来创建一个下拉列表: |
||||
|
||||
```php |
||||
/* @var $form yii\widgets\ActiveForm */ |
||||
|
||||
echo $form->field($model, 'category')->dropdownList([ |
||||
1 => 'item 1', |
||||
2 => 'item 2' |
||||
], |
||||
['prompt'=>'Select Category'] |
||||
); |
||||
``` |
||||
|
||||
#### 创建一个单选列表 :<span id="creating-activeform-radioList"></span> |
||||
|
||||
我们可以使用活动领域的[[yii\widgets\ActiveField::radioList()]] 方法来创建一个下拉列表: |
||||
|
||||
```php |
||||
/* @var $form yii\widgets\ActiveForm */ |
||||
|
||||
echo $form->field($model, 'category')->radioList([ |
||||
1 => 'radio 1', |
||||
2 => 'radio 2' |
||||
]); |
||||
``` |
||||
|
||||
#### 创建一个多选列表: <span id="creating-activeform-checkboxList"></span> |
||||
|
||||
我们可以使用活动领域的[[yii\widgets\ActiveField::checkboxList()]] 方法来创建一个下拉列表: |
||||
|
||||
```php |
||||
/* @var $form yii\widgets\ActiveForm */ |
||||
|
||||
echo $form->field($model, 'category')->checkboxList([ |
||||
1 => 'checkbox 1', |
||||
2 => 'checkbox 2' |
||||
]); |
||||
``` |
||||
|
||||
使用Pjax <span id="working-with-pjax"></span> |
||||
----------------------- |
||||
|
||||
[[yii\widgets\Pjax|Pjax]]组件允许你更新一个页面的某些部分而不用从新加载整个页面。你可以在提交表单后使用Pjax来更新表单,或者替换表单的某些内容。 |
||||
|
||||
你可以配置[[yii\widgets\Pjax::$formSelector|$formSelector]]来指定那些表单的提交会触发pjax。如果你没有设置,所有包含`data-pjax`属性,并且含有封闭的Pjax内容的表单,将会触发pjax请求。 |
||||
|
||||
```php |
||||
use yii\widgets\Pjax; |
||||
use yii\widgets\ActiveForm; |
||||
|
||||
Pjax::begin([ |
||||
// Pjax options |
||||
]); |
||||
$form = ActiveForm::begin([ |
||||
'options' => ['data' => ['pjax' => true]], |
||||
// more ActiveForm options |
||||
]); |
||||
|
||||
// ActiveForm content |
||||
|
||||
ActiveForm::end(); |
||||
Pjax::end(); |
||||
``` |
||||
|
||||
> Tip: 注意小心[[yii\widgets\Pjax|Pjax]]内部的链接,因为响应仍可能在组件内部呈现。为了避免这种现象,可以使用`data-pjax="0"`这个HTML属性。 |
||||
|
||||
#### 提交按钮和文件上传 |
||||
|
||||
由于`JQuery.serializeArray()`在处理[文件内容](https://github.com/jquery/jquery/issues/2321)和[提交按钮的值](https://github.com/jquery/jquery/issues/2321)时存在已知的问题,同时也为了推广`FormData`在HTML5中的使用,它将直接被弃用而不是等待修复。 |
||||
|
||||
这意味着官方对`FormData`在文件上传,ajax提交按钮的值以及组件[[yii\widgets\Pjax]]的使用上取决于[浏览器](https://developer.mozilla.org/en-US/docs/Web/API/FormData#Browser_compatibility)的支持。 |
||||
|
||||
扩展阅读 <span id="further-reading"></span> |
||||
--------------- |
||||
|
||||
下一节 [输入验证](input-validation.md) 处理提交的表单数据的服务器端验证, 以及 ajax- 和客户端验证。 |
||||
|
||||
要学会有关表格的更复杂的用法,你可以查看以下几节: |
||||
|
||||
- [收集列表输入](input-tabular-input.md) 同一种类型的多个模型的采集数据。 |
||||
- [多模型同时输入](input-multiple-models.md) 在同一窗口中处理多个不同的模型。 |
||||
- [文件上传](input-file-upload.md) 如何使用表格来上传文件。 |
@ -1,35 +1,77 @@
|
||||
多模型的复合表单 |
||||
================================== |
||||
|
||||
在复杂的用户界面可能会发生,用户在表单中填写数据 |
||||
后将其保存在数据库的不同表中。yii形式的表单与单模型表单相比 |
||||
可以让你用更加简单的方法来创建。 |
||||
当处理负载的数据时,可能会发生需要使用多个模型来收集用户的输入。例如,假设用户登录信息保存在`user`表中,但是用户详细信息却保存在`profile`表中,你也许会使用`User`模型和`Profile`模型来接受用户的输入。在Yii模型与表单的支持下,你可以非常方便用不同于单个模型的方式来解决该问题。 |
||||
|
||||
与一个模型一样,你遵循以下模式用于服务端验证: |
||||
接下来,我们会使用一个例子阐述如何创建一个表单,它允许你同时为`User`和`Profile`模型收集数据。 |
||||
|
||||
1. 实例化模型类 |
||||
2. 用输入数据填充模型属性 |
||||
3. 验证所有模型 |
||||
4. 如果所有模型验证通过,则保存它们 |
||||
5. 如果验证失败或没有提交数据,传递所有模型对象到视图显示表单 |
||||
首先,控制user和profile接收数据的控制器如下: |
||||
|
||||
在下文中我们展示了一个在表单中使用多模型的例子... TBD |
||||
```php |
||||
namespace app\controllers; |
||||
|
||||
多模型实例 |
||||
--------------- |
||||
use Yii; |
||||
use yii\base\Model; |
||||
use yii\web\Controller; |
||||
use yii\web\NotFoundHttpException; |
||||
use app\models\User; |
||||
use app\models\Profile; |
||||
|
||||
> Note: This section is under development. |
||||
> |
||||
> It has no content yet. |
||||
class UserController extends Controller |
||||
{ |
||||
public function actionUpdate($id) |
||||
{ |
||||
$user = User::findOne($id); |
||||
if (!$user) { |
||||
throw new NotFoundHttpException("The user was not found."); |
||||
} |
||||
|
||||
$profile = Profile::findOne($user->profile_id); |
||||
|
||||
if (!$profile) { |
||||
throw new NotFoundHttpException("The user has no profile."); |
||||
} |
||||
|
||||
$user->scenario = 'update'; |
||||
$profile->scenario = 'update'; |
||||
|
||||
if ($user->load(Yii::$app->request->post()) && $profile->load(Yii::$app->request->post())) { |
||||
$isValid = $user->validate(); |
||||
$isValid = $profile->validate() && $isValid; |
||||
if ($isValid) { |
||||
$user->save(false); |
||||
$profile->save(false); |
||||
return $this->redirect(['user/view', 'id' => $id]); |
||||
} |
||||
} |
||||
|
||||
return $this->render('update', [ |
||||
'user' => $user, |
||||
'profile' => $profile, |
||||
]); |
||||
} |
||||
} |
||||
``` |
||||
|
||||
TBD |
||||
在`update`动作中,我们首先加载`$user`和`$profile`模型并设置他们为更新模式。然后我们使用[[yii\base\Model::load()]]方法将用户输入的数据填充到模型中。如果数据顺利填充了,我们会验证这两个模型之后在保存它们。但是,请注意我们使用了`save(false)`来避免验证通过的数据在模型中被重复验证。如果填充不成功,我们将会显示下面的`update`视图: |
||||
|
||||
Dependend models |
||||
---------------- |
||||
```php |
||||
<?php |
||||
use yii\helpers\Html; |
||||
use yii\widgets\ActiveForm; |
||||
|
||||
$form = ActiveForm::begin([ |
||||
'id' => 'user-update-form', |
||||
'options' => ['class' => 'form-horizontal'], |
||||
]) ?> |
||||
<?= $form->field($user, 'username') ?> |
||||
|
||||
> Note: This section is under development. |
||||
> |
||||
> It has no content yet. |
||||
...other input fields... |
||||
|
||||
<?= $form->field($profile, 'website') ?> |
||||
|
||||
TBD |
||||
<?= Html::submitButton('Update', ['class' => 'btn btn-primary']) ?> |
||||
<?php ActiveForm::end() ?> |
||||
``` |
||||
|
||||
如上,在`update`视图中你需要给予输入框两个模型`$user`和`$profile`。 |
@ -0,0 +1,118 @@
|
||||
请求 |
||||
=== |
||||
|
||||
应用的请求使用 [[yii\web\Request]] 对象来表示,它提供了请求参数、HTTP 头、cookie 等信息。 |
||||
对于一个给定的请求,你可以通过 `request` [应用组件](structure-application-components.md) 来访问,默认情况下它是 [[yii\web\Request]] 的实例。在本节中,我们将介绍如何在应用中使用此组件。 |
||||
|
||||
## 请求参数 <span id="request-parameters"></span> |
||||
|
||||
你可以通过 `request` 组件的 [[yii\web\Request::get()|get()]] 和 [[yii\web\Request::post()|post()]] 方法来获取请求参数。 |
||||
它分别返回 `$_GET` 和 `$_POST` 的值。例如: |
||||
|
||||
```php |
||||
$request = Yii::$app->request; |
||||
|
||||
$get = $request->get(); |
||||
// equivalent to: $get = $_GET; |
||||
|
||||
$id = $request->get('id'); |
||||
// equivalent to: $id = isset($_GET['id']) ? $_GET['id'] : null; |
||||
|
||||
$id = $request->get('id', 1); |
||||
// equivalent to: $id = isset($_GET['id']) ? $_GET['id'] : 1; |
||||
|
||||
$post = $request->post(); |
||||
// equivalent to: $post = $_POST; |
||||
|
||||
$name = $request->post('name'); |
||||
// equivalent to: $name = isset($_POST['name']) ? $_POST['name'] : null; |
||||
|
||||
$name = $request->post('name', ''); |
||||
// equivalent to: $name = isset($_POST['name']) ? $_POST['name'] : ''; |
||||
``` |
||||
|
||||
> Info: 推荐上面的方式使用 `request` 组件来获取请求参数而不是直接使用 `$_GET` 和 `$_POST`。这将使编写测试变得更容易,因为您可以创建一个带有伪造请求数据的模拟请求组件。 |
||||
|
||||
在实现 [RESTful APIs](rest-quick-start.md) 是,你通常会需要获取 PUT、PATCH 或其他 [请求方法](#request-methods) 提交的参数. |
||||
你可以通过调用 [[yii\web\Request::getBodyParam()]] 方法来获取。例如: |
||||
|
||||
```php |
||||
$request = Yii::$app->request; |
||||
|
||||
// returns all parameters |
||||
$params = $request->bodyParams; |
||||
|
||||
// returns the parameter "id" |
||||
$param = $request->getBodyParam('id'); |
||||
``` |
||||
|
||||
> Info: 和 `GET` 参数不同,通过 `POST`、`PUT`、`PATCH` 等提交的参数实在请求体中发送。 |
||||
当使用上述方式访问它们时, `request` 组件将解析这些参数。 |
||||
你可以通过配置 [[yii\web\Request::parsers]] 属性来自定义解析这些参数的方式。 |
||||
|
||||
## 请求方法 <span id="request-methods"></span> |
||||
|
||||
你可以通过 `Yii::$app->request->method` 来获取当前请求使用的 HTTP 请求方法。 |
||||
`request` 还提供了一组布尔属性,用来检查当前请求是否具有某种类型。例如: |
||||
|
||||
```php |
||||
$request = Yii::$app->request; |
||||
|
||||
if ($request->isAjax) { /* the request is an AJAX request */ } |
||||
if ($request->isGet) { /* the request method is GET */ } |
||||
if ($request->isPost) { /* the request method is POST */ } |
||||
if ($request->isPut) { /* the request method is PUT */ } |
||||
``` |
||||
|
||||
## 请求 URLs <span id="request-urls"></span> |
||||
|
||||
`request` 组件提供了许多检查当前请求地址的方法。 |
||||
|
||||
如果被请求的 URL 是 `http://example.com/admin/index.php/product?id=100`,您可以得到以下内容的不同部分: |
||||
|
||||
* [[yii\web\Request::url|url]]: 返回 `/admin/index.php/product?id=100`, 没有 host info 部分的 URL。 |
||||
* [[yii\web\Request::absoluteUrl|absoluteUrl]]: 返回 `http://example.com/admin/index.php/product?id=100`,包含 host info 的完整 URL 地址。 |
||||
* [[yii\web\Request::hostInfo|hostInfo]]: 返回 `http://example.com`,URL 的 host info 部分。 |
||||
* [[yii\web\Request::pathInfo|pathInfo]]: 返回 `/product`,在脚本和问号(查询字符串)之间的部分。 |
||||
* [[yii\web\Request::queryString|queryString]]: 返回 `id=100`,问号后面的部分。 |
||||
* [[yii\web\Request::baseUrl|baseUrl]]: 返回 `/admin`,在 host info 和脚本名称之间的部分。 |
||||
* [[yii\web\Request::scriptUrl|scriptUrl]]: 返回 `/admin/index.php`,不包含 host info 和 查询字符串的部分。 |
||||
* [[yii\web\Request::serverName|serverName]]: 返回 `example.com`,URL 中的主机名。 |
||||
* [[yii\web\Request::serverPort|serverPort]]: 返回 80,WEB 服务器使用的端口。 |
||||
|
||||
|
||||
## HTTP 头信息 <span id="http-headers"></span> |
||||
|
||||
你可以通过 [[yii\web\Request::headers]] 返回的 [[yii\web\HeaderCollection|header collection]] 属性来获取 HTTP 头信息。例如: |
||||
|
||||
```php |
||||
// $headers is an object of yii\web\HeaderCollection |
||||
$headers = Yii::$app->request->headers; |
||||
|
||||
// returns the Accept header value |
||||
$accept = $headers->get('Accept'); |
||||
|
||||
if ($headers->has('User-Agent')) { /* there is User-Agent header */ } |
||||
``` |
||||
|
||||
`请求` 组件还支持快速访问一些常用的头信息,包括: |
||||
|
||||
* [[yii\web\Request::userAgent|userAgent]]: 返回 `User-Agent` 的头信息的值。 |
||||
* [[yii\web\Request::contentType|contentType]]: 返回 `Content-Type` 的头信息的值,它表示请求请求主体中数据的 MIME 类型。 |
||||
* [[yii\web\Request::acceptableContentTypes|acceptableContentTypes]]: 返回用户可以接受的内容 MIME 类型。返回类型根据它们的评分。高评分的类型首先返回。 |
||||
* [[yii\web\Request::acceptableLanguages|acceptableLanguages]]: 返回用户可接受的语言。返回的语言是由它们的优先级排序的。第一个元素表示最优先的语言。 |
||||
|
||||
如果您的应用支持多语言,并且你想根据是最终用户语言显示页面的语言。你可以通过语言协商方法 [[yii\web\Request::getPreferredLanguage()]] 来设置。 |
||||
|
||||
此方法将你的应用支持的语言列表和 [[yii\web\Request::acceptableLanguages|acceptableLanguages]] 进行对比来返回合适的语言。 |
||||
|
||||
> Tip: 同样,你可以使用 [[yii\filters\ContentNegotiator|ContentNegotiator]] 过滤器来动态决定响应中应该使用的内容类型和语言。这个过滤器实现了上述属性和方法中的内容协商。 |
||||
|
||||
## 客户端信息 <span id="client-information"></span> |
||||
|
||||
你可以分别通过 [[yii\web\Request::userHost|userHost]] 和 [[yii\web\Request::userIP|userIP]] 来获取客户端机器的机器名和 IP 地址。例如: |
||||
|
||||
```php |
||||
$userHost = Yii::$app->request->userHost; |
||||
$userIP = Yii::$app->request->userIP; |
||||
``` |
@ -0,0 +1,202 @@
|
||||
Extending ActiveForm on the Client Side |
||||
======================================= |
||||
|
||||
The [[yii\widgets\ActiveForm]] widget comes with a set of JavaScript methods that are used for client validation. |
||||
Its implementation is very flexible and allows you to extend it in different ways. |
||||
In the following these are described. |
||||
|
||||
## ActiveForm events |
||||
|
||||
ActiveForm triggers a series of dedicated events. Using the code like the following you can subscribe to these |
||||
events and handle them: |
||||
|
||||
```javascript |
||||
$('#contact-form').on('beforeSubmit', function (e) { |
||||
if (!confirm("Everything is correct. Submit?")) { |
||||
return false; |
||||
} |
||||
return true; |
||||
}); |
||||
``` |
||||
|
||||
In the following we'll review events available. |
||||
|
||||
### `beforeValidate` |
||||
|
||||
`beforeValidate` is triggered before validating the whole form. |
||||
|
||||
The signature of the event handler should be: |
||||
|
||||
```javascript |
||||
function (event, messages, deferreds) |
||||
``` |
||||
|
||||
where |
||||
|
||||
- `event`: an Event object. |
||||
- `messages`: an associative array with keys being attribute IDs and values being error message arrays |
||||
for the corresponding attributes. |
||||
- `deferreds`: an array of Deferred objects. You can use `deferreds.add(callback)` to add a new |
||||
deferred validation. |
||||
|
||||
If the handler returns a boolean `false`, it will stop further form validation after this event. And as |
||||
a result, `afterValidate` event will not be triggered. |
||||
|
||||
### `afterValidate` |
||||
|
||||
`afterValidate` event is triggered after validating the whole form. |
||||
|
||||
The signature of the event handler should be: |
||||
|
||||
```javascript |
||||
function (event, messages, errorAttributes) |
||||
``` |
||||
|
||||
where |
||||
|
||||
- `event`: an Event object. |
||||
- `messages`: an associative array with keys being attribute IDs and values being error message arrays |
||||
for the corresponding attributes. |
||||
- `errorAttributes`: an array of attributes that have validation errors. Please refer to |
||||
`attributeDefaults` for the structure of this parameter. |
||||
|
||||
### `beforeValidateAttribute` |
||||
|
||||
`beforeValidateAttribute` event is triggered before validating an attribute. |
||||
The signature of the event handler should be: |
||||
|
||||
```javascript |
||||
function (event, attribute, messages, deferreds) |
||||
``` |
||||
|
||||
where |
||||
|
||||
- `event`: an Event object. |
||||
- `attribute`: the attribute to be validated. Please refer to `attributeDefaults` for the structure |
||||
of this parameter. |
||||
- `messages`: an array to which you can add validation error messages for the specified attribute. |
||||
- `deferreds`: an array of Deferred objects. You can use `deferreds.add(callback)` to add |
||||
a new deferred validation. |
||||
|
||||
If the handler returns a boolean `false`, it will stop further validation of the specified attribute. |
||||
And as a result, `afterValidateAttribute` event will not be triggered. |
||||
|
||||
### `afterValidateAttribute` |
||||
|
||||
`afterValidateAttribute` event is triggered after validating the whole form and each attribute. |
||||
|
||||
The signature of the event handler should be: |
||||
|
||||
```javascript |
||||
function (event, attribute, messages) |
||||
``` |
||||
|
||||
where |
||||
|
||||
- `event`: an Event object. |
||||
- `attribute`: the attribute being validated. Please refer to `attributeDefaults` for the structure |
||||
of this parameter. |
||||
- `messages`: an array to which you can add additional validation error messages for the specified |
||||
attribute. |
||||
|
||||
### `beforeSubmit` |
||||
|
||||
`beforeSubmit` event is triggered before submitting the form after all validations have passed. |
||||
|
||||
The signature of the event handler should be: |
||||
|
||||
```javascript |
||||
function (event) |
||||
``` |
||||
|
||||
where event is an Event object. |
||||
|
||||
If the handler returns a boolean `false`, it will stop form submission. |
||||
|
||||
### `ajaxBeforeSend` |
||||
|
||||
`ajaxBeforeSend` event is triggered before sending an AJAX request for AJAX-based validation. |
||||
|
||||
The signature of the event handler should be: |
||||
|
||||
```javascript |
||||
function (event, jqXHR, settings) |
||||
``` |
||||
|
||||
where |
||||
|
||||
- `event`: an Event object. |
||||
- `jqXHR`: a jqXHR object |
||||
- `settings`: the settings for the AJAX request |
||||
|
||||
### `ajaxComplete` |
||||
|
||||
`ajaxComplete` event is triggered after completing an AJAX request for AJAX-based validation. |
||||
|
||||
The signature of the event handler should be: |
||||
|
||||
```javascript |
||||
function (event, jqXHR, textStatus) |
||||
``` |
||||
|
||||
where |
||||
|
||||
- `event`: an Event object. |
||||
- `jqXHR`: a jqXHR object |
||||
- `textStatus`: the status of the request ("success", "notmodified", "error", "timeout", |
||||
"abort", or "parsererror"). |
||||
|
||||
## Submitting the form via AJAX |
||||
|
||||
While validation can be made on client side or via AJAX request, the form submission itself is done |
||||
as a normal request by default. If you want the form to be submitted via AJAX, you can achieve this |
||||
by handling the `beforeSubmit` event of the form in the following way: |
||||
|
||||
```javascript |
||||
var $form = $('#formId'); |
||||
$form.on('beforeSubmit', function() { |
||||
var data = $form.serialize(); |
||||
$.ajax({ |
||||
url: $form.attr('action'), |
||||
type: 'POST', |
||||
data: data, |
||||
success: function (data) { |
||||
// Implement successful |
||||
}, |
||||
error: function(jqXHR, errMsg) { |
||||
alert(errMsg); |
||||
} |
||||
}); |
||||
return false; // prevent default submit |
||||
}); |
||||
``` |
||||
|
||||
To learn more about the jQuery `ajax()` function, please refer to the [jQuery documentation](https://api.jquery.com/jQuery.ajax/). |
||||
|
||||
|
||||
## Adding fields dynamically |
||||
|
||||
In modern web applications you often have the need of changing a form after it has been displayed to the user. |
||||
This can for example be the addition of new fields after click on a "plus"-icon. |
||||
To enable client validation for these fields, they have to be registered with the ActiveForm JavaScript plugin. |
||||
|
||||
You have to add a field itself and then add it to validation list: |
||||
|
||||
```javascript |
||||
$('#contact-form').yiiActiveForm('add', { |
||||
id: 'address', |
||||
name: 'address', |
||||
container: '.field-address', |
||||
input: '#address', |
||||
error: '.help-block', |
||||
validate: function (attribute, value, messages, deferred, $form) { |
||||
yii.validation.required(value, messages, {message: "Validation Message Here"}); |
||||
} |
||||
}); |
||||
``` |
||||
|
||||
To remove a field from validation list so it's not validated you can do the following: |
||||
|
||||
```javascript |
||||
$('#contact-form').yiiActiveForm('remove', 'address'); |
||||
``` |
@ -0,0 +1,210 @@
|
||||
# Using Yii as a Micro-framework |
||||
|
||||
Yii can be easily used without the features included in basic and advanced templates. In other words, Yii is already a micro-framework. It is not required to have the directory structure provided by templates to work with Yii. |
||||
|
||||
This is especially handy when you do not need all the pre-defined template code like assets or views. One of such cases is building a JSON API. In the following sections will show how to do that. |
||||
|
||||
## Installing Yii |
||||
|
||||
Create a directory for your project files and change working directory to that path. Commands used in examples are Unix-based but similar commands exist in Windows. |
||||
|
||||
```bash |
||||
mkdir micro-app |
||||
cd micro-app |
||||
``` |
||||
|
||||
> Note: A little bit of Composer knowledge is required to continue. If you don't know how to use composer yet, please take time to read [Composer Guide](https://getcomposer.org/doc/00-intro.md). |
||||
|
||||
Create file `composer.json` under the `micro-app` directory using your favorite editor and add the following: |
||||
|
||||
```json |
||||
{ |
||||
"require": { |
||||
"yiisoft/yii2": "~2.0.0" |
||||
}, |
||||
"repositories": [ |
||||
{ |
||||
"type": "composer", |
||||
"url": "https://asset-packagist.org" |
||||
} |
||||
] |
||||
} |
||||
``` |
||||
|
||||
Save the file and run the `composer install` command. This will install the framework with all its dependencies. |
||||
|
||||
## Creating the Project Structure |
||||
|
||||
After you have installed the framework, it's time to create an [entry point](structure-entry-scripts.md) for the application. Entry point is the very first file that will be executed when you try to open your application. For the security reasons, it is recommended to put the entrypoint file in a separate directory and make it a web root. |
||||
|
||||
Create a `web` directory and put `index.php` inside with the following content: |
||||
|
||||
```php |
||||
<?php |
||||
|
||||
// comment out the following two lines when deployed to production |
||||
defined('YII_DEBUG') or define('YII_DEBUG', true); |
||||
defined('YII_ENV') or define('YII_ENV', 'dev'); |
||||
|
||||
require(__DIR__ . '/../vendor/autoload.php'); |
||||
require(__DIR__ . '/../vendor/yiisoft/yii2/Yii.php'); |
||||
|
||||
$config = require __DIR__ . '/../config.php'; |
||||
(new yii\web\Application($config))->run(); |
||||
``` |
||||
|
||||
Also create a file named `config.php` which will contain all application configuration: |
||||
|
||||
```php |
||||
<?php |
||||
return [ |
||||
'id' => 'micro-app', |
||||
// the basePath of the application will be the `micro-app` directory |
||||
'basePath' => __DIR__, |
||||
// this is where the application will find all controllers |
||||
'controllerNamespace' => 'micro\controllers', |
||||
// set an alias to enable autoloading of classes from the 'micro' namespace |
||||
'aliases' => [ |
||||
'@micro' => __DIR__, |
||||
], |
||||
]; |
||||
``` |
||||
|
||||
> Info: Even though the configuration could be kept in the `index.php` file it is recommended |
||||
> to have it separately. This way it can be used for console application also as it is shown below. |
||||
|
||||
Your project is now ready for coding. Although it's up to you to decide the project directory structure, as long as you observe namespaces. |
||||
|
||||
## Creating the first Controller |
||||
|
||||
Create a `controllers` directory and add a file `SiteController.php`, which is the default |
||||
controller that will handle a request with no path info. |
||||
|
||||
```php |
||||
<?php |
||||
|
||||
namespace micro\controllers; |
||||
|
||||
use yii\web\Controller; |
||||
|
||||
class SiteController extends Controller |
||||
{ |
||||
public function actionIndex() |
||||
{ |
||||
return 'Hello World!'; |
||||
} |
||||
} |
||||
``` |
||||
|
||||
If you want to use a different name for this controller you can change it and configure [[yii\base\Application::$defaultRoute]] accordingly. |
||||
For example, for a `DefaultController` that would be `'defaultRoute' => 'default/index'`. |
||||
|
||||
At this point the project structure should look like this: |
||||
|
||||
``` |
||||
micro-app/ |
||||
├── composer.json |
||||
├── web/ |
||||
└── index.php |
||||
└── controllers/ |
||||
└── SiteController.php |
||||
``` |
||||
|
||||
If you have not set up the web server yet, you may want to take a look at [web server configuration file examples](start-installation.md#configuring-web-servers). |
||||
Another options is to use the `yii serve` command which will use the PHP build-in web server. You can run |
||||
it from the `micro-app/` directory via: |
||||
|
||||
vendor/bin/yii serve --docroot=./web |
||||
|
||||
Opening the application URL in a browser should now print "Hello World!" which has been returned in the `SiteController::actionIndex()`. |
||||
|
||||
> Info: In our example, we have changed default application namespace `app` to `micro` to demonstrate |
||||
> that you are not tied to that name (in case you thought you were), then adjusted |
||||
> [[yii\base\Application::$controllerNamespace|controllers namespace]] and set the correct alias. |
||||
|
||||
|
||||
## Creating a REST API |
||||
|
||||
In order to demonstrate the usage of our "micro framework", we will create a simple REST API for posts. |
||||
|
||||
For this API to serve some data, we need a database first. Add the database connection configuration |
||||
to the application configuration: |
||||
|
||||
```php |
||||
'components' => [ |
||||
'db' => [ |
||||
'class' => 'yii\db\Connection', |
||||
'dsn' => 'sqlite:@micro/database.sqlite', |
||||
], |
||||
], |
||||
``` |
||||
|
||||
> Info: We use an sqlite database here for simplicity. Please refer to the [Database guide](db-dao.md) for more options. |
||||
|
||||
Next we create a [database migration](db-migrations.md) to create a posts table. |
||||
Make sure you have a separate configuration file as explained above, we need it to run the console commands below. |
||||
Running the following commands will |
||||
create a database migration file and apply the migration to the database: |
||||
|
||||
vendor/bin/yii migrate/create --appconfig=config.php create_post_table --fields="title:string,body:text" |
||||
vendor/bin/yii migrate/up --appconfig=config.php |
||||
|
||||
Create directory `models` and a `Post.php` file in that directory. This is the code for the model: |
||||
|
||||
```php |
||||
<?php |
||||
|
||||
namespace micro\models; |
||||
|
||||
use yii\db\ActiveRecord; |
||||
|
||||
class Post extends ActiveRecord |
||||
{ |
||||
public static function tableName() |
||||
{ |
||||
return '{{posts}}'; |
||||
} |
||||
} |
||||
``` |
||||
|
||||
> Info: The model created here is an ActiveRecord class, which represents the data from the `posts` table. |
||||
> Please refer to the [active record guide](db-active-record.md) for more information. |
||||
|
||||
To serve posts on our API, add the `PostController` in `controllers`: |
||||
|
||||
```php |
||||
<?php |
||||
|
||||
namespace micro\controllers; |
||||
|
||||
use yii\rest\ActiveController; |
||||
|
||||
class PostController extends ActiveController |
||||
{ |
||||
public $modelClass = 'micro\models\Post'; |
||||
|
||||
public function behaviors() |
||||
{ |
||||
// remove rateLimiter which requires an authenticated user to work |
||||
$behaviors = parent::behaviors(); |
||||
unset($behaviors['rateLimiter']); |
||||
return $behaviors; |
||||
} |
||||
} |
||||
``` |
||||
|
||||
At this point our API will provide the following URLs: |
||||
|
||||
- `/index.php?r=post` - list all posts |
||||
- `/index.php?r=post/view&id=1` - show post with ID 1 |
||||
- `/index.php?r=post/create` - create a post |
||||
- `/index.php?r=post/update&id=1` - update post with ID 1 |
||||
- `/index.php?r=post/delete&id=1` - delete post with ID 1 |
||||
|
||||
Starting from Here you may want to look at the following guides to further develop your application: |
||||
|
||||
- The API currently only understands urlencoded form data as input, to make it a real JSON API, you |
||||
need to configure [[yii\web\JsonParser]]. |
||||
- To make the URLs more friendly you need to configure routing. |
||||
See [guide on REST routing](rest-routing.md) on how to do this. |
||||
- Please also refer to the [Looking Ahead](start-looking-ahead.md) section for further references. |
@ -0,0 +1,30 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\base; |
||||
|
||||
/** |
||||
* StaticInstanceInterface is the interface for providing static instances to classes, |
||||
* which can be used to obtain class meta information that can not be expressed in static methods. |
||||
* For example: adjustments made by DI or behaviors reveal only at object level, but might be needed |
||||
* at class (static) level as well. |
||||
* |
||||
* To implement the [[instance()]] method you may use [[StaticInstanceTrait]]. |
||||
* |
||||
* @author Paul Klimov <klimov.paul@gmail.com> |
||||
* @since 2.0.13 |
||||
* @see StaticInstanceTrait |
||||
*/ |
||||
interface StaticInstanceInterface |
||||
{ |
||||
/** |
||||
* Returns static class instance, which can be used to obtain meta information. |
||||
* @param bool $refresh whether to re-create static instance even, if it is already cached. |
||||
* @return static class instance. |
||||
*/ |
||||
public static function instance($refresh = false); |
||||
} |
@ -0,0 +1,41 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\base; |
||||
|
||||
use Yii; |
||||
|
||||
/** |
||||
* StaticInstanceTrait provides methods to satisfy [[StaticInstanceInterface]] interface. |
||||
* |
||||
* @see StaticInstanceInterface |
||||
* |
||||
* @author Paul Klimov <klimov.paul@gmail.com> |
||||
* @since 2.0.13 |
||||
*/ |
||||
trait StaticInstanceTrait |
||||
{ |
||||
/** |
||||
* @var static[] static instances in format: `[className => object]` |
||||
*/ |
||||
private static $_instances = []; |
||||
|
||||
|
||||
/** |
||||
* Returns static class instance, which can be used to obtain meta information. |
||||
* @param bool $refresh whether to re-create static instance even, if it is already cached. |
||||
* @return static class instance. |
||||
*/ |
||||
public static function instance($refresh = false) |
||||
{ |
||||
$className = get_called_class(); |
||||
if ($refresh || !isset(self::$_instances[$className])) { |
||||
self::$_instances[$className] = Yii::createObject($className); |
||||
} |
||||
return self::$_instances[$className]; |
||||
} |
||||
} |
@ -0,0 +1,185 @@
|
||||
<?php |
||||
/** |
||||
* @link http://www.yiiframework.com/ |
||||
* @copyright Copyright (c) 2008 Yii Software LLC |
||||
* @license http://www.yiiframework.com/license/ |
||||
*/ |
||||
|
||||
namespace yii\behaviors; |
||||
|
||||
use Closure; |
||||
use yii\base\Behavior; |
||||
use yii\base\Event; |
||||
use yii\db\ActiveRecord; |
||||
|
||||
/** |
||||
* AttributesBehavior automatically assigns values specified to one or multiple attributes of an ActiveRecord |
||||
* object when certain events happen. |
||||
* |
||||
* To use AttributesBehavior, configure the [[attributes]] property which should specify the list of attributes |
||||
* that need to be updated and the corresponding events that should trigger the update. Then configure the |
||||
* value of enclosed arrays with a PHP callable whose return value will be used to assign to the current attribute. |
||||
* For example, |
||||
* |
||||
* ```php |
||||
* use yii\behaviors\AttributesBehavior; |
||||
* |
||||
* public function behaviors() |
||||
* { |
||||
* return [ |
||||
* [ |
||||
* 'class' => AttributesBehavior::class, |
||||
* 'attributes' => [ |
||||
* 'attribute1' => [ |
||||
* ActiveRecord::EVENT_BEFORE_INSERT => new Expression('NOW()'), |
||||
* ActiveRecord::EVENT_BEFORE_UPDATE => \Yii::$app->formatter->asDatetime('2017-07-13'), |
||||
* ], |
||||
* 'attribute2' => [ |
||||
* ActiveRecord::EVENT_BEFORE_VALIDATE => [$this, 'storeAttributes'], |
||||
* ActiveRecord::EVENT_AFTER_VALIDATE => [$this, 'restoreAttributes'], |
||||
* ], |
||||
* 'attribute3' => [ |
||||
* ActiveRecord::EVENT_BEFORE_VALIDATE => $fn2 = [$this, 'getAttribute2'], |
||||
* ActiveRecord::EVENT_AFTER_VALIDATE => $fn2, |
||||
* ], |
||||
* 'attribute4' => [ |
||||
* ActiveRecord::EVENT_BEFORE_DELETE => function ($event, $attribute) { |
||||
* static::disabled() || $event->isValid = false; |
||||
* }, |
||||
* ], |
||||
* ], |
||||
* ], |
||||
* ]; |
||||
* } |
||||
* ``` |
||||
* |
||||
* Because attribute values will be set automatically by this behavior, they are usually not user input and should therefore |
||||
* not be validated, i.e. they should not appear in the [[\yii\base\Model::rules()|rules()]] method of the model. |
||||
* |
||||
* @author Luciano Baraglia <luciano.baraglia@gmail.com> |
||||
* @author Qiang Xue <qiang.xue@gmail.com> |
||||
* @author Bogdan Stepanenko <bscheshirwork@gmail.com> |
||||
* @since 2.0.13 |
||||
*/ |
||||
class AttributesBehavior extends Behavior |
||||
{ |
||||
/** |
||||
* @var array list of attributes that are to be automatically filled with the values specified via enclosed arrays. |
||||
* The array keys are the ActiveRecord attributes upon which the events are to be updated, |
||||
* and the array values are the array of corresponding events(s). For this enclosed array: |
||||
* the array keys are the ActiveRecord events upon which the attributes are to be updated, |
||||
* and the array values are the value that will be assigned to the current attributes. This can be an anonymous function, |
||||
* callable in array format (e.g. `[$this, 'methodName']`), an [[\yii\db\Expression|Expression]] object representing a DB expression |
||||
* (e.g. `new Expression('NOW()')`), scalar, string or an arbitrary value. If the former, the return value of the |
||||
* function will be assigned to the attributes. |
||||
* |
||||
* ```php |
||||
* [ |
||||
* 'attribute1' => [ |
||||
* ActiveRecord::EVENT_BEFORE_INSERT => new Expression('NOW()'), |
||||
* ActiveRecord::EVENT_BEFORE_UPDATE => \Yii::$app->formatter->asDatetime('2017-07-13'), |
||||
* ], |
||||
* 'attribute2' => [ |
||||
* ActiveRecord::EVENT_BEFORE_VALIDATE => [$this, 'storeAttributes'], |
||||
* ActiveRecord::EVENT_AFTER_VALIDATE => [$this, 'restoreAttributes'], |
||||
* ], |
||||
* 'attribute3' => [ |
||||
* ActiveRecord::EVENT_BEFORE_VALIDATE => $fn2 = [$this, 'getAttribute2'], |
||||
* ActiveRecord::EVENT_AFTER_VALIDATE => $fn2, |
||||
* ], |
||||
* 'attribute4' => [ |
||||
* ActiveRecord::EVENT_BEFORE_DELETE => function ($event, $attribute) { |
||||
* static::disabled() || $event->isValid = false; |
||||
* }, |
||||
* ], |
||||
* ] |
||||
* ``` |
||||
*/ |
||||
public $attributes = []; |
||||
/** |
||||
* @var array list of order of attributes that are to be automatically filled with the event. |
||||
* The array keys are the ActiveRecord events upon which the attributes are to be updated, |
||||
* and the array values are represent the order corresponding attributes. |
||||
* The rest of the attributes are processed at the end. |
||||
* If the [[attributes]] for this attribute do not specify this event, it is ignored |
||||
* |
||||
* ```php |
||||
* [ |
||||
* ActiveRecord::EVENT_BEFORE_VALIDATE => ['attribute1', 'attribute2'], |
||||
* ActiveRecord::EVENT_AFTER_VALIDATE => ['attribute2', 'attribute1'], |
||||
* ] |
||||
* ``` |
||||
*/ |
||||
public $order = []; |
||||
/** |
||||
* @var bool whether to skip this behavior when the `$owner` has not been modified |
||||
*/ |
||||
public $skipUpdateOnClean = true; |
||||
/** |
||||
* @var bool whether to preserve non-empty attribute values. |
||||
*/ |
||||
public $preserveNonEmptyValues = false; |
||||
|
||||
|
||||
/** |
||||
* @inheritdoc |
||||
*/ |
||||
public function events() |
||||
{ |
||||
return array_fill_keys( |
||||
array_reduce($this->attributes, function ($carry, $item) { |
||||
return array_merge($carry, array_keys($item)); |
||||
}, []), |
||||
'evaluateAttributes' |
||||
); |
||||
} |
||||
|
||||
/** |
||||
* Evaluates the attributes values and assigns it to the current attributes. |
||||
* @param Event $event |
||||
*/ |
||||
public function evaluateAttributes($event) |
||||
{ |
||||
if ($this->skipUpdateOnClean |
||||
&& $event->name === ActiveRecord::EVENT_BEFORE_UPDATE |
||||
&& empty($this->owner->dirtyAttributes) |
||||
) { |
||||
return; |
||||
} |
||||
$attributes = array_keys(array_filter($this->attributes, function ($carry) use ($event) { |
||||
return array_key_exists($event->name, $carry); |
||||
})); |
||||
if (!empty($this->order[$event->name])) { |
||||
$attributes = array_merge( |
||||
array_intersect((array) $this->order[$event->name], $attributes), |
||||
array_diff($attributes, (array) $this->order[$event->name])); |
||||
} |
||||
foreach ($attributes as $attribute) { |
||||
if ($this->preserveNonEmptyValues && !empty($this->owner->$attribute)) { |
||||
continue; |
||||
} |
||||
$this->owner->$attribute = $this->getValue($attribute, $event); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Returns the value for the current attributes. |
||||
* This method is called by [[evaluateAttributes()]]. Its return value will be assigned |
||||
* to the target attribute corresponding to the triggering event. |
||||
* @param string $attribute target attribute name |
||||
* @param Event $event the event that triggers the current attribute updating. |
||||
* @return mixed the attribute value |
||||
*/ |
||||
protected function getValue($attribute, $event) |
||||
{ |
||||
if (!isset($this->attributes[$attribute][$event->name])) { |
||||
return null; |
||||
} |
||||
$value = $this->attributes[$attribute][$event->name]; |
||||
if ($value instanceof Closure || (is_array($value) && is_callable($value))) { |
||||
return $value($event, $attribute); |
||||
} |
||||
|
||||
return $value; |
||||
} |
||||
} |