Commit a0384498 by Klimov Paul

Merge branch 'master' of github.com:yiisoft/yii2 into mongo

parents 9da7a80f 05272b71
......@@ -78,9 +78,43 @@ directory and Yii will be able to autoload any class in this library.
Autoloading
-----------
TBD
All classes, interfaces and traits are loaded automatically at the moment they are used. There's no need to use
`include` or `require`. It is, as well, true for Composer-loaded packages and Yii extensions.
Autoloader works according to [PSR-0](). That means namespaces and class, interface and trait
names should correspond to file system paths except root namespace path that is defined by an alias.
For example, if standard alias `@app` refers to `/var/www/example.com/` then `\app\models\User` will be loaded from
`/var/www/example.com/app/models/User.php`.
Custom alias may be added using the following code:
```php
Yii::setAlias('shared', realpath('~/src/shared'));
```
Additional autoloaders may be registered using standard PHP `spl_autoload_register`.
Helper classes
--------------
TDB
\ No newline at end of file
Helper class typically contains static methods only and used as follows:
```php
use \yii\helpers\Html;
echo Html::encode('Test > test');
```
There are several classes provided by framework:
- ArrayHelper
- Console
- FileHelper
- Html
- HtmlPurifier
- Inflector
- Json
- Markdown
- Security
- StringHelper
- VarDumper
\ No newline at end of file
......@@ -21,7 +21,11 @@ console applications it's `yii`. Both are doing nearly the same job:
5. Creating new application instance using `$config` and running it.
The Bootstrap file is not the part of framework but your application so it's OK to adjust it to fit your application. Typical
adjustments are the value of `YII_DEBUG` that should never be `true` on production and the way config is read.
adjustments are the value of `YII_DEBUG` that should never be `true` on production and the way config is read:
```php
defined('YII_DEBUG') or define('YII_DEBUG', false);
```
Configuring application instance
--------------------------------
......
......@@ -1385,6 +1385,8 @@ abstract class ActiveRecord extends Model
$this->populateRelation($offset, $item);
return;
}
} catch (InvalidParamException $e) {
// shut down exception : has getter, but not relation
} catch (UnknownMethodException $e) {
throw $e->getPrevious();
}
......
......@@ -519,12 +519,14 @@ class BaseYii
* Configures an object with the initial property values.
* @param object $object the object to be configured
* @param array $properties the property initial values given in terms of name-value pairs.
* @return object the object itself
*/
public static function configure($object, $properties)
{
foreach ($properties as $name => $value) {
$object->$name = $value;
}
return $object;
}
/**
......
......@@ -459,6 +459,15 @@ abstract class Application extends Module
}
/**
* Returns the mailer component.
* @return \yii\mail\MailerInterface the mailer interface
*/
public function getMail()
{
return $this->getComponent('mail');
}
/**
* Returns the auth manager for this application.
* @return \yii\rbac\Manager the auth manager for this application.
*/
......
......@@ -33,7 +33,7 @@ use yii\helpers\ArrayHelper;
*
* ~~~
* CREATE TABLE tbl_migration (
* version varchar(255) PRIMARY KEY,
* version varchar(180) PRIMARY KEY,
* apply_time integer
* )
* ~~~
......
......@@ -50,6 +50,28 @@ class Schema extends \yii\db\Schema
];
/**
* Quotes a table name for use in a query.
* A simple table name has no schema prefix.
* @param string $name table name
* @return string the properly quoted table name
*/
public function quoteSimpleTableName($name)
{
return strpos($name, "`") !== false ? $name : "`" . $name . "`";
}
/**
* Quotes a column name for use in a query.
* A simple column name has no prefix.
* @param string $name column name
* @return string the properly quoted column name
*/
public function quoteSimpleColumnName($name)
{
return strpos($name, '`') !== false || $name === '*' ? $name : '`' . $name . '`';
}
/**
* Creates a query builder for the MySQL database.
* This method may be overridden by child classes to create a DBMS-specific query builder.
* @return QueryBuilder query builder instance
......
......@@ -111,10 +111,9 @@ class BaseVarDumper
} else {
$id = array_push(self::$_objects, $var);
$className = get_class($var);
$members = (array)$var;
$spaces = str_repeat(' ', $level * 4);
self::$_output .= "$className#$id\n" . $spaces . '(';
foreach ($members as $key => $value) {
foreach ((array)$var as $key => $value) {
$keyDisplay = strtr(trim($key), ["\0" => ':']);
self::$_output .= "\n" . $spaces . " [$keyDisplay] => ";
self::dumpInternal($value, $level + 1);
......
......@@ -7,6 +7,10 @@
namespace yii\log;
use Yii;
use yii\base\InvalidConfigException;
use yii\mail\MailerInterface;
/**
* EmailTarget sends selected log messages to the specified email addresses.
*
......@@ -20,51 +24,57 @@ namespace yii\log;
class EmailTarget extends Target
{
/**
* @var array list of destination email addresses.
*/
public $emails = [];
/**
* @var string email subject
* @var array the configuration array for creating a [[\yii\mail\MessageInterface|message]] object.
* Note that the "to" option must be set, which specifies the destination email address(es).
*/
public $subject;
public $message = [];
/**
* @var string email sent-from address
* @var MailerInterface|string the mailer object or the application component ID of the mailer object.
* After the EmailTarget object is created, if you want to change this property, you should only assign it
* with a mailer object.
*/
public $sentFrom;
public $mail = 'mail';
/**
* @var array list of additional headers to use when sending an email.
* @inheritdoc
*/
public $headers = [];
public function init()
{
parent::init();
if (empty($this->message['to'])) {
throw new InvalidConfigException('The "to" option must be set for EmailTarget::message.');
}
if (empty($this->message['subject'])) {
$this->message['subject'] = Yii::t('yii', 'Application Log');
}
if (is_string($this->mail)) {
$this->mail = Yii::$app->getComponent($this->mail);
}
if (!$this->mail instanceof MailerInterface) {
throw new InvalidConfigException("EmailTarget::mailer must be either a mailer object or the application component ID of a mailer object.");
}
}
/**
* Sends log messages to specified email addresses.
*/
public function export()
{
$body = '';
foreach ($this->messages as $message) {
$body .= $this->formatMessage($message);
}
$body = wordwrap($body, 70);
$subject = $this->subject === null ? \Yii::t('yii', 'Application Log') : $this->subject;
foreach ($this->emails as $email) {
$this->sendEmail($subject, $body, $email, $this->sentFrom, $this->headers);
}
$messages = array_map([$this, 'formatMessage'], $this->messages);
$body = wordwrap(implode("\n", $messages), 70);
$this->composeMessage($body)->send($this->mail);
}
/**
* Sends an email.
* @param string $subject email subject
* @param string $body email body
* @param string $sentTo sent-to email address
* @param string $sentFrom sent-from email address
* @param array $headers additional headers to be used when sending the email
* Composes a mail message with the given body content.
* @param string $body the body content
* @return \yii\mail\MessageInterface $message
*/
protected function sendEmail($subject, $body, $sentTo, $sentFrom, $headers)
protected function composeMessage($body)
{
if ($sentFrom !== null) {
$headers[] = "From: {$sentFrom}";
}
mail($sentTo, $subject, $body, implode("\r\n", $headers));
$message = $this->mail->compose();
Yii::configure($message, $this->message);
$message->setTextBody($body);
return $message;
}
}
......@@ -233,6 +233,6 @@ abstract class Target extends Component
$text = var_export($text, true);
}
$ip = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '127.0.0.1';
return date('Y/m/d H:i:s', $timestamp) . " [$ip] [$level] [$category] $text\n";
return date('Y/m/d H:i:s', $timestamp) . " [$ip] [$level] [$category] $text";
}
}
......@@ -26,19 +26,14 @@ use Yii;
abstract class BaseMessage extends Object implements MessageInterface
{
/**
* @return MailerInterface the mailer component
*/
public function getMailer()
{
return Yii::$app->getComponent('mail');
}
/**
* {@inheritdoc}
*/
public function send()
public function send(MailerInterface $mailer = null)
{
return $this->getMailer()->send($this);
if ($mailer === null) {
$mailer = Yii::$app->getMail();
}
return $mailer->send($this);
}
/**
......
......@@ -204,9 +204,11 @@ interface MessageInterface
/**
* Sends this email message.
* @param MailerInterface $mailer the mailer that should be used to send this message.
* If null, the "mail" application component will be used instead.
* @return boolean whether this message is sent successfully.
*/
public function send();
public function send(MailerInterface $mailer = null);
/**
* Returns string representation of this message.
......
......@@ -27,4 +27,4 @@ class VendorTestCase extends TestCase
throw new NotSupportedException("Vendor autoload file '{$vendorAutoload}' is missing.");
}
}
}
\ No newline at end of file
}
......@@ -79,10 +79,10 @@ class ActiveRecordTest extends SphinxTestCase
// asArray
$article = ArticleIndex::find()->where('id=2')->asArray()->one();
unset($article['add_date']);
$this->assertEquals([
'id' => '2',
'author_id' => '2',
'add_date' => '1384466400',
'tag' => '3,4',
], $article);
......
......@@ -56,7 +56,9 @@ class MessageTest extends VendorTestCase
*/
protected function createTestEmailComponent()
{
$component = new Mailer();
$component = new Mailer([
'useFileTransport' => true,
]);
return $component;
}
......
......@@ -17,6 +17,6 @@ class SqliteCommandTest extends CommandTest
$sql = 'SELECT [[id]], [[t.name]] FROM {{tbl_customer}} t';
$command = $db->createCommand($sql);
$this->assertEquals("SELECT \"id\", 't'.\"name\" FROM 'tbl_customer' t", $command->sql);
$this->assertEquals("SELECT `id`, `t`.`name` FROM `tbl_customer` t", $command->sql);
}
}
......@@ -30,8 +30,8 @@ class SqliteConnectionTest extends ConnectionTest
public function testQuoteTableName()
{
$connection = $this->getConnection(false);
$this->assertEquals("'table'", $connection->quoteTableName('table'));
$this->assertEquals("'schema'.'table'", $connection->quoteTableName('schema.table'));
$this->assertEquals("`table`", $connection->quoteTableName('table'));
$this->assertEquals("`schema`.`table`", $connection->quoteTableName('schema.table'));
$this->assertEquals('{{table}}', $connection->quoteTableName('{{table}}'));
$this->assertEquals('(table)', $connection->quoteTableName('(table)'));
}
......@@ -39,8 +39,8 @@ class SqliteConnectionTest extends ConnectionTest
public function testQuoteColumnName()
{
$connection = $this->getConnection(false);
$this->assertEquals('"column"', $connection->quoteColumnName('column'));
$this->assertEquals("'table'.\"column\"", $connection->quoteColumnName('table.column'));
$this->assertEquals('`column`', $connection->quoteColumnName('column'));
$this->assertEquals("`table`.`column`", $connection->quoteColumnName('table.column'));
$this->assertEquals('[[column]]', $connection->quoteColumnName('[[column]]'));
$this->assertEquals('{{column}}', $connection->quoteColumnName('{{column}}'));
$this->assertEquals('(column)', $connection->quoteColumnName('(column)'));
......
......@@ -85,6 +85,6 @@ class SqliteQueryBuilderTest extends QueryBuilderTest
public function testBatchInsert()
{
$sql = $this->getQueryBuilder()->batchInsert('{{tbl_customer}} t', ['t.id','t.name'], array(array(1,'a'), array(2,'b')));
$this->assertEquals("INSERT INTO {{tbl_customer}} t ('t'.\"id\", 't'.\"name\") SELECT 1, 'a' UNION ALL 2, 'b'", $sql);
$this->assertEquals("INSERT INTO {{tbl_customer}} t (`t`.`id`, `t`.`name`) SELECT 1, 'a' UNION ALL 2, 'b'", $sql);
}
}
......@@ -40,18 +40,11 @@ class BaseMessageTest extends TestCase
// Tests :
public function testGetMailer()
{
$mailer = $this->getMailer();
$message = $mailer->compose();
$this->assertEquals($mailer, $message->getMailer());
}
public function testSend()
{
$mailer = $this->getMailer();
$message = $mailer->compose();
$message->send();
$message->send($mailer);
$this->assertEquals($message, $mailer->sentMessages[0], 'Unable to send message!');
}
......
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