рдореЗрдиреВ рдореЙрдбреНрдпреВрд▓ рдмрдирд╛рдиреЗ рдХреЗ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд░реВрдк рдореЗрдВ Yii2 рдореЗрдВ рдмрд╣реБрднрд╛рд╖реА рдкреЗрдбрд╝

рдкреНрд░рд╡рд┐рд╖реНрдЯрд┐


рдХрдИ рдиреМрд╕рд┐рдЦрд┐рдП рд╡реЗрдм рдбреЗрд╡рд▓рдкрд░реНрд╕ рдХреЛ рдЕрдкрдиреЗ Yii2 рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдХреЗ рд▓рд┐рдП рдореЗрдиреВ, рдирд┐рд░реНрджреЗрд╢рд┐рдХрд╛ рдпрд╛ рд╢реНрд░реЗрдгрд┐рдпрд╛рдВ рдмрдирд╛рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдХреЗ рд╕рд╛рде рд╕рд╛рдордирд╛ рдХрд░рдирд╛ рдкрдбрд╝рддрд╛ рд╣реИ, рдЬрд┐рд╕рдореЗрдВ рдПрдХ рдкрджрд╛рдиреБрдХреНрд░рдорд┐рдд рд╕рдВрд░рдЪрдирд╛ рд╣реЛрддреА рд╣реИ, рд▓реЗрдХрд┐рди рдПрдХ рд╣реА рд╕рдордп рдореЗрдВ рдмрд╣реБрднрд╛рд╖реАрд╡рд╛рдж рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рддрд╛ рд╣реИред рдХрд╛рд░реНрдп рдХрд╛рдлреА рд╕рд░рд▓ рд╣реИ, рд▓реЗрдХрд┐рди рдЗрд╕ рдврд╛рдВрдЪреЗ рдХреЗ рдврд╛рдВрдЪреЗ рдХреЗ рднреАрддрд░ рдмрд┐рд▓реНрдХреБрд▓ рд╕реНрдкрд╖реНрдЯ рдирд╣реАрдВ рд╣реИред рдкреЗрдбрд╝ рд╕рдВрд░рдЪрдирд╛рдУрдВ (рдореЗрдиреВ, рдирд┐рд░реНрджреЗрд╢рд┐рдХрд╛, рдЖрджрд┐) рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдмрдбрд╝реА рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рддреИрдпрд╛рд░ рдПрдХреНрд╕рдЯреЗрдВрд╢рди рд╣реИрдВ, рд▓реЗрдХрд┐рди рдРрд╕рд╛ рд╕рдорд╛рдзрд╛рди рдвреВрдВрдврдирд╛ рдореБрд╢реНрдХрд┐рд▓ рд╣реИ рдЬреЛ рдХрдИ рднрд╛рд╖рд╛рдУрдВ рдХреЗ рд╕рд╛рде рдкреВрд░реНрдг рдХрд╛рдо рдХрд╛ рд╕рдорд░реНрдерди рдХрд░реЗрдЧрд╛ред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рд╣рдо рдорд╛рдирдХ рдлреНрд░реЗрдорд╡рд░реНрдХ рдЯреВрд▓ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХрд╛ рдЕрдиреБрд╡рд╛рдж рдХрд░рдиреЗ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдмрд╛рдд рдирд╣реАрдВ рдХрд░ рд░рд╣реЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдХрдИ рднрд╛рд╖рд╛рдУрдВ рдореЗрдВ рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рдбреЗрдЯрд╛ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рдиреЗ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВред рдкреЗрдбрд╝ рдХреЗ рдкреНрд░рдмрдВрдзрди рдХреЗ рд▓рд┐рдП рдПрдХ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рдФрд░ рдкреВрд░реА рддрд░рд╣ рдХрд╛рд░реНрдпрд╛рддреНрдордХ рд╡рд┐рдЬреЗрдЯ рдвреВрдВрдврдирд╛ рднреА рдХрд╛рдлреА рдореБрд╢реНрдХрд┐рд▓ рд╣реИ, рдЬреЛ рдЬрдЯрд┐рд▓ рдХреЛрдб рдЬреЛрдбрд╝рддреЛрдбрд╝ рдХреЗ рдмрд┐рдирд╛ рдмрд╣реБрднрд╛рд╖реА рд╕рд╛рдордЧреНрд░реА рдХреЗ рд╕рд╛рде рднреА рдХрд╛рдо рдХрд░ рд╕рдХрддрд╛ рд╣реИред


рдореИрдВ рдореЗрдиреВ рдореЙрдбреНрдпреВрд▓ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЗ рдЙрджрд╛рд╣рд░рдг рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╕рдорд╛рди рдореЙрдбреНрдпреВрд▓ рдмрдирд╛рдиреЗ рдХреЗ рддрд░реАрдХреЗ рдкрд░ рдПрдХ рдиреБрд╕реНрдЦрд╛ рд╕рд╛рдЭрд╛ рдХрд░рдирд╛ рдЪрд╛рд╣реВрдВрдЧрд╛ред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдореИрдВ Yii2 рдРрдк рдмреЗрд╕рд┐рдХ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдЯреЗрдореНрдкреНрд▓реЗрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реВрдВрдЧрд╛, рд▓реЗрдХрд┐рди рдЕрдЧрд░ рдпрд╣ рдЖрдзрд╛рд░ рд╕реЗ рдЕрд▓рдЧ рд╣реИ рддреЛ рдЖрдк рдЕрдкрдиреЗ рдЯреЗрдореНрдкрд▓реЗрдЯ рдХреЗ рд▓рд┐рдП рд╕рдм рдХреБрдЫ рдЕрдиреБрдХреВрд▓рд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред


рдЯреНрд░реЗрдирд┐рдВрдЧ


рдХрд╛рд░реНрдп рдХреЛ рдкреВрд░рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ рдХреБрдЫ рдЕрджреНрднреБрдд рдПрдХреНрд╕рдЯреЗрдВрд╢рдиреЛрдВ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреА, рдЕрд░реНрдерд╛рддреН:



рд╕рдВрдЧреАрддрдХрд╛рд░ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдПрдХреНрд╕рдЯреЗрдВрд╢рди рдбреЗрдЯрд╛ рд╕реНрдерд╛рдкрд┐рдд рдХрд░реЗрдВ:


composer require paulzi/yii2-adjacency-list composer require execut/yii2-widget-bootstraptreeview composer require creocoder/yii2-translateable 

рдореЗрдиреВ рдХреЛ рдореЙрдбреНрдпреВрд▓ рдХреЗ рд░реВрдк рдореЗрдВ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, Gii рдЬрдирд░реЗрдЯрд░ (рдпрд╛ рдореИрдиреНрдпреБрдЕрд▓ рд░реВрдк рд╕реЗ) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдПрдХ рдирдпрд╛ рдореЗрдиреВ рдореЙрдбреНрдпреВрд▓ рдмрдирд╛рдПрдВ рдФрд░ рдЗрд╕реЗ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рд╕реЗрдЯрд┐рдВрдЧреНрд╕ рдореЗрдВ рдХрдиреЗрдХреНрдЯ рдХрд░реЗрдВред


рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдореЗрдВ рдПрдХ рднрд╛рд╖рд╛ рд╕реНрд╡рд┐рдЪрд┐рдВрдЧ рдореИрдХреЗрдирд┐рдЬреНрдо рднреА рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред рдореИрдВ Yii2 рдХреЗ рд▓рд┐рдП рдЗрд╕ рдПрдХреНрд╕рдЯреЗрдВрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдкрд╕рдВрдж рдХрд░рддрд╛ рд╣реВрдВ ред


рдореЙрдбрд▓ рдирд┐рд░реНрдорд╛рдг


рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рдореЗрдиреВ (рдпрд╛ рдПрдХ рдЕрдиреНрдп рдЗрдХрд╛рдИ рдЬрд┐рд╕рдореЗрдВ рдмрд╣реБрднрд╛рд╖реАрд╡рд╛рдж рд╣реИ) рдХреЛ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ рджреЛ рдЯреЗрдмрд▓ рдмрдирд╛рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рдмрд╣реБрднрд╛рд╖реА рдбреЗрдЯрд╛ рдХреЛ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╡рд┐рднрд┐рдиреНрди рддрд░реАрдХреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдореБрдЭреЗ рджреЛ рддрд╛рд▓рд┐рдХрд╛рдУрдВ рдХреЗ рд╕рд╛рде рд╡рд┐рдХрд▓реНрдк рдкрд╕рдВрдж рд╣реИ, рдЬрд┐рдирдореЗрдВ рд╕реЗ рдПрдХ рд╕рд╛рд░ рдЦреБрдж рдХреЛ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рддрд╛ рд╣реИ, рдФрд░ рджреВрд╕рд░рд╛ - рдЗрд╕рдХреА рднрд╛рд╖рд╛ рд╡рд┐рд╡рд┐рдзрддрд╛рдПрдВ, рджреВрд╕рд░реЛрдВ рдХреА рддреБрд▓рдирд╛ рдореЗрдВ рдЕрдзрд┐рдХред рдЯреЗрдмрд▓ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдорд╛рдЗрдЧреНрд░реЗрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд╣реИред рдпрд╣рд╛рдБ рдЗрд╕ рддрд░рд╣ рдХреЗ рдкреНрд░рд╡рд╛рд╕ рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг рджрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ:


m180819_083502_menu_init.php
 <?php use yii\db\Schema; use yii\db\Migration; class m180819_083502_menu_init extends Migration { public function init() { $this->db = 'db'; parent::init(); } public function safeUp() { $tableOptions = 'ENGINE=InnoDB'; $this->createTable('{{%menu}}', [ 'id'=> $this->primaryKey(11), 'parent_id'=> $this->integer(11)->null()->defaultValue(null), 'link'=> $this->string(255)->notNull()->defaultValue('#'), 'link_attributes'=> $this->text()->notNull(), 'icon_class'=> $this->string(255)->notNull(), 'sort'=> $this->integer(11)->notNull()->defaultValue(0), 'status'=> $this->tinyInteger(1)->notNull()->defaultValue(1), ], $tableOptions); $this->createIndex('parent_sort', '{{%menu}}', ['parent_id','sort'], false); $this->createTable('{{%menu_lang}}', [ 'owner_id'=> $this->integer(11)->notNull(), 'language'=> $this->string(2)->notNull(), 'name'=> $this->string(255)->notNull(), 'title'=> $this->text()->notNull(), ], $tableOptions); $this->addPrimaryKey('pk_on_menu_lang', '{{%menu_lang}}', ['owner_id','language']); $this->addForeignKey( 'fk_menu_lang_owner_id', '{{%menu_lang}}', 'owner_id', '{{%menu}}', 'id', 'CASCADE', 'CASCADE' ); // Insert sample data $this->batchInsert( '{{%menu}}', ['id', 'parent_id', 'link', 'link_attributes', 'icon_class', 'sort', 'status'], [ [ 'id' => '1', 'parent_id' => null, 'link' => '#', 'link_attributes' => '', 'icon_class' => '', 'sort' => '0', 'status' => '0', ], [ 'id' => '2', 'parent_id' => '1', 'link' => '/', 'link_attributes' => '', 'icon_class' => 'fa fa-home', 'sort' => '0', 'status' => '1', ], ] ); $this->batchInsert( '{{%menu_lang}}', ['owner_id', 'language', 'name', 'title'], [ [ 'owner_id' => '1', 'language' => 'ru', 'name' => ' ', 'title' => '', ], [ 'owner_id' => '1', 'language' => 'en', 'name' => 'Main menu', 'title' => '', ], [ 'owner_id' => '2', 'language' => 'ru', 'name' => '', 'title' => '  ', ], [ 'owner_id' => '2', 'language' => 'en', 'name' => 'Home', 'title' => 'Site homepage', ], ] ); } public function safeDown() { $this->truncateTable('{{%menu}} CASCADE'); $this->dropForeignKey('fk_menu_lang_owner_id', '{{%menu_lang}}'); $this->dropTable('{{%menu}}'); $this->dropPrimaryKey('pk_on_menu_lang', '{{%menu_lang}}'); $this->dropTable('{{%menu_lang}}'); } } 

рдЗрд╕ рдорд╛рдЗрдЧреНрд░реЗрд╢рди рдлрд╝рд╛рдЗрд▓ рдХреЛ рд╣рдорд╛рд░реЗ рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдХреЗ / рдорд╛рдЗрдЧреНрд░реЗрд╢рди рдлрд╝реЛрд▓реНрдбрд░ рдореЗрдВ рд░рдЦреЗрдВ, рдФрд░
рдХрдВрд╕реЛрд▓ рдореЗрдВ рдХрдорд╛рдВрдб рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░реЗрдВ:


 php yii migrate 

рдЬрдм рд╣рдордиреЗ рдЖрд╡рд╢реНрдпрдХ рддрд╛рд▓рд┐рдХрд╛рдУрдВ рдХрд╛ рдирд┐рд░реНрдорд╛рдг рдХрд┐рдпрд╛ рдФрд░ рдкреНрд░рд╡рд╛рд╕рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЙрдирдХреЗ рд▓рд┐рдП рдПрдХ рдирдпрд╛ рдореЗрдиреВ рдЬреЛрдбрд╝рд╛, рддреЛ рд╣рдореЗрдВ рдореЙрдбрд▓ рдмрдирд╛рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдЪреВрдВрдХрд┐ рдмрд╣реБрднрд╛рд╖реАрд╡рд╛рдж рдФрд░ рдкреЗрдбрд╝ рди рдХреЗрд╡рд▓ рдореЗрдиреВ рдореЗрдВ рдкрд╛рдП рдЬрд╛ рд╕рдХрддреЗ рд╣реИрдВ, рдмрд▓реНрдХрд┐ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдореЗрдВ рдЕрдиреНрдп рд╕рдВрд╕реНрдерд╛рдУрдВ (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рд╕рд╛рдЗрдЯ рдкреГрд╖реНрда) рдореЗрдВ рднреА, рдореЗрд░рд╛ рд╕реБрдЭрд╛рд╡ рд╣реИ рдХрд┐ рдмрд╣реБрднрд╛рд╖рд╛рд╡рд╛рдж рддрдВрддреНрд░ рдФрд░ рд╡реГрдХреНрд╖ рд╕рдВрдЧрдарди рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рддрд░реАрдХреЛрдВ рдХреЛ рдЕрд▓рдЧ-рдЕрд▓рдЧ рд▓рдХреНрд╖рдгреЛрдВ рдореЗрдВ рд░рдЦрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП рддрд╛рдХрд┐ рд╣рдо рдЖрд╕рд╛рдиреА рд╕реЗ рдмрд╛рдж рдореЗрдВ рдЙрдирдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХреЗрдВред рдХреЛрдб рдХреЗ рджреЛрд╣рд░рд╛рд╡ рдХреЗ рдмрд┐рдирд╛ рдЙрдиреНрд╣реЗрдВ рдЕрдиреНрдп рдореЙрдбрд▓реЛрдВ рдореЗрдВред рдПрдкреНрд▓рд┐рдХреЗрд╢рди рд░реВрдЯ рдореЗрдВ рдПрдХ рд╡рд┐рд╢реЗрд╖рддрд╛ рдлрд╝реЛрд▓реНрдбрд░ рдмрдирд╛рдПрдВ (рдпрджрд┐ рдпрд╣ рдкрд╣рд▓реЗ рд╕реЗ рдореМрдЬреВрдж рдирд╣реАрдВ рд╣реИ) рдФрд░ рд╡рд╣рд╛рдВ рджреЛ рдлрд╛рдЗрд▓реЗрдВ рдбрд╛рд▓реЗрдВ:


LangTrait.php
 <?php namespace app\traits; use Yii; use yii\behaviors\SluggableBehavior; use creocoder\translateable\TranslateableBehavior; trait LangTrait { public static function langClass() { return self::class . 'Lang'; } public static function langTableName() { return self::tableName() . '_lang'; } public function langBehaviors($translationAttributes) { return [ 'translateable' => [ 'class' => TranslateableBehavior::class, 'translationAttributes' => $translationAttributes, 'translationRelation' => 'translations', 'translationLanguageAttribute' => 'language', ], ]; } public function transactions() { return [ self::SCENARIO_DEFAULT => self::OP_INSERT | self::OP_UPDATE, ]; } public function getLang() { return $this->hasOne(self::langClass(), ['owner_id' => 'id'])->where([self::langTableName() . '.language' => Yii::$app->language]); } public function getTranslations() { return $this->hasMany(self::langClass(), ['owner_id' => 'id']); } } 

TreeTrait.php
 <?php namespace app\traits; use Yii; use yii\helpers\Html; use paulzi\adjacencyList\AdjacencyListBehavior; trait TreeTrait { private static function getQueryClass() { return self::class . 'Query'; } public function treeBehaviors() { return [ 'tree' => [ 'class' => AdjacencyListBehavior::class, 'parentAttribute' => 'parent_id', 'sortable' => [ 'step' => 10, ], 'checkLoop' => false, 'parentsJoinLevels' => 5, 'childrenJoinLevels' => 5, ], ]; } public static function find() { $queryClass = self::getQueryClass(); return new $queryClass(get_called_class()); } public static function listTree($node = null, $level = 1, $nameAttribute = 'name', $prefix = '-->') { $result = []; if (!$node) { $node = self::find()->roots()->one()->populateTree(); } if ($node->isRoot()) { $result[$node['id']] = mb_strtoupper($node[$nameAttribute ?: 'slug']); } if ($node['children']) { foreach ($node['children'] as $child) { $result[$child['id']] = str_repeat($prefix, $level) . $child[$nameAttribute]; $result = $result + self::listTree($child, $level + 1, $nameAttribute); } } return $result; } public static function treeViewData($node = null) { if ($node === null) { $node = self::find()->roots()->one()->populateTree(); } $result = null; $items = null; $children = null; if ($node['children']) { foreach ($node['children'] as $child) { $items[] = self::treeViewData($child); } $children = call_user_func_array('array_merge', $items); } $result[] = [ 'text' => Html::a($node['lang']['name'] ?: $node['id'], ['update', 'id' => $node['id']], ['title' => Yii::t('app', ' ')]), 'tags' => [ Html::a( '<i class="glyphicon glyphicon-arrow-down"></i>', ['move-down', 'id' => $node['id']], ['title' => Yii::t('app', ' ')] ), Html::a( '<i class="glyphicon glyphicon-arrow-up"></i>', ['move-up', 'id' => $node['id']], ['title' => Yii::t('app', ' ')] ) ], 'backColor' => $node['status'] == 0 ? '#ccc' : '#fff', 'selectable' => false, 'nodes' => $children, ]; return $result; } } 

рдЕрдм рд╣рдо рд╕реАрдзреЗ рдореЗрдиреВ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдореЙрдбрд▓ рдЦреБрдж рдмрдирд╛рдПрдВрдЧреЗ, рдЬрд┐рд╕рдореЗрдВ рд╣рдо рдкреЗрдбрд╝ рдФрд░ рдмрд╣реБрднрд╛рд╖рд╛рд╡рд╛рдж рдХреЗ рд▓рд┐рдП рд▓рдХреНрд╖рдгреЛрдВ рдХреЛ рдЬреЛрдбрд╝рддреЗ рд╣реИрдВред рд╣рдо рдореЙрдбрд▓ / рдореЙрдбреНрдпреВрд▓ / рдореЗрдиреВ / рдореЙрдбрд▓ рдореЗрдВ рд░рдЦрддреЗ рд╣реИрдВ:


Menu.php
 <?php namespace app\modules\menu\models; use Yii; class Menu extends \yii\db\ActiveRecord { use \app\traits\TreeTrait; use \app\traits\LangTrait; const STATUS_ACTIVE = 1; const STATUS_INACTIVE = 0; public function behaviors() { $behaviors = []; return array_merge( $behaviors, $this->treeBehaviors(), $this->langBehaviors(['name', 'title']) ); } public static function tableName() { return 'menu'; } public function rules() { return [ [['parent_id', 'sort', 'status'], 'integer'], [['link', 'icon_class'], 'string', 'max' => 255], [['link_attributes'], 'string'], [['link'], 'default', 'value' => '#'], [['link_attributes', 'icon_class'], 'default', 'value' => ''], [['parent_id'], 'exist', 'skipOnError' => true, 'targetClass' => self::class, 'targetAttribute' => ['parent_id' => 'id']], ]; } public function attributeLabels() { return [ 'id' => Yii::t('app', 'ID'), 'parent_id' => Yii::t('app', ''), 'link' => Yii::t('app', ''), 'link_attributes' => Yii::t('app', '  (JSON )'), 'icon_class' => Yii::t('app', ' '), 'sort' => Yii::t('app', ''), 'status' => Yii::t('app', ''), ]; } public static function menuItems($node = null) { if ($node === null) { $node = self::find()->roots()->one()->populateTree(); } $result = null; $items = null; $children = null; if ($node['children']) { foreach ($node['children'] as $child) { $items[] = self::menuItems($child); } $children = call_user_func_array('array_merge', $items); } $result[] = [ 'label' => ($node['icon_class'] ? '<i class="' . $node['icon_class'] . '"></i> ' . ($node['lang']['name'] ?: $node['id']) : ($node['lang']['name'] ?: $node['id'] )), 'encode' => ($node['icon_class'] ? false : true), 'url' => [$node['link'], 'language' => Yii::$app->language], 'active' => $node['link'] == Yii::$app->request->url ? true : false, 'linkOptions' => ($node['link_attributes'] ? array_merge(json_decode($node['link_attributes'], true), ['title' => ($node['lang']['title'] ?: $node['lang']['name'])]) : ['title' => ($node['lang']['title'] ?: $node['lang']['name'])]), 'items' => $children, ]; return $result; } } 

MenuLang.php
 <?php namespace app\modules\menu\models; use Yii; class MenuLang extends \yii\db\ActiveRecord { public static function tableName() { return 'menu_lang'; } public function rules() { return [ [['name'], 'required'], [['name', 'title'], 'string', 'max' => 255], ]; } public function attributeLabels() { return [ 'owner_id' => Yii::t('app', ''), 'language' => Yii::t('app', ''), 'name' => Yii::t('app', ''), 'title' => Yii::t('app', ' '), ]; } public function getOwner() { return $this->hasOne(Menu::class, ['id' => 'owner_id']); } } 

MenuQuery.php
 <?php namespace app\modules\menu\models; use paulzi\adjacencyList\AdjacencyListQueryTrait; class MenuQuery extends \yii\db\ActiveQuery { use AdjacencyListQueryTrait; } 

MenuSearch.php
 <?php namespace app\modules\menu\models; use Yii; use yii\base\Model; use yii\data\ActiveDataProvider; use app\modules\menu\models\Menu; class MenuSearch extends Menu { public $name; public function rules() { return [ [['id', 'parent_id', 'sort', 'status'], 'integer'], [['link', 'link_attributes', 'icon_class'], 'safe'], [['name'], 'safe'], ]; } public function scenarios() { return Model::scenarios(); } public function search($params) { $query = parent::find()->joinWith(['lang']); $dataProvider = new ActiveDataProvider([ 'query' => $query, 'sort' => ['defaultOrder' => ['sort' => SORT_ASC]] ]); $dataProvider->sort->attributes['name'] = [ 'asc' => [ 'menu_lang.name' => SORT_ASC, ], 'desc' => [ 'menu_lang.name' => SORT_DESC, ], ]; $this->load($params); if (!$this->validate()) { return $dataProvider; } $query->andFilterWhere([ 'id' => $this->id, 'parent_id' => $this->parent_id, 'sort' => $this->sort, 'status' => $this->status, ]); $query->andFilterWhere(['like', 'link', $this->link]); $query->andFilterWhere(['like', 'link_attributes', $this->link_attributes]); $query->andFilterWhere(['like', 'icon_class', $this->icon_class]); $query->andFilterWhere(['like', 'name', $this->name]); return $dataProvider; } } 

рдирд┐рдпрдВрддреНрд░рдХ рдмрдирд╛рдирд╛


рдмрд╣реБрднрд╛рд╖реА рдкреЗрдбрд╝реЛрдВ рдкрд░ CRUD рд╕рдВрдЪрд╛рд▓рди рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ рдПрдХ рдирд┐рдпрдВрддреНрд░рдХ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рднрд╡рд┐рд╖реНрдп рдореЗрдВ рд╣рдорд╛рд░реЗ рдЬреАрд╡рди рдХреЛ рд╕рд░рд▓ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рдПрдХ рдмреБрдирд┐рдпрд╛рджреА рдирд┐рдпрдВрддреНрд░рдХ рдмрдирд╛рдПрдВрдЧреЗ рдЬрд┐рд╕рдореЗрдВ рд╕рднреА рдЖрд╡рд╢реНрдпрдХ рдХрд╛рд░реНрдп рд╣реЛрдВрдЧреЗ, рдФрд░ рд╡рд┐рднрд┐рдиреНрди рд╕рдВрд╕реНрдерд╛рдУрдВ рдХреЗ рд▓рд┐рдП, рдЪрд╛рд╣реЗ рд╡рд╣ рдПрдХ рдореЗрдиреВ рд╣реЛ, рдпрд╛ рдПрдХ рдирд┐рд░реНрджреЗрд╢рд┐рдХрд╛, рдпрд╛ рдкреГрд╖реНрда рд╣реЛрдВ, рд╣рдо рдЗрд╕реЗ рд╡рд┐рд░рд╛рд╕рдд рдореЗрдВ рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВрдЧреЗред


рд╣рдорд╛рд░реА рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХреА рдХрдХреНрд╖рд╛рдПрдВ рдЬрд┐рдиреНрд╣реЗрдВ рд╣рдо рдЖрдзрд╛рд░ рдХрдХреНрд╖рд╛рдУрдВ рдХреЗ рд░реВрдк рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗ, рдЙрдиреНрд╣реЗрдВ / рдЖрдзрд╛рд░ рдлрд╝реЛрд▓реНрдбрд░ рдореЗрдВ рд░рдЦрд╛ рдЬрд╛рдПрдЧрд╛ред рдлрд╝рд╛рдЗрд▓ рдмрдирд╛рдПрдБ /base/controllers/AdminLangTreeController.phpред рдпрд╣ рдирд┐рдпрдВрддреНрд░рдХ рдЙрди рд╕рднреА рд╕рдВрд╕реНрдерд╛рдУрдВ рдХреЗ CRUD рдХрд╛ рдЖрдзрд╛рд░ рд╣реЛрдЧрд╛ рдЬрд┐рд╕рдореЗрдВ рд╡реГрдХреНрд╖ рдФрд░ рдмрд╣реБрднрд╛рд╖рд╛рд╡рд╛рдж рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ:


AdminLangTreeController.php
 <?php namespace app\base\controllers; use Yii; use yii\web\Controller; use yii\web\NotFoundHttpException; use yii\filters\VerbFilter; use yii\helpers\Url; class AdminLangTreeController extends Controller { public $modelClass; public $modelClassSearch; public $modelName; public $modelNameLang; public function behaviors() { return [ 'verbs' => [ 'class' => VerbFilter::class, 'actions' => [ 'delete' => ['POST'], ], ], ]; } public function actionIndex() { //     ,     if (count($this->modelClass::find()->roots()->all()) == 0) { $model = new $this->modelClass; $model->makeRoot()->save(); Yii::$app->session->setFlash('info', Yii::t('app', '   ')); return $this->redirect(['index']); } $searchModel = new $this->modelClassSearch; $dataProvider = $searchModel->search(Yii::$app->request->queryParams); $dataProvider->pagination = false; return $this->render('index', [ 'searchModel' => $searchModel, 'dataProvider' => $dataProvider, ]); } public function actionCreate() { //     if (count($this->modelClass::find()->roots()->all()) == 0) { return $this->redirect(['index']); } //         $model = new $this->modelClass; $root = $model::find()->roots()->one(); $model->parent_id = $root->id; //     if ($model->load(Yii::$app->request->post()) && $model->validate()) { $parent = $model::findOne($model->parent_id); $model->appendTo($parent)->save(); //    foreach (Yii::$app->request->post($this->modelNameLang, []) as $language => $data) { foreach ($data as $attribute => $translation) { $model->translate($language)->$attribute = $translation; } } $model->save(); Yii::$app->session->setFlash('success', Yii::t('app', '  ')); return $this->redirect(['update', 'id' => $model->id]); } else { return $this->render('create', [ 'model' => $model, ]); } } public function actionUpdate($id) { //    $model = $this->modelClass::find()->with('translations')->where(['id' => $id])->one(); if ($model === null) { throw new NotFoundHttpException(Yii::t('app', '  ')); } //     if ($model->load(Yii::$app->request->post()) && $model->save()) { foreach (Yii::$app->request->post($this->modelNameLang, []) as $language => $data) { foreach ($data as $attribute => $translation) { $model->translate($language)->$attribute = $translation; } } $model->save(); Yii::$app->session->setFlash('success', Yii::t('app', '  ')); if (Yii::$app->request->post('save') !== null) { return $this->redirect(['index']); } return $this->redirect(['update', 'id' => $model->id]); } else { return $this->render('update', [ 'model' => $model, ]); } } public function actionDelete($id) { $model = $this->findModel($id); //   ,      if (count($model->children) > 0) { Yii::$app->session->setFlash('error', Yii::t('app', '    ,     .      ')); return $this->redirect(['index']); } //     if ($model->isRoot()) { Yii::$app->session->setFlash('error', Yii::t('app', '   ')); return $this->redirect(['index']); } //   if ($model->delete()) { Yii::$app->session->setFlash('success', Yii::t('app', '  ')); } return $this->redirect(['index']); } public function actionMoveUp($id) { $model = $this->findModel($id); if ($prev = $model->getPrev()->one()) { $model->moveBefore($prev)->save(); $model->reorder(false); } else { Yii::$app->session->setFlash('error', Yii::t('app', '   ')); } return $this->redirect(Yii::$app->request->referrer); } public function actionMoveDown($id) { $model = $this->findModel($id); if ($next = $model->getNext()->one()) { $model->moveAfter($next)->save(); $model->reorder(false); } else { Yii::$app->session->setFlash('error', Yii::t('app', '   ')); } return $this->redirect(Yii::$app->request->referrer); } protected function findModel($id) { if (($model = $this->modelClass::findOne($id)) !== null) { return $model; } else { throw new NotFoundHttpException(Yii::t('app', '  ')); } } } 

рдЕрдм рдореЙрдбреНрдпреВрд▓ рдореЗрдВ, рдлрд╝рд╛рдЗрд▓ /modules/menu/controllers/AdminController.php рдмрдирд╛рдПрдВред рдпрд╣ рдореЗрдиреВ рдХреЗ рдкреНрд░рдмрдВрдзрди рдХреЗ рд▓рд┐рдП рдореБрдЦреНрдп рдирд┐рдпрдВрддреНрд░рдХ рд╣реЛрдЧрд╛, рдФрд░ рдЪреВрдВрдХрд┐ рдпрд╣ рдкреЗрдбрд╝ рдФрд░ рдмрд╣реБрднрд╛рд╖рд╛рд╡рд╛рдж рдХреЛ рд▓рд╛рдЧреВ рдХрд░рддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдпрд╣ рдЖрдзрд╛рд░ рд╕реЗ рд╡рд┐рд░рд╛рд╕рдд рдореЗрдВ рд╣реЛрдЧрд╛ рдЬрд┐рд╕реЗ рд╣рдордиреЗ рдкрд╣рд▓реЗ рд╣реА рдкрд┐рдЫрд▓реЗ рдЪрд░рдг рдореЗрдВ рдмрдирд╛рдпрд╛ рдерд╛:


AdminController.php
 <?php namespace app\modules\menu\controllers; use app\base\controllers\AdminLangTreeController as BaseController; class AdminController extends BaseController { public $modelClass = \app\modules\menu\models\Menu::class; public $modelClassSearch = \app\modules\menu\models\MenuSearch::class; public $modelName = 'Menu'; public $modelNameLang = 'MenuLang'; } 

рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ, рдЗрд╕ рдирд┐рдпрдВрддреНрд░рдХ рдХреЗ рдХреЛрдб рдореЗрдВ рдХреЗрд╡рд▓ рдореЙрдбрд▓ рдФрд░ рдЙрдирдХреА рдХрдХреНрд╖рд╛рдУрдВ рдХреЗ рдирд╛рдо рд╢рд╛рдорд┐рд▓ рд╣реИрдВред рдпрд╣реА рд╣реИ, рдЕрдиреНрдп рдореЙрдбреНрдпреВрд▓ (рдХреИрдЯрд▓реЙрдЧ, рд╢реНрд░реЗрдгрд┐рдпрд╛рдВ, рдЖрджрд┐) рдХреЗ рд▓рд┐рдП рд╕реАрдЖрд░рдпреВрдбреА рдирд┐рдпрдВрддреНрд░рдХ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП, рдЬреЛ рдкреЗрдбрд╝ рдФрд░ рдмрд╣реБрднрд╛рд╖рд╛рд╡рд╛рдж рдХрд╛ рднреА рдЙрдкрдпреЛрдЧ рдХрд░реЗрдЧрд╛, рдЖрдк рдЙрд╕реА рддрд░рд╣ рд╕реЗ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ - рдЖрдзрд╛рд░ рдирд┐рдпрдВрддреНрд░рдХ рдХрд╛ рд╡рд┐рд╕реНрддрд╛рд░ рдХрд░реЗрдВред


рдореЗрдиреВ рдХреЗ рдкреНрд░рдмрдВрдзрди рдХреЗ рд▓рд┐рдП рдПрдХ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдмрдирд╛рдирд╛


рдЕрдВрддрд┐рдо рдЪрд░рдг рдПрдХ рдмрд╣реБрднрд╛рд╖реА рдкреЗрдбрд╝ рдХреЗ рдкреНрд░рдмрдВрдзрди рдХреЗ рд▓рд┐рдП рдПрдХ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХрд╛ рдирд┐рд░реНрдорд╛рдг рд╣реИред рдмреВрдЯрд╕реНрдЯреНрд░реИрдк рдЯреНрд░реАрд╡реНрдпреВ рдПрдХреНрд╕рдЯреЗрдВрд╢рди рдПрдХ рдкреЗрдбрд╝ рдХреЛ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХреЗ рдХрд╛рд░реНрдп рдХреЛ рд╕рдВрднрд╛рд▓рддрд╛ рд╣реИ, рдЬрд┐рд╕реЗ рдХрд╛рдлреА рд▓рдЪреАрд▓реЗ рдврдВрдЧ рд╕реЗ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ рдФрд░ рдпрд╣ рдХрдИ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рдХрд╛рд░реНрдпреЛрдВ рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рддрд╛ рд╣реИ (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдПрдХ рдкреЗрдбрд╝ рдореЗрдВ рдЦреЛрдЬ)ред рдкреЗрдбрд╝ рдХреЛ рд╕реНрд╡рдпрдВ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдЗрдВрдбреЗрдХреНрд╕ рд╡реНрдпреВ рдмрдирд╛рдПрдВ рдФрд░ рдЙрд╕реЗ /modules/menu/views/admin/index.php/ рдореЗрдВ рдбрд╛рд▓реЗрдВ:


index.php
 <?php use yii\helpers\Html; use yii\grid\GridView; use yii\widgets\ActiveForm; use execut\widget\TreeView; $this->title = Yii::t('app', ' '); $this->params['breadcrumbs'][] = $this->title; ?> <div class="row"> <div class="col-md-6"> <div class="panel panel-primary"> <div class="panel-heading"> <?= Html::a(Yii::t('app', ''), ['create'], ['class' => 'btn btn-success btn-flat']) ?> </div> <div class="panel-body"> <?= TreeView::widget([ 'id' => 'tree', 'data' => $searchModel::treeViewData($searchModel::find()->roots()->one()), 'header' => Yii::t('app', ' '), 'searchOptions' => [ 'inputOptions' => [ 'placeholder' => Yii::t('app', '  ') . '...' ], ], 'clientOptions' => [ 'selectedBackColor' => 'rgb(40, 153, 57)', 'borderColor' => '#fff', 'levels' => 10, 'showTags' => true, 'tagsClass' => 'badge', 'enableLinks' => true, ], ]) ?> </div> </div> </div> </div> 

рддреЛ рд╣рдо рдЗрд╕ рдорд╛рдорд▓реЗ рдХреЗ рд╕рдмрд╕реЗ рджрд┐рд▓рдЪрд╕реНрдк рдЪрд░рдг рдореЗрдВ рдЖрдП: рдмрд╣реБрднрд╛рд╖реА рдбреЗрдЯрд╛ рдмрдирд╛рдиреЗ / рд╕рдВрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдлреЙрд░реНрдо рдХреИрд╕реЗ рдмрдирд╛рдПрдВред / рдореЙрдбреНрдпреВрд▓ / рдореЗрдиреВ / рд╡рд┐рдЪрд╛рд░ / рд╡реНрдпрд╡рд╕реНрдерд╛рдкрдХ рдлрд╝реЛрд▓реНрдбрд░ рдореЗрдВ рддреАрди рдлрд╛рдЗрд▓реЗрдВ рдмрдирд╛рдПрдБ:


create.php
 <?php use yii\helpers\Html; $this->title = Yii::t('app', ''); $this->params['breadcrumbs'][] = ['label' => Yii::t('app', ' '), 'url' => ['index']]; $this->params['breadcrumbs'][] = $this->title; echo $this->render('_form', [ 'model' => $model, ]); 

update.php
 <?php use yii\helpers\Html; $this->title = Yii::t('app', '') . ': ' . $model->name; $this->params['breadcrumbs'][] = ['label' => Yii::t('app', ' '), 'url' => ['index']]; $this->params['breadcrumbs'][] = ['label' => $model->name, 'url' => ['update', 'id' => $model->id]]; $this->params['breadcrumbs'][] = Yii::t('app', ''); echo $this->render('_form', [ 'model' => $model, ]); 

_form.php
 <?php use yii\helpers\Html; use yii\widgets\ActiveForm; if ($model->isNewRecord) { $model->status = true; } ?> <div class="panel panel-primary"> <?php $form = ActiveForm::begin(); ?> <div class="panel-body"> <fieldset> <legend><?= Yii::t('app', ' ') ?></legend> <div class="row"> <div class="col-md-4"> <?php if (!$model->isRoot()) { ?> <?= $form->field($model, 'parent_id')->dropDownList($model::listTree()) ?> <?php } ?> <?= $form->field($model, 'link')->textInput(['maxlength' => true]) ?> <?= $form->field($model, 'link_attributes')->textInput(['maxlength' => true]) ?> <?= $form->field($model, 'icon_class')->textInput(['maxlength' => true]) ?> <?= $form->field($model, 'status')->checkbox() ?> </div> </div> </fieldset> <fieldset> <legend><?= Yii::t('app', '') ?></legend> <!-- Nav tabs --> <ul class="nav nav-tabs" role="tablist"> <?php foreach (Yii::$app->urlManager->languages as $key => $language) { ?> <li role="presentation" <?= $key == 0 ? 'class="active"' : '' ?>> <a href="#tab-content-<?= $language ?>" aria-controls="tab-content-<?= $language ?>" role="tab" data-toggle="tab"><?= $language ?></a> </li> <?php } ?> </ul> <!-- Tab panes --> <div class="tab-content"> <?php foreach (Yii::$app->urlManager->languages as $key => $language) { ?> <div role="tabpanel" class="tab-pane <?= $key == 0 ? 'active' : '' ?>" id="tab-content-<?= $language ?>"> <?= $form->field($model->translate($language), "[$language]name")->textInput() ?> <?= $form->field($model->translate($language), "[$language]title")->textInput() ?> </div> <?php } ?> </div> </fieldset> </div> <div class="box-footer"> <?= Html::submitButton($model->isNewRecord ? '<i class="fa fa-plus"></i> ' . Yii::t('app', '') : '<i class="fa fa-refresh"></i> ' . Yii::t('app', ''), ['class' => $model->isNewRecord ? 'btn btn-primary' : 'btn btn-success']) ?> <?= !$model->isNewRecord ? Html::submitButton('<i class="fa fa-save"></i> ' . Yii::t('app', ''), ['class' => 'btn btn-warning', 'name' => 'save']) : ''; ?> <?= !$model->isNewRecord ? Html::a('<i class="fa fa-trash"></i> ' . Yii::t('app', ''), ['delete', 'id' => $model->id], ['class' => 'btn btn-danger', 'data' => ['confirm' => Yii::t('app', ' ,     ?'), 'method' => 'post']]) : ''; ?> </div> <?php ActiveForm::end(); ?> </div> 

рдпрд╣ рдордд рднреВрд▓реЛ рдХрд┐ рдПрдкреНрд▓рд┐рдХреЗрд╢рди (рднрд╛рд╖рд╛ рдкреИрд░рд╛рдореАрдЯрд░) рдореЗрдВ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рднрд╛рд╖рд╛ рдХреЛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП, рдФрд░ рдЙрд░рд▓рдордирдЧрд░ рдорд╛рдкрджрдВрдбреЛрдВ рдореЗрдВ - рднрд╛рд╖рд╛рдУрдВ рдХреА рдПрдХ рд╕реВрдЪреА (рднрд╛рд╖рд╛рдУрдВ) рдХреЗ рд╕рд╛рде рдПрдХ рд╕рд░рдгреА рдЬреЛ рд╣рдо рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗред рдЗрд╕ рд╕рд░рдгреА рдореЗрдВ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рднрд╛рд╖рд╛ рдкрд╣рд▓реА рд╣реЛрдиреА рдЪрд╛рд╣рд┐рдПред


рдирд┐рд╖реНрдХрд░реНрд╖


рдирддреАрдЬрддрди, рд╣рдореЗрдВ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдорд┐рд▓рдирд╛ рдЪрд╛рд╣рд┐рдП:


  • рдПрдХ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рдФрд░ рдЕрдиреБрдХреВрд▓рди рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХреЗ рд╕рд╛рде рд╕рд╛рдЗрдЯ рдХреЗ рдмрд╣реБрднрд╛рд╖реА рдкреЗрдбрд╝ рдХреА рддрд░рд╣ рдореЗрдиреВ рдХреЗ рд▓рд┐рдП рдПрдХ рддреИрдпрд╛рд░ рдореЙрдбреНрдпреВрд▓;
  • рдПрдХ рдмреБрдирд┐рдпрд╛рджреА рд╕реАрдЖрд░рдпреВрдбреА рдирд┐рдпрдВрддреНрд░рдХ рдЬреЛ рд▓рдХрдбрд╝реА рдФрд░ рдмрд╣реБрднрд╛рд╖реАрд╡рд╛рдж рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рдЕрдиреНрдп рдореЙрдбреНрдпреВрд▓ рдмрдирд╛рддреЗ рд╕рдордп рд╡рд┐рд░рд╛рд╕рдд рдореЗрдВ рдорд┐рд▓ рд╕рдХрддрд╛ рд╣реИ;
  • рджреЛ рд▓рдХреНрд╖рдг (рдмрд╣реБрднрд╛рд╖реА рдФрд░ рдкреЗрдбрд╝) рдЬреЛ рд╕рдВрдмрдВрдзрд┐рдд рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдореЙрдбрд▓ рд╕реЗ рдЬреБрдбрд╝реЗ рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВред

рдореБрдЭреЗ рдЙрдореНрдореАрдж рд╣реИ рдХрд┐ рдпрд╣ рд▓реЗрдЦ рдЙрдкрдпреЛрдЧреА рд╣реЛрдЧрд╛ рдФрд░ Yii2 рдкрд░ рдирдИ рдЕрдЪреНрдЫреА рдкрд░рд┐рдпреЛрдЬрдирд╛рдУрдВ рдХреЛ рд╡рд┐рдХрд╕рд┐рдд рдХрд░рдиреЗ рдореЗрдВ рдЖрдкрдХреА рдорджрдж рдХрд░реЗрдЧрд╛ред

Source: https://habr.com/ru/post/hi426625/


All Articles