Commit 31ea3f89 by Paul Klimov

Merge branch 'master' of github.com:yiisoft/yii2 into email-swift-2

parents 2d537704 155e9c6c
...@@ -20,3 +20,6 @@ composer.phar ...@@ -20,3 +20,6 @@ composer.phar
# Mac DS_Store Files # Mac DS_Store Files
.DS_Store .DS_Store
# local phpunit config
/phpunit.xml
\ No newline at end of file
...@@ -25,10 +25,10 @@ $this->params['breadcrumbs'][] = $this->title; ...@@ -25,10 +25,10 @@ $this->params['breadcrumbs'][] = $this->title;
<?= $form->field($model, 'email') ?> <?= $form->field($model, 'email') ?>
<?= $form->field($model, 'subject') ?> <?= $form->field($model, 'subject') ?>
<?= $form->field($model, 'body')->textArea(['rows' => 6]) ?> <?= $form->field($model, 'body')->textArea(['rows' => 6]) ?>
<?=$form->field($model, 'verifyCode')->widget(Captcha::className(), [ <?= $form->field($model, 'verifyCode')->widget(Captcha::className(), [
'options' => ['class' => 'form-control'], 'options' => ['class' => 'form-control'],
'template' => '<div class="row"><div class="col-lg-3">{image}</div><div class="col-lg-6">{input}</div></div>', 'template' => '<div class="row"><div class="col-lg-3">{image}</div><div class="col-lg-6">{input}</div></div>',
]); ?> ]) ?>
<div class="form-group"> <div class="form-group">
<?= Html::submitButton('Submit', ['class' => 'btn btn-primary']) ?> <?= Html::submitButton('Submit', ['class' => 'btn btn-primary']) ?>
</div> </div>
......
...@@ -21,7 +21,7 @@ if (empty($params['env'])) { ...@@ -21,7 +21,7 @@ if (empty($params['env'])) {
exit(1); exit(1);
} }
if(isset($envNames[$answer])) { if (isset($envNames[$answer])) {
$envName = $envNames[$answer]; $envName = $envNames[$answer];
} }
} }
......
...@@ -33,10 +33,10 @@ $this->params['breadcrumbs'][] = $this->title; ...@@ -33,10 +33,10 @@ $this->params['breadcrumbs'][] = $this->title;
<?= $form->field($model, 'email') ?> <?= $form->field($model, 'email') ?>
<?= $form->field($model, 'subject') ?> <?= $form->field($model, 'subject') ?>
<?= $form->field($model, 'body')->textArea(['rows' => 6]) ?> <?= $form->field($model, 'body')->textArea(['rows' => 6]) ?>
<?=$form->field($model, 'verifyCode')->widget(Captcha::className(), [ <?= $form->field($model, 'verifyCode')->widget(Captcha::className(), [
'options' => ['class' => 'form-control'], 'options' => ['class' => 'form-control'],
'template' => '<div class="row"><div class="col-lg-3">{image}</div><div class="col-lg-6">{input}</div></div>', 'template' => '<div class="row"><div class="col-lg-3">{image}</div><div class="col-lg-6">{input}</div></div>',
]); ?> ]) ?>
<div class="form-group"> <div class="form-group">
<?= Html::submitButton('Submit', ['class' => 'btn btn-primary']) ?> <?= Html::submitButton('Submit', ['class' => 'btn btn-primary']) ?>
</div> </div>
......
...@@ -28,9 +28,9 @@ $this->params['breadcrumbs'][] = $this->title; ...@@ -28,9 +28,9 @@ $this->params['breadcrumbs'][] = $this->title;
<?= $form->field($model, 'password')->passwordInput() ?> <?= $form->field($model, 'password')->passwordInput() ?>
<?=$form->field($model, 'rememberMe', [ <?= $form->field($model, 'rememberMe', [
'template' => "<div class=\"col-lg-offset-1 col-lg-3\">{input}</div>\n<div class=\"col-lg-8\">{error}</div>", 'template' => "<div class=\"col-lg-offset-1 col-lg-3\">{input}</div>\n<div class=\"col-lg-8\">{error}</div>",
])->checkbox(); ?> ])->checkbox() ?>
<div class="form-group"> <div class="form-group">
<div class="col-lg-offset-1 col-lg-11"> <div class="col-lg-offset-1 col-lg-11">
......
...@@ -115,7 +115,7 @@ class PhpDocController extends Controller ...@@ -115,7 +115,7 @@ class PhpDocController extends Controller
if (trim($lines[1]) == '*' || substr(trim($lines[1]), 0, 3) == '* @') { if (trim($lines[1]) == '*' || substr(trim($lines[1]), 0, 3) == '* @') {
$this->stderr("[WARN] Class $className has no short description.\n", Console::FG_YELLOW, Console::BOLD); $this->stderr("[WARN] Class $className has no short description.\n", Console::FG_YELLOW, Console::BOLD);
} }
foreach($lines as $line) { foreach ($lines as $line) {
if (substr(trim($line), 0, 9) == '* @since ') { if (substr(trim($line), 0, 9) == '* @since ') {
$seenSince = true; $seenSince = true;
} elseif (substr(trim($line), 0, 10) == '* @author ') { } elseif (substr(trim($line), 0, 10) == '* @author ') {
...@@ -138,7 +138,7 @@ class PhpDocController extends Controller ...@@ -138,7 +138,7 @@ class PhpDocController extends Controller
$newFileContent = []; $newFileContent = [];
$n = count($fileContent); $n = count($fileContent);
for($i = 0; $i < $n; $i++) { for ($i = 0; $i < $n; $i++) {
if ($i > $start || $i < $docStart) { if ($i > $start || $i < $docStart) {
$newFileContent[] = $fileContent[$i]; $newFileContent[] = $fileContent[$i];
} else { } else {
...@@ -164,7 +164,7 @@ class PhpDocController extends Controller ...@@ -164,7 +164,7 @@ class PhpDocController extends Controller
{ {
$lines = explode("\n", $doc); $lines = explode("\n", $doc);
$n = count($lines); $n = count($lines);
for($i = 0; $i < $n; $i++) { for ($i = 0; $i < $n; $i++) {
$lines[$i] = rtrim($lines[$i]); $lines[$i] = rtrim($lines[$i]);
if (trim($lines[$i]) == '*' && trim($lines[$i + 1]) == '*') { if (trim($lines[$i]) == '*' && trim($lines[$i + 1]) == '*') {
unset($lines[$i]); unset($lines[$i]);
...@@ -184,7 +184,7 @@ class PhpDocController extends Controller ...@@ -184,7 +184,7 @@ class PhpDocController extends Controller
$lines = explode("\n", $doc); $lines = explode("\n", $doc);
$propertyPart = false; $propertyPart = false;
$propertyPosition = false; $propertyPosition = false;
foreach($lines as $i => $line) { foreach ($lines as $i => $line) {
if (substr(trim($line), 0, 12) == '* @property ') { if (substr(trim($line), 0, 12) == '* @property ') {
$propertyPart = true; $propertyPart = true;
} elseif ($propertyPart && trim($line) == '*') { } elseif ($propertyPart && trim($line) == '*') {
...@@ -200,7 +200,7 @@ class PhpDocController extends Controller ...@@ -200,7 +200,7 @@ class PhpDocController extends Controller
} }
} }
$finalDoc = ''; $finalDoc = '';
foreach($lines as $i => $line) { foreach ($lines as $i => $line) {
$finalDoc .= $line . "\n"; $finalDoc .= $line . "\n";
if ($i == $propertyPosition) { if ($i == $propertyPosition) {
$finalDoc .= $properties; $finalDoc .= $properties;
......
...@@ -89,7 +89,7 @@ class BlogController extends Controller ...@@ -89,7 +89,7 @@ class BlogController extends Controller
$post = Post::find($id); $post = Post::find($id);
$text = $post->text; $text = $post->text;
if($version) { if ($version) {
$text = $post->getHistory($version); $text = $post->getHistory($version);
} }
...@@ -121,13 +121,13 @@ class BlogController extends Controller ...@@ -121,13 +121,13 @@ class BlogController extends Controller
public function actionUpdate($id) public function actionUpdate($id)
{ {
$post = Post::find($id); $post = Post::find($id);
if(!$post) { if (!$post) {
throw new HttpException(404); throw new HttpException(404);
} }
if(\Yii::$app->request->isPost)) { if (\Yii::$app->request->isPost)) {
$post->load($_POST); $post->load($_POST);
if($post->save()) { if ($post->save()) {
$this->redirect(['view', 'id' => $post->id]); $this->redirect(['view', 'id' => $post->id]);
} }
} }
......
...@@ -179,7 +179,7 @@ $model->save(); ...@@ -179,7 +179,7 @@ $model->save();
$postTags = []; $postTags = [];
$tagsCount = count($_POST['PostTag']); $tagsCount = count($_POST['PostTag']);
while($tagsCount-- > 0){ while ($tagsCount-- > 0) {
$postTags[] = new PostTag(['post_id' => $model->id]); $postTags[] = new PostTag(['post_id' => $model->id]);
} }
Model::loadMultiple($postTags, $_POST); Model::loadMultiple($postTags, $_POST);
......
...@@ -28,7 +28,7 @@ as the corresponding key. ...@@ -28,7 +28,7 @@ as the corresponding key.
So the view for the action above should be in `views/site/index.php` and can be something like: So the view for the action above should be in `views/site/index.php` and can be something like:
```php ```php
<p>Hello, <?=$username?>!</p> <p>Hello, <?= $username ?>!</p>
``` ```
Instead of just scalar values you can pass anything else such as arrays or objects. Instead of just scalar values you can pass anything else such as arrays or objects.
...@@ -305,7 +305,7 @@ Then we're using it in `index.php` view where we display a list of users: ...@@ -305,7 +305,7 @@ Then we're using it in `index.php` view where we display a list of users:
```php ```php
<div class="user-index"> <div class="user-index">
<?php <?php
foreach($users as $user) { foreach ($users as $user) {
echo $this->render('_profile', [ echo $this->render('_profile', [
'username' => $user->name, 'username' => $user->name,
'tagline' => $user->tagline, 'tagline' => $user->tagline,
......
...@@ -515,7 +515,7 @@ class BaseYii ...@@ -515,7 +515,7 @@ class BaseYii
return self::$app->getI18n()->translate($category, $message, $params, $language ?: self::$app->language); return self::$app->getI18n()->translate($category, $message, $params, $language ?: self::$app->language);
} else { } else {
$p = []; $p = [];
foreach((array) $params as $name => $value) { foreach ((array) $params as $name => $value) {
$p['{' . $name . '}'] = $value; $p['{' . $name . '}'] = $value;
} }
return ($p === []) ? $message : strtr($message, $p); return ($p === []) ? $message : strtr($message, $p);
......
...@@ -20,7 +20,7 @@ use yii\web\HttpException; ...@@ -20,7 +20,7 @@ use yii\web\HttpException;
* @property \yii\db\Connection $db The database connection. This property is read-only. * @property \yii\db\Connection $db The database connection. This property is read-only.
* @property ErrorHandler $errorHandler The error handler application component. This property is read-only. * @property ErrorHandler $errorHandler The error handler application component. This property is read-only.
* @property \yii\base\Formatter $formatter The formatter application component. This property is read-only. * @property \yii\base\Formatter $formatter The formatter application component. This property is read-only.
* @property \yii\i18n\I18N $i18N The internationalization component. This property is read-only. * @property \yii\i18n\I18N $i18n The internationalization component. This property is read-only.
* @property \yii\log\Logger $log The log component. This property is read-only. * @property \yii\log\Logger $log The log component. This property is read-only.
* @property \yii\web\Request|\yii\console\Request $request The request component. This property is read-only. * @property \yii\web\Request|\yii\console\Request $request The request component. This property is read-only.
* @property string $runtimePath The directory that stores runtime files. Defaults to the "runtime" * @property string $runtimePath The directory that stores runtime files. Defaults to the "runtime"
......
...@@ -25,7 +25,7 @@ use Yii; ...@@ -25,7 +25,7 @@ use Yii;
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
*/ */
class Controller extends Component class Controller extends Component implements ViewContextInterface
{ {
/** /**
* @event ActionEvent an event raised right before executing a controller action. * @event ActionEvent an event raised right before executing a controller action.
...@@ -305,8 +305,7 @@ class Controller extends Component ...@@ -305,8 +305,7 @@ class Controller extends Component
*/ */
public function render($view, $params = []) public function render($view, $params = [])
{ {
$viewFile = $this->findViewFile($view); $output = $this->getView()->render($view, $params, $this);
$output = $this->getView()->renderFile($viewFile, $params, $this);
$layoutFile = $this->findLayoutFile(); $layoutFile = $this->findLayoutFile();
if ($layoutFile !== false) { if ($layoutFile !== false) {
return $this->getView()->renderFile($layoutFile, ['content' => $output], $this); return $this->getView()->renderFile($layoutFile, ['content' => $output], $this);
...@@ -325,8 +324,7 @@ class Controller extends Component ...@@ -325,8 +324,7 @@ class Controller extends Component
*/ */
public function renderPartial($view, $params = []) public function renderPartial($view, $params = [])
{ {
$viewFile = $this->findViewFile($view); return $this->getView()->render($view, $params, $this);
return $this->getView()->renderFile($viewFile, $params, $this);
} }
/** /**
...@@ -382,22 +380,9 @@ class Controller extends Component ...@@ -382,22 +380,9 @@ class Controller extends Component
* on how to specify this parameter. * on how to specify this parameter.
* @return string the view file path. Note that the file may not exist. * @return string the view file path. Note that the file may not exist.
*/ */
protected function findViewFile($view) public function findViewFile($view)
{ {
if (strncmp($view, '@', 1) === 0) { return $this->getViewPath() . DIRECTORY_SEPARATOR . $view;
// e.g. "@app/views/main"
$file = Yii::getAlias($view);
} elseif (strncmp($view, '//', 2) === 0) {
// e.g. "//layouts/main"
$file = Yii::$app->getViewPath() . DIRECTORY_SEPARATOR . ltrim($view, '/');
} elseif (strncmp($view, '/', 1) === 0) {
// e.g. "/site/index"
$file = $this->module->getViewPath() . DIRECTORY_SEPARATOR . ltrim($view, '/');
} else {
$file = $this->getViewPath() . DIRECTORY_SEPARATOR . $view;
}
return pathinfo($file, PATHINFO_EXTENSION) === '' ? $file . '.php' : $file;
} }
/** /**
......
...@@ -63,6 +63,7 @@ class Object implements Arrayable ...@@ -63,6 +63,7 @@ class Object implements Arrayable
* @param string $name the property name * @param string $name the property name
* @return mixed the property value * @return mixed the property value
* @throws UnknownPropertyException if the property is not defined * @throws UnknownPropertyException if the property is not defined
* @throws InvalidCallException if the property is write-only
* @see __set * @see __set
*/ */
public function __get($name) public function __get($name)
...@@ -85,7 +86,7 @@ class Object implements Arrayable ...@@ -85,7 +86,7 @@ class Object implements Arrayable
* @param string $name the property name or the event name * @param string $name the property name or the event name
* @param mixed $value the property value * @param mixed $value the property value
* @throws UnknownPropertyException if the property is not defined * @throws UnknownPropertyException if the property is not defined
* @throws InvalidCallException if the property is read-only. * @throws InvalidCallException if the property is read-only
* @see __get * @see __get
*/ */
public function __set($name, $value) public function __set($name, $value)
......
...@@ -89,8 +89,7 @@ class View extends Component ...@@ -89,8 +89,7 @@ class View extends Component
/** /**
* @var object the context under which the [[renderFile()]] method is being invoked. * @var ViewContextInterface the context under which the [[renderFile()]] method is being invoked.
* This can be a controller, a widget, or any other object.
*/ */
public $context; public $context;
/** /**
...@@ -196,29 +195,67 @@ class View extends Component ...@@ -196,29 +195,67 @@ class View extends Component
/** /**
* Renders a view. * Renders a view.
* *
* This method delegates the call to the [[context]] object: * The view to be rendered can be specified in one of the following formats:
* *
* - If [[context]] is a controller, the [[Controller::renderPartial()]] method will be called; * - path alias (e.g. "@app/views/site/index");
* - If [[context]] is a widget, the [[Widget::render()]] method will be called; * - absolute path within application (e.g. "//site/index"): the view name starts with double slashes.
* - Otherwise, an InvalidCallException exception will be thrown. * The actual view file will be looked for under the [[Application::viewPath|view path]] of the application.
* - absolute path within current module (e.g. "/site/index"): the view name starts with a single slash.
* The actual view file will be looked for under the [[Module::viewPath|view path]] of [[module]].
* - resolving any other format will be performed via [[ViewContext::findViewFile()]].
* *
* @param string $view the view name. Please refer to [[Controller::findViewFile()]] * @param string $view the view name. Please refer to [[Controller::findViewFile()]]
* and [[Widget::findViewFile()]] on how to specify this parameter. * and [[Widget::findViewFile()]] on how to specify this parameter.
* @param array $params the parameters (name-value pairs) that will be extracted and made available in the view file. * @param array $params the parameters (name-value pairs) that will be extracted and made available in the view file.
* @param object $context the context that the view should use for rendering the view. If null,
* existing [[context]] will be used.
* @return string the rendering result * @return string the rendering result
* @throws InvalidCallException if [[context]] is neither a controller nor a widget.
* @throws InvalidParamException if the view cannot be resolved or the view file does not exist. * @throws InvalidParamException if the view cannot be resolved or the view file does not exist.
* @see renderFile * @see renderFile
*/ */
public function render($view, $params = []) public function render($view, $params = [], $context = null)
{ {
if ($this->context instanceof Controller) { $viewFile = $this->findViewFile($view, $context);
return $this->context->renderPartial($view, $params); return $this->renderFile($viewFile, $params, $context);
} elseif ($this->context instanceof Widget) { }
return $this->context->render($view, $params);
/**
* Finds the view file based on the given view name.
* @param string $view the view name or the path alias of the view file. Please refer to [[render()]]
* on how to specify this parameter.
* @param object $context the context that the view should be used to search the view file. If null,
* existing [[context]] will be used.
* @return string the view file path. Note that the file may not exist.
* @throws InvalidCallException if [[context]] is required and invalid.
*/
protected function findViewFile($view, $context = null)
{
if (strncmp($view, '@', 1) === 0) {
// e.g. "@app/views/main"
$file = Yii::getAlias($view);
} elseif (strncmp($view, '//', 2) === 0) {
// e.g. "//layouts/main"
$file = Yii::$app->getViewPath() . DIRECTORY_SEPARATOR . ltrim($view, '/');
} elseif (strncmp($view, '/', 1) === 0) {
// e.g. "/site/index"
if (Yii::$app->controller !== null) {
$file = Yii::$app->controller->module->getViewPath() . DIRECTORY_SEPARATOR . ltrim($view, '/');
} else {
throw new InvalidCallException("Unable to locate view file for view '$view': no active controller.");
}
} else { } else {
throw new InvalidCallException('View::render() is not supported for the current context.'); // context required
if ($context === null) {
$context = $this->context;
}
if ($context instanceof ViewContextInterface) {
$file = $context->findViewFile($view);
} else {
throw new InvalidCallException("Unable to locate view file for view '$view': no active view context.");
}
} }
return pathinfo($file, PATHINFO_EXTENSION) === '' ? $file . '.php' : $file;
} }
/** /**
...@@ -519,7 +556,7 @@ class View extends Component ...@@ -519,7 +556,7 @@ class View extends Component
$this->trigger(self::EVENT_END_PAGE); $this->trigger(self::EVENT_END_PAGE);
$content = ob_get_clean(); $content = ob_get_clean();
foreach(array_keys($this->assetBundles) as $bundle) { foreach (array_keys($this->assetBundles) as $bundle) {
$this->registerAssetFiles($bundle); $this->registerAssetFiles($bundle);
} }
echo strtr($content, [ echo strtr($content, [
...@@ -549,7 +586,7 @@ class View extends Component ...@@ -549,7 +586,7 @@ class View extends Component
return; return;
} }
$bundle = $this->assetBundles[$name]; $bundle = $this->assetBundles[$name];
foreach($bundle->depends as $dep) { foreach ($bundle->depends as $dep) {
$this->registerAssetFiles($dep); $this->registerAssetFiles($dep);
} }
$bundle->registerAssetFiles($this); $bundle->registerAssetFiles($this);
......
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\base;
/**
* ViewContextInterface is the interface that should implemented by classes who want to support relative view names.
*
* The method [[findViewFile()]] should be implemented to convert a relative view name into a file path.
*
* @author Paul Klimov <klimov.paul@gmail.com>
* @since 2.0
*/
interface ViewContextInterface
{
/**
* Finds the view file corresponding to the specified relative view name.
* @param string $view a relative view name. The name does NOT start with a slash.
* @return string the view file path. Note that the file may not exist.
*/
public function findViewFile($view);
}
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
namespace yii\base; namespace yii\base;
use Yii; use Yii;
use ReflectionClass;
/** /**
* Widget is the base class for widgets. * Widget is the base class for widgets.
...@@ -20,7 +21,7 @@ use Yii; ...@@ -20,7 +21,7 @@ use Yii;
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
*/ */
class Widget extends Component class Widget extends Component implements ViewContextInterface
{ {
/** /**
* @var integer a counter used to generate [[id]] for widgets. * @var integer a counter used to generate [[id]] for widgets.
...@@ -167,8 +168,7 @@ class Widget extends Component ...@@ -167,8 +168,7 @@ class Widget extends Component
*/ */
public function render($view, $params = []) public function render($view, $params = [])
{ {
$viewFile = $this->findViewFile($view); return $this->getView()->render($view, $params, $this);
return $this->getView()->renderFile($viewFile, $params, $this);
} }
/** /**
...@@ -190,32 +190,18 @@ class Widget extends Component ...@@ -190,32 +190,18 @@ class Widget extends Component
*/ */
public function getViewPath() public function getViewPath()
{ {
$className = get_class($this); $class = new ReflectionClass($this);
$class = new \ReflectionClass($className);
return dirname($class->getFileName()) . DIRECTORY_SEPARATOR . 'views'; return dirname($class->getFileName()) . DIRECTORY_SEPARATOR . 'views';
} }
/** /**
* Finds the view file based on the given view name. * Finds the view file based on the given view name.
* @param string $view the view name or the path alias of the view file. Please refer to [[render()]] * File will be searched under [[viewPath]] directory.
* on how to specify this parameter. * @param string $view the view name.
* @return string the view file path. Note that the file may not exist. * @return string the view file path. Note that the file may not exist.
*/ */
protected function findViewFile($view) public function findViewFile($view)
{ {
if (strncmp($view, '@', 1) === 0) { return $this->getViewPath() . DIRECTORY_SEPARATOR . $view;
// e.g. "@app/views/main"
$file = Yii::getAlias($view);
} elseif (strncmp($view, '//', 2) === 0) {
// e.g. "//layouts/main"
$file = Yii::$app->getViewPath() . DIRECTORY_SEPARATOR . ltrim($view, '/');
} elseif (strncmp($view, '/', 1) === 0 && Yii::$app->controller !== null) {
// e.g. "/site/index"
$file = Yii::$app->controller->module->getViewPath() . DIRECTORY_SEPARATOR . ltrim($view, '/');
} else {
$file = $this->getViewPath() . DIRECTORY_SEPARATOR . ltrim($view, '/');
}
return pathinfo($file, PATHINFO_EXTENSION) === '' ? $file . '.php' : $file;
} }
} }
...@@ -192,7 +192,7 @@ abstract class Cache extends Component implements \ArrayAccess ...@@ -192,7 +192,7 @@ abstract class Cache extends Component implements \ArrayAccess
* If the cache already contains such a key, the existing value and * If the cache already contains such a key, the existing value and
* expiration time will be replaced with the new ones, respectively. * expiration time will be replaced with the new ones, respectively.
* *
* @param mixed $key a key identifying the value to be cached value. This can be a simple string or * @param mixed $key a key identifying the value to be cached. This can be a simple string or
* a complex data structure consisting of factors representing the key. * a complex data structure consisting of factors representing the key.
* @param mixed $value the value to be cached * @param mixed $value the value to be cached
* @param integer $expire the number of seconds in which the cached value will expire. 0 means never expire. * @param integer $expire the number of seconds in which the cached value will expire. 0 means never expire.
...@@ -218,7 +218,7 @@ abstract class Cache extends Component implements \ArrayAccess ...@@ -218,7 +218,7 @@ abstract class Cache extends Component implements \ArrayAccess
/** /**
* Stores a value identified by a key into cache if the cache does not contain this key. * Stores a value identified by a key into cache if the cache does not contain this key.
* Nothing will be done if the cache already contains the key. * Nothing will be done if the cache already contains the key.
* @param mixed $key a key identifying the value to be cached value. This can be a simple string or * @param mixed $key a key identifying the value to be cached. This can be a simple string or
* a complex data structure consisting of factors representing the key. * a complex data structure consisting of factors representing the key.
* @param mixed $value the value to be cached * @param mixed $value the value to be cached
* @param integer $expire the number of seconds in which the cached value will expire. 0 means never expire. * @param integer $expire the number of seconds in which the cached value will expire. 0 means never expire.
......
...@@ -139,7 +139,7 @@ class RedisCache extends Cache ...@@ -139,7 +139,7 @@ class RedisCache extends Cache
$response = $this->_connection->executeCommand('MGET', $keys); $response = $this->_connection->executeCommand('MGET', $keys);
$result = []; $result = [];
$i = 0; $i = 0;
foreach($keys as $key) { foreach ($keys as $key) {
$result[$key] = $response[$i++]; $result[$key] = $response[$i++];
} }
return $result; return $result;
......
...@@ -170,7 +170,7 @@ class ActiveDataProvider extends BaseDataProvider ...@@ -170,7 +170,7 @@ class ActiveDataProvider extends BaseDataProvider
if (($sort = $this->getSort()) !== false && empty($sort->attributes) && $this->query instanceof ActiveQuery) { if (($sort = $this->getSort()) !== false && empty($sort->attributes) && $this->query instanceof ActiveQuery) {
/** @var Model $model */ /** @var Model $model */
$model = new $this->query->modelClass; $model = new $this->query->modelClass;
foreach($model->attributes() as $attribute) { foreach ($model->attributes() as $attribute) {
$sort->attributes[$attribute] = [ $sort->attributes[$attribute] = [
'asc' => [$attribute => Sort::ASC], 'asc' => [$attribute => Sort::ASC],
'desc' => [$attribute => Sort::DESC], 'desc' => [$attribute => Sort::DESC],
......
...@@ -147,7 +147,7 @@ class Schema extends \yii\db\Schema ...@@ -147,7 +147,7 @@ class Schema extends \yii\db\Schema
} }
$foreignKeys = $this->db->pdo->cubrid_schema(\PDO::CUBRID_SCH_IMPORTED_KEYS, $table->name); $foreignKeys = $this->db->pdo->cubrid_schema(\PDO::CUBRID_SCH_IMPORTED_KEYS, $table->name);
foreach($foreignKeys as $key) { foreach ($foreignKeys as $key) {
if (isset($table->foreignKeys[$key['FK_NAME']])) { if (isset($table->foreignKeys[$key['FK_NAME']])) {
$table->foreignKeys[$key['FK_NAME']][$key['FKCOLUMN_NAME']] = $key['PKCOLUMN_NAME']; $table->foreignKeys[$key['FK_NAME']][$key['FKCOLUMN_NAME']] = $key['PKCOLUMN_NAME'];
} else { } else {
...@@ -230,7 +230,7 @@ class Schema extends \yii\db\Schema ...@@ -230,7 +230,7 @@ class Schema extends \yii\db\Schema
$this->db->open(); $this->db->open();
$tables = $this->db->pdo->cubrid_schema(\PDO::CUBRID_SCH_TABLE); $tables = $this->db->pdo->cubrid_schema(\PDO::CUBRID_SCH_TABLE);
$tableNames = []; $tableNames = [];
foreach($tables as $table) { foreach ($tables as $table) {
// do not list system tables // do not list system tables
if ($table['TYPE'] != 0) { if ($table['TYPE'] != 0) {
$tableNames[] = $table['NAME']; $tableNames[] = $table['NAME'];
......
...@@ -34,6 +34,7 @@ class Schema extends \yii\db\Schema ...@@ -34,6 +34,7 @@ class Schema extends \yii\db\Schema
public $typeMap = [ public $typeMap = [
'abstime' => self::TYPE_TIMESTAMP, 'abstime' => self::TYPE_TIMESTAMP,
'bit' => self::TYPE_STRING, 'bit' => self::TYPE_STRING,
'bool' => self::TYPE_BOOLEAN,
'boolean' => self::TYPE_BOOLEAN, 'boolean' => self::TYPE_BOOLEAN,
'box' => self::TYPE_STRING, 'box' => self::TYPE_STRING,
'character' => self::TYPE_STRING, 'character' => self::TYPE_STRING,
......
...@@ -17,7 +17,7 @@ public function action<?= Inflector::id2camel(trim(basename($generator->viewName ...@@ -17,7 +17,7 @@ public function action<?= Inflector::id2camel(trim(basename($generator->viewName
$model = new <?= $generator->modelClass ?><?= empty($generator->scenarioName) ? "" : "(['scenario' => '{$generator->scenarioName}'])" ?>; $model = new <?= $generator->modelClass ?><?= empty($generator->scenarioName) ? "" : "(['scenario' => '{$generator->scenarioName}'])" ?>;
if ($model->load($_POST)) { if ($model->load($_POST)) {
if($model->validate()) { if ($model->validate()) {
// form inputs are valid, do something here // form inputs are valid, do something here
return; return;
} }
......
...@@ -34,19 +34,19 @@ foreach ($generator->templates as $name => $path) { ...@@ -34,19 +34,19 @@ foreach ($generator->templates as $name => $path) {
]); ?> ]); ?>
<div class="row"> <div class="row">
<div class="col-lg-8"> <div class="col-lg-8">
<?=$this->renderFile($generator->formView(), [ <?= $this->renderFile($generator->formView(), [
'generator' => $generator, 'generator' => $generator,
'form' => $form, 'form' => $form,
]); ?> ]) ?>
<?=$form->field($generator, 'template')->sticky() <?= $form->field($generator, 'template')->sticky()
->label('Code Template') ->label('Code Template')
->dropDownList($templates)->hint(' ->dropDownList($templates)->hint('
Please select which set of the templates should be used to generated the code. Please select which set of the templates should be used to generated the code.
'); ?> ') ?>
<div class="form-group"> <div class="form-group">
<?= Html::submitButton('Preview', ['name' => 'preview', 'class' => 'btn btn-primary']) ?> <?= Html::submitButton('Preview', ['name' => 'preview', 'class' => 'btn btn-primary']) ?>
<?php if(isset($files)): ?> <?php if (isset($files)): ?>
<?= Html::submitButton('Generate', ['name' => 'generate', 'class' => 'btn btn-success']) ?> <?= Html::submitButton('Generate', ['name' => 'generate', 'class' => 'btn btn-success']) ?>
<?php endif; ?> <?php endif; ?>
</div> </div>
......
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\i18n;
use yii\base\NotSupportedException;
/**
* FallbackMessageFormatter is a fallback implementation for the PHP intl MessageFormatter that is
* used in case PHP intl extension is not installed.
*
* Do not use this class directly. Use [[MessageFormatter]] instead, which will automatically detect
* installed version of PHP intl and use the fallback if it is not installed.
*
* It is highly recommended that you install [PHP intl extension](http://php.net/manual/en/book.intl.php) if you want to use
* MessageFormatter features.
*
* This implementation only supports to following message formats:
* - plural formatting for english
* - select format
* - simple parameters
*
* The pattern also does NOT support the ['apostrophe-friendly' syntax](http://www.php.net/manual/en/messageformatter.formatmessage.php).
*
* @author Carsten Brandt <mail@cebe.cc>
* @since 2.0
*/
class FallbackMessageFormatter
{
private $_locale;
private $_pattern;
private $_errorMessage = '';
private $_errorCode = 0;
/**
* Constructs a new Message Formatter
* @link http://php.net/manual/en/messageformatter.create.php
* @param string $locale The locale to use when formatting arguments
* @param string $pattern The pattern string to stick arguments into.
*/
public function __construct($locale, $pattern)
{
$this->_locale = $locale;
$this->_pattern = $pattern;
}
/**
* Constructs a new Message Formatter
* @link http://php.net/manual/en/messageformatter.create.php
* @param string $locale The locale to use when formatting arguments
* @param string $pattern The pattern string to stick arguments into.
* @return MessageFormatter The formatter object
*/
public static function create($locale, $pattern)
{
return new static($locale, $pattern);
}
/**
* Format the message
* @link http://php.net/manual/en/messageformatter.format.php
* @param array $args Arguments to insert into the format string
* @return string The formatted string, or `FALSE` if an error occurred
*/
public function format($args)
{
return static::formatMessage($this->_locale, $this->_pattern, $args);
}
/**
* Quick format message
* @link http://php.net/manual/en/messageformatter.formatmessage.php
* @param string $locale The locale to use for formatting locale-dependent parts
* @param string $pattern The pattern string to insert things into.
* @param array $args The array of values to insert into the format string
* @return string The formatted pattern string or `FALSE` if an error occurred
*/
public static function formatMessage($locale, $pattern, $args)
{
if (($tokens = static::tokenizePattern($pattern)) === false) {
return false;
}
foreach($tokens as $i => $token) {
if (is_array($token)) {
if (($tokens[$i] = static::parseToken($token, $args, $locale)) === false) {
return false;
}
}
}
return implode('', $tokens);
}
/**
* Tokenizes a pattern by separating normal text from replaceable patterns
* @param string $pattern patter to tokenize
* @return array|bool array of tokens or false on failure
*/
private static function tokenizePattern($pattern)
{
$depth = 1;
if (($start = $pos = mb_strpos($pattern, '{')) === false) {
return [$pattern];
}
$tokens = [mb_substr($pattern, 0, $pos)];
while(true) {
$open = mb_strpos($pattern, '{', $pos + 1);
$close = mb_strpos($pattern, '}', $pos + 1);
if ($open === false && $close === false) {
break;
}
if ($open === false) {
$open = mb_strlen($pattern);
}
if ($close > $open) {
$depth++;
$pos = $open;
} else {
$depth--;
$pos = $close;
}
if ($depth == 0) {
$tokens[] = explode(',', mb_substr($pattern, $start + 1, $pos - $start - 1), 3);
$start = $pos + 1;
$tokens[] = mb_substr($pattern, $start, $open - $start);
$start = $open;
}
}
if ($depth != 0) {
return false;
}
return $tokens;
}
/**
* Parses a token
* @param array $token the token to parse
* @param array $args arguments to replace
* @param string $locale the locale
* @return bool|string parsed token or false on failure
* @throws \yii\base\NotSupportedException when unsupported formatting is used.
*/
private static function parseToken($token, $args, $locale)
{
$param = trim($token[0]);
if (isset($args[$param])) {
$arg = $args[$param];
} else {
return '{' . implode(',', $token) . '}';
}
$type = isset($token[1]) ? trim($token[1]) : 'none';
switch($type)
{
case 'number':
case 'date':
case 'time':
case 'spellout':
case 'ordinal':
case 'duration':
case 'choice':
case 'selectordinal':
throw new NotSupportedException("Message format '$type' is not supported. You have to install PHP intl extension to use this feature.");
case 'none': return $arg;
case 'select':
/* http://icu-project.org/apiref/icu4c/classicu_1_1SelectFormat.html
selectStyle = (selector '{' message '}')+
*/
$select = static::tokenizePattern($token[2]);
$c = count($select);
$message = false;
for($i = 0; $i + 1 < $c; $i++) {
if (is_array($select[$i]) || !is_array($select[$i + 1])) {
return false;
}
$selector = trim($select[$i++]);
if ($message === false && $selector == 'other' || $selector == $arg) {
$message = implode(',', $select[$i]);
}
}
if ($message !== false) {
return static::formatMessage($locale, $message, $args);
}
break;
case 'plural':
/* http://icu-project.org/apiref/icu4c/classicu_1_1PluralFormat.html
pluralStyle = [offsetValue] (selector '{' message '}')+
offsetValue = "offset:" number
selector = explicitValue | keyword
explicitValue = '=' number // adjacent, no white space in between
keyword = [^[[:Pattern_Syntax:][:Pattern_White_Space:]]]+
message: see MessageFormat
*/
$plural = static::tokenizePattern($token[2]);
$c = count($plural);
$message = false;
$offset = 0;
for($i = 0; $i + 1 < $c; $i++) {
if (is_array($plural[$i]) || !is_array($plural[$i + 1])) {
return false;
}
$selector = trim($plural[$i++]);
if ($i == 1 && substr($selector, 0, 7) == 'offset:') {
$offset = (int) trim(mb_substr($selector, 7, ($pos = mb_strpos(str_replace(["\n", "\r", "\t"], ' ', $selector), ' ', 7)) - 7));
$selector = trim(mb_substr($selector, $pos + 1));
}
if ($message === false && $selector == 'other' ||
$selector[0] == '=' && (int) mb_substr($selector, 1) == $arg ||
$selector == 'zero' && $arg - $offset == 0 ||
$selector == 'one' && $arg - $offset == 1 ||
$selector == 'two' && $arg - $offset == 2
) {
$message = implode(',', str_replace('#', $arg - $offset, $plural[$i]));
}
}
if ($message !== false) {
return static::formatMessage($locale, $message, $args);
}
break;
}
return false;
}
/**
* Parse input string according to pattern
* @link http://php.net/manual/en/messageformatter.parse.php
* @param string $value The string to parse
* @return array An array containing the items extracted, or `FALSE` on error
*/
public function parse($value)
{
throw new NotSupportedException('You have to install PHP intl extension to use this feature.');
}
/**
* Quick parse input string
* @link http://php.net/manual/en/messageformatter.parsemessage.php
* @param string $locale The locale to use for parsing locale-dependent parts
* @param string $pattern The pattern with which to parse the `value`.
* @param string $source The string to parse, conforming to the `pattern`.
* @return array An array containing items extracted, or `FALSE` on error
*/
public static function parseMessage($locale, $pattern, $source)
{
throw new NotSupportedException('You have to install PHP intl extension to use this feature.');
}
/**
* Set the pattern used by the formatter
* @link http://php.net/manual/en/messageformatter.setpattern.php
* @param string $pattern The pattern string to use in this message formatter.
* @return bool `TRUE` on success or `FALSE` on failure.
*/
public function setPattern($pattern)
{
$this->_pattern = $pattern;
return true;
}
/**
* Get the pattern used by the formatter
* @link http://php.net/manual/en/messageformatter.getpattern.php
* @return string The pattern string for this message formatter
*/
public function getPattern()
{
return $this->_pattern;
}
/**
* Get the locale for which the formatter was created.
* @link http://php.net/manual/en/messageformatter.getlocale.php
* @return string The locale name
*/
public function getLocale()
{
return $this->_locale;
}
/**
* Get the error code from last operation
* @link http://php.net/manual/en/messageformatter.geterrorcode.php
* @return int The error code, one of UErrorCode values. Initial value is U_ZERO_ERROR.
*/
public function getErrorCode()
{
return $this->_errorCode;
}
/**
* Get the error text from the last operation
* @link http://php.net/manual/en/messageformatter.geterrormessage.php
* @return string Description of the last error.
*/
public function getErrorMessage()
{
return $this->_errorMessage;
}
}
if (!class_exists('MessageFormatter', false)) {
class_alias('yii\\i18n\\FallbackMessageFormatter', 'MessageFormatter');
define('YII_INTL_MESSAGE_FALLBACK', true);
}
...@@ -14,6 +14,10 @@ use yii\base\InvalidConfigException; ...@@ -14,6 +14,10 @@ use yii\base\InvalidConfigException;
/** /**
* I18N provides features related with internationalization (I18N) and localization (L10N). * I18N provides features related with internationalization (I18N) and localization (L10N).
* *
* @property MessageFormatter $messageFormatter The message formatter to be used to format message via ICU
* message format. Note that the type of this property differs in getter and setter. See
* [[getMessageFormatter()]] and [[setMessageFormatter()]] for details.
*
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
*/ */
...@@ -69,7 +73,7 @@ class I18N extends Component ...@@ -69,7 +73,7 @@ class I18N extends Component
* @param string $message the message to be translated. * @param string $message the message to be translated.
* @param array $params the parameters that will be used to replace the corresponding placeholders in the message. * @param array $params the parameters that will be used to replace the corresponding placeholders in the message.
* @param string $language the language code (e.g. `en_US`, `en`). * @param string $language the language code (e.g. `en_US`, `en`).
* @return string the translated message. * @return string the translated and formatted message.
*/ */
public function translate($category, $message, $params, $language) public function translate($category, $message, $params, $language)
{ {
...@@ -78,7 +82,7 @@ class I18N extends Component ...@@ -78,7 +82,7 @@ class I18N extends Component
} }
/** /**
* Formats a message using using [[MessageFormatter]]. * Formats a message using [[MessageFormatter]].
* *
* @param string $message the message to be formatted. * @param string $message the message to be formatted.
* @param array $params the parameters that will be used to replace the corresponding placeholders in the message. * @param array $params the parameters that will be used to replace the corresponding placeholders in the message.
...@@ -93,12 +97,8 @@ class I18N extends Component ...@@ -93,12 +97,8 @@ class I18N extends Component
} }
if (preg_match('~{\s*[\d\w]+\s*,~u', $message)) { if (preg_match('~{\s*[\d\w]+\s*,~u', $message)) {
$formatter = new MessageFormatter($language, $message); $formatter = $this->getMessageFormatter();
if ($formatter === null) { $result = $formatter->format($message, $params, $language);
Yii::warning("Unable to format message in language '$language': $message.");
return $message;
}
$result = $formatter->format($params);
if ($result === false) { if ($result === false) {
$errorMessage = $formatter->getErrorMessage(); $errorMessage = $formatter->getErrorMessage();
Yii::warning("Formatting message for language '$language' failed with error: $errorMessage. The message being formatted was: $message."); Yii::warning("Formatting message for language '$language' failed with error: $errorMessage. The message being formatted was: $message.");
...@@ -116,6 +116,35 @@ class I18N extends Component ...@@ -116,6 +116,35 @@ class I18N extends Component
} }
/** /**
* @var string|array|MessageFormatter
*/
private $_messageFormatter;
/**
* Returns the message formatter instance.
* @return MessageFormatter the message formatter to be used to format message via ICU message format.
*/
public function getMessageFormatter()
{
if ($this->_messageFormatter === null) {
$this->_messageFormatter = new MessageFormatter();
} elseif (is_array($this->_messageFormatter) || is_string($this->_messageFormatter)) {
$this->_messageFormatter = Yii::createObject($this->_messageFormatter);
}
return $this->_messageFormatter;
}
/**
* @param string|array|MessageFormatter $value the message formatter to be used to format message via ICU message format.
* Can be given as array or string configuration that will be given to [[Yii::createObject]] to create an instance
* or a [[MessageFormatter]] instance.
*/
public function setMessageFormatter($value)
{
$this->_messageFormatter = $value;
}
/**
* Returns the message source for the given category. * Returns the message source for the given category.
* @param string $category the category name. * @param string $category the category name.
* @return MessageSource the message source for the given category. * @return MessageSource the message source for the given category.
......
...@@ -65,8 +65,8 @@ use yii\base\InvalidConfigException; ...@@ -65,8 +65,8 @@ use yii\base\InvalidConfigException;
* second element the total time spent in SQL execution. This property is read-only. * second element the total time spent in SQL execution. This property is read-only.
* @property float $elapsedTime The total elapsed time in seconds for current request. This property is * @property float $elapsedTime The total elapsed time in seconds for current request. This property is
* read-only. * read-only.
* @property array $profiling The profiling results. Each array element has the following structure: * @property array $profiling The profiling results. Each array element has the following structure: `[$token,
* `[$token, $category, $time]`. This property is read-only. * $category, $time]`. This property is read-only.
* *
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
......
...@@ -384,7 +384,7 @@ class Connection extends Component ...@@ -384,7 +384,7 @@ class Connection extends Component
private function parseResponse($command) private function parseResponse($command)
{ {
if(($line = fgets($this->_socket)) === false) { if (($line = fgets($this->_socket)) === false) {
throw new Exception("Failed to read from socket.\nRedis command was: " . $command); throw new Exception("Failed to read from socket.\nRedis command was: " . $command);
} }
$type = $line[0]; $type = $line[0];
...@@ -405,7 +405,7 @@ class Connection extends Component ...@@ -405,7 +405,7 @@ class Connection extends Component
$length = $line + 2; $length = $line + 2;
$data = ''; $data = '';
while ($length > 0) { while ($length > 0) {
if(($block = fread($this->_socket, $line + 2)) === false) { if (($block = fread($this->_socket, $line + 2)) === false) {
throw new Exception("Failed to read from socket.\nRedis command was: " . $command); throw new Exception("Failed to read from socket.\nRedis command was: " . $command);
} }
$data .= $block; $data .= $block;
...@@ -415,7 +415,7 @@ class Connection extends Component ...@@ -415,7 +415,7 @@ class Connection extends Component
case '*': // Multi-bulk replies case '*': // Multi-bulk replies
$count = (int) $line; $count = (int) $line;
$data = []; $data = [];
for($i = 0; $i < $count; $i++) { for ($i = 0; $i < $count; $i++) {
$data[] = $this->parseResponse($command); $data[] = $this->parseResponse($command);
} }
return $data; return $data;
......
...@@ -367,8 +367,8 @@ pre .diff .change{ ...@@ -367,8 +367,8 @@ pre .diff .change{
<ul> <ul>
<?= $handler->renderCallStackItem($exception->getFile(), $exception->getLine(), null, null, 1) ?> <?= $handler->renderCallStackItem($exception->getFile(), $exception->getLine(), null, null, 1) ?>
<?php for ($i = 0, $trace = $exception->getTrace(), $length = count($trace); $i < $length; ++$i): ?> <?php for ($i = 0, $trace = $exception->getTrace(), $length = count($trace); $i < $length; ++$i): ?>
<?=$handler->renderCallStackItem(@$trace[$i]['file'] ?: null, @$trace[$i]['line'] ?: null, <?= $handler->renderCallStackItem(@$trace[$i]['file'] ?: null, @$trace[$i]['line'] ?: null,
@$trace[$i]['class'] ?: null, @$trace[$i]['function'] ?: null, $i + 2); ?> @$trace[$i]['class'] ?: null, @$trace[$i]['function'] ?: null, $i + 2) ?>
<?php endfor; ?> <?php endfor; ?>
</ul> </ul>
</div> </div>
......
Yii 2.0 Unit tests
==================
DIRECTORY STRUCTURE
-------------------
unit/ Unit tests to run with PHPUnit
data/ models, config and other test data
config.php this file contains configuration for database and caching backends
framework/ the framework unit tests
runtime/ the application runtime dir for the yii test app
web/ webapp for functional testing
HOW TO RUN THE TESTS
--------------------
Make sure you have PHPUnit installed.
Run PHPUnit in the yii repo base directory.
```php
phpunit
```
You can run tests for specific groups only:
```php
phpunit --group=mysql,base,i18n
```
You can get a list of available groups via `phpunit --list-groups`.
TEST CONFIGURATION
------------------
PHPUnit configuration is in `phpunit.xml.dist` in repository root folder.
You can create your own phpunit.xml to override dist config.
Database and other backend system configuration can be found in `unit/data/config.php`
adjust them to your needs to allow testing databases and caching in your environment.
\ No newline at end of file
...@@ -24,11 +24,11 @@ class RedisCacheTest extends CacheTestCase ...@@ -24,11 +24,11 @@ class RedisCacheTest extends CacheTestCase
'dataTimeout' => 0.1, 'dataTimeout' => 0.1,
]; ];
$dsn = $config['hostname'] . ':' .$config['port']; $dsn = $config['hostname'] . ':' .$config['port'];
if(!@stream_socket_client($dsn, $errorNumber, $errorDescription, 0.5)) { if (!@stream_socket_client($dsn, $errorNumber, $errorDescription, 0.5)) {
$this->markTestSkipped('No redis server running at ' . $dsn .' : ' . $errorNumber . ' - ' . $errorDescription); $this->markTestSkipped('No redis server running at ' . $dsn .' : ' . $errorNumber . ' - ' . $errorDescription);
} }
if($this->_cacheInstance === null) { if ($this->_cacheInstance === null) {
$this->_cacheInstance = new RedisCache($config); $this->_cacheInstance = new RedisCache($config);
} }
return $this->_cacheInstance; return $this->_cacheInstance;
......
...@@ -73,7 +73,7 @@ class ConsoleTest extends TestCase ...@@ -73,7 +73,7 @@ class ConsoleTest extends TestCase
/* public function testScreenSize() /* public function testScreenSize()
{ {
for($i = 1; $i < 20; $i++) { for ($i = 1; $i < 20; $i++) {
echo implode(', ', Console::getScreenSize(true)) . "\n"; echo implode(', ', Console::getScreenSize(true)) . "\n";
ob_flush(); ob_flush();
sleep(1); sleep(1);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
namespace yiiunit\framework\i18n; namespace yiiunit\framework\i18n;
use yii\i18n\FallbackMessageFormatter; use yii\i18n\MessageFormatter;
use yiiunit\TestCase; use yiiunit\TestCase;
/** /**
...@@ -34,6 +34,24 @@ class FallbackMessageFormatterTest extends TestCase ...@@ -34,6 +34,24 @@ class FallbackMessageFormatterTest extends TestCase
] ]
], ],
[
'{'.self::SUBJECT.'} is {'.self::N.', number}', // pattern
self::SUBJECT_VALUE.' is '.self::N_VALUE, // expected
[ // params
self::N => self::N_VALUE,
self::SUBJECT => self::SUBJECT_VALUE,
]
],
[
'{'.self::SUBJECT.'} is {'.self::N.', number, integer}', // pattern
self::SUBJECT_VALUE.' is '.self::N_VALUE, // expected
[ // params
self::N => self::N_VALUE,
self::SUBJECT => self::SUBJECT_VALUE,
]
],
// This one was provided by Aura.Intl. Thanks! // This one was provided by Aura.Intl. Thanks!
[<<<_MSG_ [<<<_MSG_
{gender_of_host, select, {gender_of_host, select,
...@@ -115,19 +133,10 @@ _MSG_ ...@@ -115,19 +133,10 @@ _MSG_
/** /**
* @dataProvider patterns * @dataProvider patterns
*/ */
public function testNamedArgumentsStatic($pattern, $expected, $args) public function testNamedArguments($pattern, $expected, $args)
{ {
$result = FallbackMessageFormatter::formatMessage('en_US', $pattern, $args); $formatter = new FallbackMessageFormatter();
$this->assertEquals($expected, $result); $result = $formatter->fallbackFormat($pattern, $args, 'en_US');
}
/**
* @dataProvider patterns
*/
public function testNamedArgumentsObject($pattern, $expected, $args)
{
$formatter = new FallbackMessageFormatter('en_US', $pattern);
$result = $formatter->format($args);
$this->assertEquals($expected, $result, $formatter->getErrorMessage()); $this->assertEquals($expected, $result, $formatter->getErrorMessage());
} }
...@@ -135,9 +144,10 @@ _MSG_ ...@@ -135,9 +144,10 @@ _MSG_
{ {
$expected = '{'.self::SUBJECT.'} is '.self::N_VALUE; $expected = '{'.self::SUBJECT.'} is '.self::N_VALUE;
$result = FallbackMessageFormatter::formatMessage('en_US', '{'.self::SUBJECT.'} is {'.self::N.'}', [ $formatter = new FallbackMessageFormatter();
$result = $formatter->fallbackFormat('{'.self::SUBJECT.'} is {'.self::N.'}', [
self::N => self::N_VALUE, self::N => self::N_VALUE,
]); ], 'en_US');
$this->assertEquals($expected, $result); $this->assertEquals($expected, $result);
} }
...@@ -145,11 +155,17 @@ _MSG_ ...@@ -145,11 +155,17 @@ _MSG_
public function testNoParams() public function testNoParams()
{ {
$pattern = '{'.self::SUBJECT.'} is '.self::N; $pattern = '{'.self::SUBJECT.'} is '.self::N;
$result = FallbackMessageFormatter::formatMessage('en_US', $pattern, []);
$this->assertEquals($pattern, $result);
$formatter = new FallbackMessageFormatter('en_US', $pattern); $formatter = new FallbackMessageFormatter();
$result = $formatter->format([]); $result = $formatter->fallbackFormat($pattern, [], 'en_US');
$this->assertEquals($pattern, $result, $formatter->getErrorMessage()); $this->assertEquals($pattern, $result, $formatter->getErrorMessage());
} }
}
class FallbackMessageFormatter extends MessageFormatter
{
public function fallbackFormat($pattern, $args, $locale)
{
return parent::fallbackFormat($pattern, $args, $locale);
}
} }
\ No newline at end of file
...@@ -41,6 +41,15 @@ class MessageFormatterTest extends TestCase ...@@ -41,6 +41,15 @@ class MessageFormatterTest extends TestCase
] ]
], ],
[
'{'.self::SUBJECT.'} is {'.self::N.', number, integer}', // pattern
self::SUBJECT_VALUE.' is '.self::N_VALUE, // expected
[ // params
self::N => self::N_VALUE,
self::SUBJECT => self::SUBJECT_VALUE,
]
],
// This one was provided by Aura.Intl. Thanks! // This one was provided by Aura.Intl. Thanks!
[<<<_MSG_ [<<<_MSG_
{gender_of_host, select, {gender_of_host, select,
...@@ -119,59 +128,116 @@ _MSG_ ...@@ -119,59 +128,116 @@ _MSG_
]; ];
} }
public function parsePatterns()
{
return [
[
self::SUBJECT_VALUE.' is {0, number}', // pattern
self::SUBJECT_VALUE.' is '.self::N_VALUE, // expected
[ // params
0 => self::N_VALUE,
]
],
[
self::SUBJECT_VALUE.' is {'.self::N.', number}', // pattern
self::SUBJECT_VALUE.' is '.self::N_VALUE, // expected
[ // params
self::N => self::N_VALUE,
]
],
[
self::SUBJECT_VALUE.' is {'.self::N.', number, integer}', // pattern
self::SUBJECT_VALUE.' is '.self::N_VALUE, // expected
[ // params
self::N => self::N_VALUE,
]
],
[
"{0,number,integer} monkeys on {1,number,integer} trees make {2,number} monkeys per tree",
"4,560 monkeys on 123 trees make 37.073 monkeys per tree",
[
0 => 4560,
1 => 123,
2 => 37.073
],
'en_US'
],
[
"{0,number,integer} Affen auf {1,number,integer} Bäumen sind {2,number} Affen pro Baum",
"4.560 Affen auf 123 Bäumen sind 37,073 Affen pro Baum",
[
0 => 4560,
1 => 123,
2 => 37.073
],
'de',
],
[
"{monkeyCount,number,integer} monkeys on {trees,number,integer} trees make {monkeysPerTree,number} monkeys per tree",
"4,560 monkeys on 123 trees make 37.073 monkeys per tree",
[
'monkeyCount' => 4560,
'trees' => 123,
'monkeysPerTree' => 37.073
],
'en_US'
],
[
"{monkeyCount,number,integer} Affen auf {trees,number,integer} Bäumen sind {monkeysPerTree,number} Affen pro Baum",
"4.560 Affen auf 123 Bäumen sind 37,073 Affen pro Baum",
[
'monkeyCount' => 4560,
'trees' => 123,
'monkeysPerTree' => 37.073
],
'de',
],
];
}
/** /**
* @dataProvider patterns * @dataProvider patterns
*/ */
public function testNamedArgumentsStatic($pattern, $expected, $args) public function testNamedArguments($pattern, $expected, $args)
{ {
$result = MessageFormatter::formatMessage('en_US', $pattern, $args); $formatter = new MessageFormatter();
$this->assertEquals($expected, $result, intl_get_error_message()); $result = $formatter->format($pattern, $args, 'en_US');
$this->assertEquals($expected, $result, $formatter->getErrorMessage());
} }
/** /**
* @dataProvider patterns * @dataProvider parsePatterns
*/ */
public function testNamedArgumentsObject($pattern, $expected, $args) public function testParseNamedArguments($pattern, $expected, $args, $locale = 'en_US')
{ {
$formatter = new MessageFormatter('en_US', $pattern); $formatter = new MessageFormatter();
$result = $formatter->format($args); $result = $formatter->parse($pattern, $expected, $locale);
$this->assertEquals($expected, $result, $formatter->getErrorMessage()); $this->assertEquals($args, $result, $formatter->getErrorMessage() . ' Pattern: ' . $pattern);
} }
public function testInsufficientArguments() public function testInsufficientArguments()
{ {
$expected = '{'.self::SUBJECT.'} is '.self::N_VALUE; $expected = '{'.self::SUBJECT.'} is '.self::N_VALUE;
$result = MessageFormatter::formatMessage('en_US', '{'.self::SUBJECT.'} is {'.self::N.', number}', [ $formatter = new MessageFormatter();
$result = $formatter->format('{'.self::SUBJECT.'} is {'.self::N.', number}', [
self::N => self::N_VALUE, self::N => self::N_VALUE,
]); ], 'en_US');
$this->assertEquals($expected, $result, intl_get_error_message());
}
/** $this->assertEquals($expected, $result, $formatter->getErrorMessage());
* When instantiating a MessageFormatter with invalid pattern it should be null with default settings.
* It will be IntlException if intl.use_exceptions=1 and PHP 5.5 or newer or an error if intl.error_level is not 0.
*/
public function testNullConstructor()
{
if(ini_get('intl.use_exceptions')) {
$this->setExpectedException('IntlException');
}
if (!ini_get('intl.error_level') || ini_get('intl.use_exceptions')) {
$this->assertNull(new MessageFormatter('en_US', ''));
}
} }
public function testNoParams() public function testNoParams()
{ {
$pattern = '{'.self::SUBJECT.'} is '.self::N; $pattern = '{'.self::SUBJECT.'} is '.self::N;
$result = MessageFormatter::formatMessage('en_US', $pattern, []); $formatter = new MessageFormatter();
$this->assertEquals($pattern, $result, intl_get_error_message()); $result = $formatter->format($pattern, [], 'en_US');
$formatter = new MessageFormatter('en_US', $pattern);
$result = $formatter->format([]);
$this->assertEquals($pattern, $result, $formatter->getErrorMessage()); $this->assertEquals($pattern, $result, $formatter->getErrorMessage());
} }
} }
\ No newline at end of file
...@@ -59,7 +59,7 @@ class UrlValidatorTest extends TestCase ...@@ -59,7 +59,7 @@ class UrlValidatorTest extends TestCase
public function testValidateWithIdn() public function testValidateWithIdn()
{ {
if(!function_exists('idn_to_ascii')) { if (!function_exists('idn_to_ascii')) {
$this->markTestSkipped('intl package required'); $this->markTestSkipped('intl package required');
return; return;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment