PHPixieの新しいクイックスタート:quote-by-commit見積シートの作成

画像 過去1年にわたり、PHPixieは多くの新機能といくつかのコンポーネントを追加し、開発者のしきい値を下げるために標準のバンドル構造がわずかに変更されました。 それで、新しいチュートリアルを作成する時が来ました。そして今度はそれを少し違ったものにしようとします。 完成したデモプロジェクトを説明とともに見るのではなく、徐々に進み、各反復で完全に機能するサイトを作成します。 ログイン、登録、ソーシャルネットワークとの統合、統計用のコンソールコマンドを含む簡単な見積もりボックスを作成します。 githubコミットの完全な履歴。







1.プロジェクトの作成



始める前に、 チャットで「こんにちは」と発声してください。そこで発生する可能性のある問題の99%は、ほぼ瞬時に解決されます。

Composerが必要です。インストール後、次を実行します。







php composer.phar create-project phpixie/project
      
      





これにより、 プロジェクトスケルトンと1つのバンドル「app」を含むプロジェクトフォルダが作成されます。 バンドルは、コードモジュール、テンプレート、CSSなどです。 アプリケーションの一部に関連しています。 Composerを使用して、プロジェクトからプロジェクトに簡単に転送できます。 アプリケーションのロジック全体が含まれるバンドルを1つだけ使用します。







次に、仮想ホストを作成し、プロジェクト内の/ webフォルダーにリダイレクトする必要があります。 すべてが順調に進んだら、ブラウザでhttp:// localhost /に移動すると、挨拶が表示されます。 http:// localhost / greetに移動して、ルーティングが機能するかどうかをすぐに確認します。







Windowsを使用している場合、 create-projectコマンドを実行するとエラーが発生する可能性が高くなります。これは、このPHP OSでsymlink()関数が機能しないためです。 単に無視することができますが、少し後でこの問題を回避する方法を示します。







この段階でのプロジェクトのステータス(コミット1)







2.メッセージを表示する



データベースに接続することから始めましょう。このために/assets/config/database.phpを編集します 。 プロジェクトフォルダーから2つのコンソールコマンドを実行して、接続を確認できます。







 ./console framework:database drop #      ./console framework:database create #     
      
      





次に、 /assets / migrate / migrations / 1_users_and_messages.sqlのテーブル構造を使用して移行を作成します。







 CREATE TABLE users( id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255) NOT NULL, email VARCHAR(255) UNIQUE, passwordHash VARCHAR(255) ); -- statement CREATE TABLE messages( id INT PRIMARY KEY AUTO_INCREMENT, userId INT NOT NULL, text VARCHAR(255) NOT NULL, date DATETIME NOT NULL, FOREIGN KEY (userId) REFERENCES users(id) );
      
      





-- statement



を使用してリクエストを分離していることに注意してください。







また、データベースを埋めるためにいくつかのデータをすぐに追加します。これのために、 / assets / migrate / seeds /にファイルを作成します。ここで、ファイル名はテーブル名に対応します。







 <?php // /assets/migrate/seeds/messages.php return [ [ 'id' => 1, 'userId' => 1, 'text' => "Hello World!", 'date' => '2016-12-01 10:15:00' ], // .... ]
      
      





これらのファイルの完全なコンテンツは、githubで表示できます。 次に、さらに2つのコンソールコマンドを実行します。







 ./console framework:migrate #   ./console framework:seed #   
      
      





これで、最初のページに進むことができます。 最初に、ルートが構成されている/bundles/app/assets/config/routeResolver.phpファイル、つまり、どのプロセッサーがどのリンクに対応するかを検討します。 メッセージの表示を担当するメッセージプロセッサを追加します。 デフォルトとして登録し、すぐにメインページのルートを追加します。







 return array( 'type' => 'group', 'defaults' => array('action' => 'default'), 'resolvers' => array( 'action' => array( 'path' => '<processor>/<action>' ), 'processor' => array( 'path' => '(<processor>)', 'defaults' => array('processor' => 'messages') ), //     'frontpage' => array( 'path' => '', 'defaults' => ['processor' => 'messages'] ) ) );
      
      





親テンプレート/bundles/app/assets/template/layout.php変更してレイアウトを開始し、それにBootstrap 4とCSSを追加します。







 <!DOCTYPE html> <html lang="en"> <head> <!-- Bootstrap 4 --> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta http-equiv="x-ua-compatible" content="ie=edge"> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css"> <!--   CSS,     --> <link rel="stylesheet" href="/bundles/app/main.css"> <!--         Quickstart --> <title><?=$_($this->get('pageTitle', 'Quickstart'))?></title> </head> <body> <!-- Navigation --> <nav class="navbar navbar-toggleable-md navbar-light bg-faded"> <div class="container"> <!--     --> <a class="navbar-brand mr-auto" href="<?=$this->httpPath('app.frontpage')?>">Quickstart</a> </div> </nav> <!--       --> <?php $this->childContent(); ?> <!-- Bootstrap dependencies --> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.3.7/js/tether.min.js"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/js/bootstrap.min.js"></script> </body> </html>
      
      





main.cssファイルを作成する場所は? 必要なファイルはすべてバンドル内に最適に保持されるため、これは/ bundles / app / web /フォルダーになります。 作曲家がプロジェクトを作成すると、 / bundles / app / webを含むシンボリックリンクがこのフォルダーに自動的に作成され、これらのファイルにブラウザーからアクセスできるようになります。 Windowsでは、ショートカットを作成する代わりに、コマンドを実行するフォルダーをコピーする必要があります。







 #    web    /web/bundles ./console framework:installWebAssets --copy
      
      





/bundles/app/src/HTTP/Messages.phpに新しいプロセッサを作成します







 namespace Project\App\HTTP; use PHPixie\HTTP\Request; /** *   */ class Messages extends Processor { /** * @param Request $request HTTP request * @return mixed */ public function defaultAction($request) { $components = $this->components(); //    $messages = $components->orm()->query('message') ->orderDescendingBy('date') ->find(); //   return $components->template()->get('app:messages', [ 'messages' => $messages ]); } }
      
      





重要:/bundles/app/src/HTTP.phpに登録することを忘れないでください







 namespace Project\App; class HTTP extends \PHPixie\DefaultBundle\HTTP { //        protected $classMap = array( 'messages' => 'Project\App\HTTP\Messages' ); }
      
      





ほぼ完了しました。 アプリに追いつくためだけに残っています。プロセッサが使用するメッセージテンプレートです。これが最も簡単な部分です。







 <?php //   $this->layout('app:layout'); //    //        $this->set('pageTitle', "Messages"); ?> <div class="container content"> <--   --> <?php foreach($messages as $message): ?> <blockquote class="blockquote"> <--     $_()    XSS --> <p class="mb-0"><?=$_($message->text)?></p> <footer class="blockquote-footer"> posted at <?=$this->formatDate($message->date, 'j MY, H:i')?> </footer> </blockquote> <?php endforeach; ?> </div>
      
      





すべて準備が整ったので、 http:// localhostに移動します。メッセージの完全なリストが表示されます。







この段階でのプロジェクトのステータス(コミット2)







3. ORMリンクとページネーション



各メッセージの下でそれを作成したユーザーを示すために、テーブル間の関係を登録する必要があります。 移行では、各メッセージが1 対多の関係になるように、各メッセージに必須のuserIdフィールドが含まれることを示しました。







 // bundles/app/assets/config/orm.php return [ 'relationships' => [ //      [ 'type' => 'oneToMany', 'owner' => 'user', 'items' => 'message' ] ] ];
      
      





ページパラメータを使用してメッセージをページ分割する新しいルートを追加します。







 // /bundles/app/assets/config/routeResolver.php return array( // .... 'resolvers' => array( 'messages' => array( 'path' => 'page(/<page>)', 'defaults' => ['processor' => 'messages'] ), // .... ) );
      
      





そして、メッセージプロセッサ自体を少し変更します。







 public function defaultAction($request) { $components = $this->components(); //   $messageQuery = $components->orm()->query('message') ->orderDescendingBy('date'); //         //          $pager = $components->paginateOrm() ->queryPager($messageQuery, 10, ['user']); //        $page = $request->attributes()->get('page', 1); $pager->setCurrentPage($page); //    return $components->template()->get('app:messages', [ 'pager' => $pager ]); }
      
      





テンプレートで、 $pager->getCurrentItems()



を使用してこのページのメッセージを取得し、 $pager->getCurrentItems()



$message->user()



$message->user()



に関する情報を取得し、ページャーに追いつくことができます。 ここではページ全体のテンプレートをコピーしません。リポジトリで表示できます。







この段階でのプロジェクトのステータス(コミット3)







4.ユーザー認証



ユーザーにメッセージの書き込みを許可する前に、ユーザーに許可を与える必要があります。 これを行うには、ユーザーとそのリポジトリの本質を指定して拡張する必要があります。 ここでは、エンティティが1人のユーザーを表し、リポジトリがこれらのエンティティを検索および作成する方法を提供するという違いを理解することが重要です。 パスワード認証のために、いくつかのインターフェースを実装する必要がありますが、これらはすべて非常に簡単です。







 // /bundles/app/src/ORM/User.php namespace Project\App\ORM; use Project\App\ORM\Model\Entity; /**        */ use PHPixie\AuthLogin\Repository\User as LoginUser; /** *   */ class User extends Entity implements LoginUser { /** *     . *        'passwordHash'. * @return string|null */ public function passwordHash() { return $this->getField('passwordHash'); } }
      
      





 namespace Project\App\ORM\User; use Project\App\ORM\Model\Repository; use Project\App\ORM\User; /**        */ use PHPixie\AuthLogin\Repository as LoginUserRepository; /** *   */ class UserRepository extends Repository implements LoginUserRepository { /** *     id * @param mixed $id * @return User|null */ public function getById($id) { return $this->query() ->in($id) ->findOne(); } /** *    ,      email. *            *       . * @param mixed $login * @return User|null */ public function getByLogin($login) { return $this->query() ->where('email', $login) ->findOne(); } }
      
      





重要:これらのクラスを/bundles/app/src/ORM.phpに登録することを忘れないでください







 namespace Project\App; /** *      */ class ORM extends \PHPixie\DefaultBundle\ORM { protected $entityMap = array( 'user' => 'Project\App\ORM\User' ); protected $repositoryMap = [ 'user' => 'Project\App\ORM\User\UserRepository' ]; }
      
      





認可設定を/assets/config/auth.phpに書き込みます:







 // /assets/config/auth.php return [ 'domains' => [ 'default' => [ //  ORM    'repository' => 'framework.orm.user', //         'providers' => [ //    'session' => [ 'type' => 'http.session' ], //   'password' => [ 'type' => 'login.password', //    ,     'persistProviders' => ['session'] ] ] ] ] ];
      
      





ログインページを追加するだけです。このために、新しいプロセッサを作成します。







 namespace Project\App\HTTP; use PHPixie\AuthLogin\Providers\Password; use PHPixie\HTTP\Request; use PHPixie\Validate\Form; use Project\App\ORM\User\UserRepository; use PHPixie\App\ORM\User; /** *       */ class Auth extends Processor { /** * @param Request $request HTTP request * @return mixed */ public function defaultAction($request) { //    ,     if($this->user()) { return $this->redirect('app.frontpage'); } $components = $this->components(); //     $template = $components->template()->get('app:login', [ 'user' => $this->user() ]); $loginForm = $this->loginForm(); $template->loginForm = $loginForm; //         if($request->method() !== 'POST') { return $template; } $data = $request->data(); //      $loginForm->submit($data->get()); //           if($loginForm->isValid() && $this->processLogin($loginForm)) { return $this->redirect('app.frontpage'); } //       return $template; } /** *   * * @param Form $loginForm * @return bool    */ protected function processLogin($loginForm) { //   $user = $this->passwordProvider()->login( $loginForm->email, $loginForm->password ); //        ,      if($user === null) { $loginForm->result()->addMessageError("Invalid email or password"); return false; } return true; } /** *  * @return mixed */ public function logoutAction() { //       $domain = $this->components()->auth()->domain(); $domain->forgetUser(); //     return $this->redirect('app.frontpage'); } /** *    * @return Form */ protected function loginForm() { $validate = $this->components()->validate(); $validator = $validate->validator(); //    //(        ) $document = $validator->rule()->addDocument(); //    $document->valueField('email') ->required("Email is required"); $document->valueField('password') ->required("Password is required"); //      return $validate->form($validator); } /** *       /assets/config/auth.php * @return Password */ protected function passwordProvider() { $domain = $this->components()->auth()->domain(); return $domain->provider('password'); } }
      
      





ここですべてのコードをコピーしないように、承認フォーム自体に追いつくだけです。1つのフィールドの例を示します。







 <--   has-danger     --> <div class="form-group <?=$this->if($loginForm->fieldError('email'), "has-danger")?>"> <--        --> <input name="email" type="text" value="<?=$_($loginForm->fieldValue('email'))?>" class="form-control" placeholder="Username"> <--      --> <?php if($error = $loginForm->fieldError('email')): ?> <div class="form-control-feedback"><?=$error?></div> <?php endif;?> </div>
      
      





また、ログインとログアウトへのルートとリンクをヘッダーに追加すると、ログインは機能します。







この段階でのプロジェクトのステータス(コミット4)







5.登録



登録フォームは完全に類推して行われます。Authプロセッサーの変更を考慮してください。







 /** *   * @return Form */ protected function registerForm() { $validate = $this->components()->validate(); $validator = $validate->validator(); $document = $validator->rule()->addDocument(); //          . //         . //     hidden  "register"      //     $document->allowExtraFields(); //   $document->valueField('name') ->required("Name is required") ->addFilter() ->minLength(3) ->message("Username must contain at least 3 characters"); // Email       $document->valueField('email') ->required("Email is required") ->filter('email', "Please provide a valid email"); //    8  $document->valueField('password') ->required("Password is required") ->addFilter() ->minLength(8) ->message("Password must contain at least 8 characters"); //    $document->valueField('passwordConfirm') ->required("Please repeat your password"); //           $validator->rule()->callback(function($result, $value) { //      if($value['password'] !== $value['passwordConfirm']) { $result->field('passwordConfirm')->addMessageError("Passwords don't match"); } }); //      return $validate->form($validator); } /** *   * @param Form $registerForm * @return bool     */ protected function processRegister($registerForm) { /** @var UserRepository $userRepository */ $userRepository = $this->components()->orm()->repository('user'); //  email        if($userRepository->getByLogin($registerForm->email)) { $registerForm->result()->field('email')->addMessageError("This email is already taken"); return false; } //      $provider = $this->passwordProvider(); $user = $userRepository->create([ 'name' => $registerForm->name, 'email' => $registerForm->email, 'passwordHash' => $provider->hash($registerForm->password) ]); $user->save(); //    $provider->setUser($user); return true; }
      
      





唯一の注意点は、フォームのHTMLコードに非表示のregister



フィールドを追加したことです。これにより、このログインまたは登録を確認します。







この段階でのプロジェクトのステータス(コミット5)







6.ソーシャルログイン



次に、FacebookとTwitterからのログインを接続します。 まず、2つのフィールドfacebookId



twitterId



をユーザーテーブルに追加して、新しい移行を作成します。







 /* /assets/migrate/migrations/2_social_login.sql */ ALTER TABLE users ADD COLUMN twitterId VARCHAR(255) AFTER passwordHash; -- statement ALTER TABLE users ADD COLUMN facebookId VARCHAR(255) AFTER twitterId;
      
      





次に、これらのプラットフォームでアプリケーションを作成し、 appId



およびappSecret



を取得するappId



ありappSecret



。 登録時に、Callback Urlを正しく指定します。Twitterの場合はhttp://localhost.com/socialAuth/callback/twitter



場合はhttp://localhost.com/socialAuth/callback/twitter



を正しく指定します。 これらのルートは後で作成しますが、今のところ設定を記述します。







 // /assets/config/social.php return [ 'facebook' => [ 'type' => 'facebook', 'appId' => 'YOUR APP ID', 'appSecret' => 'YOUR APP SECRET' ], 'twitter' => [ 'type' => 'twitter', 'consumerKey' => 'YOUR APP ID', 'consumerSecret' => 'YOUR APP SECRET' ] ];
      
      





そして、使い慣れたauth.php



でソーシャルログインサポートを有効にします。







 // /assets/config/auth.php <?php return [ 'domains' => [ 'default' => [ // .... 'providers' => [ //..... //   'social' => [ 'type' => 'social.oauth', //       'persistProviders' => ['session'] ] ] ] ] ];
      
      





設定ですべてが完了しました。コードに取りかかりましょう。 パスワードでログインするために、リポジトリおよびユーザーエンティティのクラスにインターフェイスを実装する必要があったことを覚えていますか? ここでもう1つ追加されます。







 namespace Project\App\ORM\User; // .... /**       */ use PHPixie\AuthSocial\Repository as SocialRepository; class UserRepository extends Repository implements LoginUserRepository, SocialRepository { // .... /** *         Social. *       null. * * @param SocialUser $socialUser * @return User|null */ public function getBySocialUser($socialUser) { //          id , //  twitterId or facebookId $providerName = $socialUser->providerName(); $field = $this->socialIdField($providerName); //       return $this->query()->where($field, $socialUser->id())->findOne(); } /** *      id. *         'Id'    * * @param string $providerName * @return string */ public function socialIdField($providerName) { return $providerName.'Id'; } }
      
      





そして最後に、承認のための新しいプロセッサ自体:







 namespace Project\App\HTTP\Auth; use PHPixie\App\ORM\User; use PHPixie\AuthSocial\Providers\OAuth as OAuthProvider; use PHPixie\HTTP\Request; use Project\App\ORM\User\UserRepository; use Project\App\HTTP\Processor; use PHPixie\Social\OAuth\User as SocialUser; /** *     */ class Social extends Processor { /** *       *  Twitter  Facebook * * @param Request $request HTTP request * @return mixed */ public function defaultAction($request) { $provider = $request->attributes()->get('provider'); //    ,       if(empty($provider)) { return $this->redirect('app.processor', ['processor' => 'auth']); } //  URL       $callbackUrl = $this->buildCallbackUrl($provider); $url = $this->oauthProvider()->loginUrl($provider, $callbackUrl); return $this->responses()->redirect($url); } /** *    . *      http://localhost.com/socialAuth/callback/twitter *       . * * @param Request $request HTTP request * @return mixed */ public function callbackAction($request) { $provider = $request->attributes()->getRequired('provider'); //   URL  ,      $callbackUrl = $this->buildCallbackUrl($provider); $query = $request->query()->get(); //     //           . //             $userData $userData = $this->oauthProvider()->handleCallback($provider, $callbackUrl, $query); //  -   ,     //        if($userData === null) { return $this->redirect('app.processor', ['processor' => 'auth']); } //     ,     //            if($this->user() === null) { $user = $this->registerNewUser($userData); //      $this->oauthProvider()->setUser($user); } //    ,        return $this->redirect('app.frontpage'); } /** *      * * @param SocialUser $socialUser * @return mixed */ protected function registerNewUser($socialUser) { /** @var UserRepository $userRepository */ $userRepository = $this->components()->orm()->repository('user'); //       . //         , //      . $profileName = $this->getProfileName($socialUser); //        id $socialIdField = $userRepository->socialIdField($socialUser->providerName()); //    $user = $userRepository->create([ 'name' => $profileName, $socialIdField => $socialUser->id() ]); $user->save(); return $user; } /** *        * * @param SocialUser $socialUser * @return mixed */ protected function getProfileName($socialUser) { //    Twitter  Facebook   ,    . return $socialUser->loginData()->name; } /** *  URL  ,   *      . * * @param $provider * @return string */ protected function buildCallbackUrl($provider) { return $this->frameworkHttp()->generateUri('app.socialAuthCallback', [ 'provider' => $provider ])->__toString(); } /** *   OAuth  * * @return OAuthProvider */ protected function oauthProvider() { $domain = $this->components()->auth()->domain(); return $domain->provider('social'); } }
      
      





次に、ルートを登録し、認証フォームにログインリンクを追加します。







 // /bundles/app/assets/templates/login.php <?php $url = $this->httpPath('app.socialAuth', ['provider' => 'twitter']); ?> <a class="btn btn-lg btn-primary btn-block" href="<?=$url?>">Login with Twitter</a> <?php $url = $this->httpPath('app.socialAuth', ['provider' => 'facebook']); ?> <a class="btn btn-lg btn-primary btn-block" href="<?=$url?>">Login with Facebook</a>
      
      





この段階でのプロジェクトのステータス(コミット6)







7.メッセージの追加



実際にはここには興味深いものは何もありません。別の形式で、今回は変更のためにAJAXを介してのみです。 ここで注意すべき唯一のもの

そのため、テンプレートのブロックを使用してスクリプトを追加しています。 そして、 scripts



ブロックを親テンプレートに追加します。







 <!-- /bundles/app/assets/templates/layout.php --> <!--         --> <?=$this->block('scripts')?>
      
      





messages



テンプレート自体で、このブロックにスクリプトを追加できます。







 <!-- /bundles/app/assets/templates/messages.php --> <?php $this->startBlock('scripts'); ?> <script> $(function() { // Init the form handler <?php $url = $this->httpPath('app.action', ['processor' => 'messages', 'action' => 'post']);?> $('#messageForm').messageForm("<?=$_($url)?>"); }); </script> <?php $this->endBlock(); ?>
      
      





, . ,

, :







 <?php $this->startBlock('test'); ?> Hello <?php $this->endBlock(); ?> <?php $this->startBlock('test'); ?> World <?php $this->endBlock(); ?> <?=$this->block('test')?> <!--  --> Hello World
      
      





 <!--    true    ,   startBlock()   false      if  . --> <?php if($this->startBlock('test', true)): ?> Hello <?php $this->endBlock();endif; ?> <?php if($this->startBlock('test', true)): ?> World <?php $this->endBlock();endif; ?> <?=$this->block('test')?> <!--  --> Hello
      
      





Messages



:







  public function postAction($request) { // .... //  ORM    PHP . //  true          , //      . // //   PHPixie       JSON  . return $message->asObject(true); }
      
      





** ( 7)







8.



. :







 namespace Project\App\Console; use PHPixie\Console\Command\Config; use PHPixie\Slice\Data; /** *     */ class Messages extends Command { /** *   * @param Config $config */ protected function configure($config) { //  $config->description("Print latest messages"); //      id  $config->option('userId') ->description("Only print messages of this user"); //       $config->argument('limit') ->description("Maximum number of messages to display, default is 5"); } /** * @param Data $argumentData * @param Data $optionData */ public function run($argumentData, $optionData) { //    $limit = $argumentData->get('limit', 5); //   $query = $this->components()->orm()->query('message') ->orderDescendingBy('date') ->limit($limit); //   userId      $userId = $optionData->get('userId'); if($userId) { $query->relatedTo('user', $userId); } //    $messages = $query->find(['user'])->asArray(); //     if(empty($messages)) { $this->writeLine("No messages found"); } //   foreach($messages as $message) { $dateTime = new \DateTime($message->date); $this->writeLine($message->text); $this->writeLine(sprintf( "by %s on %s", $message->user()->name, $dateTime->format('j MY, H:i') )); $this->writeLine(); } } }
      
      





 namespace Project\App\Console; use PHPixie\Console\Command\Config; use PHPixie\Database\Driver\PDO\Connection; use PHPixie\Slice\Data; /** *     */ class Stats extends Command { /** *   * @param Config $config */ protected function configure($config) { $config->description("Display statistics"); } /** * @param Data $argumentData * @param Data $optionData */ public function run($argumentData, $optionData) { //   Database $database = $this->components()->database(); /** @var Connection $connection */ $connection = $database->get(); //    $total = $connection->countQuery() ->table('messages') ->execute(); $this->writeLine("Total messages: $total"); //      $stats = $connection->selectQuery() ->fields([ 'name' => 'u.name', // sqlExpression    SQL 'count' => $database->sqlExpression('COUNT(1)'), ]) ->table('messages', 'm') ->join('users', 'u') ->on('m.userId', 'u.id') ->groupBy('u.id') ->execute(); foreach($stats as $row) { $this->writeLine("{$row->name}: {$row->count}"); } } }
      
      





Project\App\Console



:







 namespace Project\App; class Console extends \PHPixie\DefaultBundle\Console { /** * Here we define console commands * @var array */ protected $classMap = array( 'messages' => 'Project\App\Console\Messages', 'stats' => 'Project\App\Console\Stats' ); }
      
      





, :







 # ./console Available commands: app:messages Print latest messages app:stats Display statistics # ....
      
      





 # ./console help app:messages app:messages [ --userId=VALUE ] [ LIMIT ] Print latest messages Options: userId Only print messages of this user Arguments: LIMIT Maximum number of messages to display, default is 5
      
      





 # ./console help app:stats app:stats Display statistics
      
      





:







 # ./console app:messages 2 Simplicity is the ultimate sophistication. -- Leonardo da Vinci by Trixie on 7 Dec 2016, 16:40 Simplicity is prerequisite for reliability. -- Edsger W. Dijkstra by Trixie on 7 Dec 2016, 15:05
      
      





 # ./console app:stats Total messages: 14 Pixie: 3 Trixie: 11
      
      





( 8)







9.



, .

, /assets/parameters.php



, .







 // /assets/parameters.php return [ 'database' => [ 'name' => 'phpixie', 'user' => 'phpixie', 'password' => 'phpixie' ], 'social' => [ 'facebookId' => 'YOUR APP ID', 'facebookSecret' => 'YOUR APP SECRET', 'twitterId' => 'YOUR APP ID', 'twitterSecret' => 'YOUR APP SECRET', ] ];
      
      





:







 // /assets/config/database.php return [ // Database configuration 'default' => [ //     /assets/parameters.php 'database' => '%database.name%', 'user' => '%database.user%', 'password' => '%database.password%', 'adapter' => 'mysql', 'driver' => 'pdo' ] ];
      
      





 // /assets/config/social.php return [ 'facebook' => [ 'type' => 'facebook', 'appId' => '%social.facebookId%', 'appSecret' => '%social.facebookSecret%' ], 'twitter' => [ 'type' => 'twitter', 'consumerKey' => '%social.twitterId%', 'consumerSecret' => '%social.twitterSecret%' ] ];
      
      





. PHP

if



switch



.















, , . , , .







:)








All Articles