Yii2の動作を作成する

多くの場合、そして実際、ほとんどの場合、サイトを作成するとき、データベースのエンティティのIDではなく、テキスト識別子によってサイトのページを開く必要があります。それをslugと呼びましょう。

post/view/1 => post/view/testovaya-novost 


(URLからビューを削除する価値がありますが、レッスンはそれについてではありません)

最も基本的な方法は、ポストテーブルにスラッグフィールドを作成し、ポストモデルに新しい属性を表示し、ビューに新しい入力を追加して、ペンでスラッグを駆動することです。

 <?php use yii\helpers\Html; use yii\widgets\ActiveForm; /** * @var yii\web\View $this * @var common\models\Post $model * @var yii\widgets\ActiveForm $form */ ?> <div class="post-form"> <?php $form = ActiveForm::begin(); ?> <?= $form->field( $model, 'name' )->textInput( [ 'maxlength' => 255 ] ) ?> <?= $form->field( $model, 'slug' )->textInput( [ 'maxlength' => 255 ] ) ?> <?= $form->field( $model, 'content' )->textarea( [ 'rows' => 6 ] ) ?> <div class="form-group"> <?= Html::submitButton( $model->isNewRecord ? Yii::t( 'app', 'Create' ) : Yii::t( 'app', 'Update' ), [ 'class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary' ] ) ?> </div> <?php ActiveForm::end(); ?> </div> 




しかし、ペンでそれを行うことは必ずしも面白くない(私がだましている人にはまったく面白くない)ので、モデルに保存すると、名前からスラッグを自動的に生成し、テーブルでその一意性をチェックするメソッドを追加します(スラッグから投稿を抽出するため)ベース、したがって、スラッグは一意ではありません)、まあ、そしておそらくそれを音訳します(test-news => testovaya-novost)-これも有用です。
まあ、私たちは書いて、イベントにアタッチして、テストします-すべてがうまくいきます。 そして、ここで、サイトを開発するとき、ページモデルでナメクジがまだ必要であるという事実に直面しています。 また、商品のカタログでも-それをアイテムモデルにします。 抵抗が最も少ないパス-コピー&ペーストをたどることができます。 しかし...

Yiiには、ビヘイビアなどの機能があります。異なるモデルで同じ機能を使用できる機能です。 それでは、slug'ificationの動作を記述しましょう。

Postモデル(別名\ commoin \ models \ Post)では、まだ作成されていない動作を接続します:

 public function behaviors() { return [ 'slug' => [ 'class' => 'common\behaviors\Slug', 'in_attribute' => 'name', 'out_attribute' => 'slug', 'translit' => true ] ]; } 


接続に必要な動作関数を作成し、配置先のクラスを登録して、このクラスに3つの属性を渡しました。
1. in_attribute-スラッグが生成されるモデルの属性(異なるモデルでは、名前やタイトルなど、異なる場合があります)
2. out_attributeはそれぞれスラッグの属性です(スラッグまたはエイリアス)
3. translit-すべてはここで明確です

ビヘイビアを作成するときに、別の4番目の属性がありました-一意ですが、この機能を除外しました。 ナメクジがユニークではないことは非常にまれです。

yii2-app-advancedアプリケーションの構造を使用していることを思い出させてください。つまり、コントローラーとビューが配置されているバックエンドとフロントエンドのフォルダー、および共通のモデルと動作を持つ共通のフォルダーがあります。

一般的な/動作/ Slug.phpを作成します。

 <?php namespace common\behaviors; use yii; use yii\base\Behavior; use yii\db\ActiveRecord; class Slug extends Behavior { public $in_attribute = 'name'; public $out_attribute = 'slug'; public $translit = true; public function events() { return [ ActiveRecord::EVENT_BEFORE_VALIDATE => 'getSlug' ]; } } 


yii \ base \ Behaviorからクラスを継承し、3つの属性を初期設定で指定し、モデルを保存するときに一部のイベントに動作をアタッチするイベントメソッドを作成します。 通常、スラッグは必要であり、必要に応じてルールに記述できるため、検証の前にスラッグの生成をバインドします。

 ActiveRecord::EVENT_BEFORE_VALIDATE => 'getSlug' 


次に、getSlugメソッドを作成します。

 public function getSlug( $event ) { if ( empty( $this->owner->{$this->out_attribute} ) ) { $this->owner->{$this->out_attribute} = $this->generateSlug( $this->owner->{$this->in_attribute} ); } else { $this->owner->{$this->out_attribute} = $this->generateSlug( $this->owner->{$this->out_attribute} ); } } 


モデルオブジェクト自体は、$ this-> ownerとして動作に渡されます。 したがって、slug属性の名前は変数$ this->に渡されるため、$ this-> owner-> slugまたはこの場合は$ this-> owner-> {$ this-> out_attribute}を呼び出すことで、slugを使用できます。 out_attribute。
保存時にスラッグが空かどうかを確認し、空の場合は名前(レコードのタイトル)から生成します。 空でない場合、受け取ったスラッグを処理します。

 private function generateSlug( $slug ) { $slug = $this->slugify( $slug ); if ( $this->checkUniqueSlug( $slug ) ) { return $slug; } else { for ( $suffix = 2; !$this->checkUniqueSlug( $new_slug = $slug . '-' . $suffix ); $suffix++ ) {} return $new_slug; } } 


メソッドの最初の行では、slugify関数を使用して不要な文字を削除し、必要に応じて文字変換に変換します。 すぐに見てみましょう:

 private function slugify( $slug ) { if ( $this->translit ) { return Inflector::slug( TransliteratorHelper::process( $slug ), '-', true ); } else { return $this->slug( $slug, '-', true ); } } 


文字変換とは何ですか? これは、標準ラテンアルファベットの類似物による国別記号の転送です。 外国のインターネットで見つかったほとんどのスニペットは、ウムラウト、キャップ、およびその他の文字からのテキストのみをクリアします( 'À' => 'A'、 'Á' => 'A'、 'Â' => 'A'、 'Ã' = > 'A'、)、つまり、「汚れた」ラテン語から「クリーン」にする。 標準ヘルパーyii2 yii \ helpers \ Inflector :: slugもこれを行います(ちなみに、このメソッドはビヘイビアの作成中に非互換に変更されました-yii2での開発はまだ進行中です)。 RuNetでは、キリル文字をラテン文字に置き換えてそれぞれ追加します。 しかし、私は最も柔軟な音訳を作成したいと思います。 yii \ helpers \ Inflector :: slugの最新バージョンはphp拡張intlを使用します。これには中国語の文字の音訳も含まれますが、理解しているように、デフォルトでは有効になっていません(php 5.5.6)。 しかし、yiiに興味があるすべての人に馴染みのある素晴らしい2amigos開発者は、文字変換器とヘルパーのアドオンを見つけました(それは、私の知る限り、drupalのアイデアを使用しています)。 これは、特定の数のphpファイルを表し、ほとんどの文字とその置換をラテン語で記述しています。
依存関係"2amigos/transliterator-helper": "2.0.*"を追加し"2amigos/transliterator-helper": "2.0.*" composer.jsonに更新し、dosamigos \ helpers \ TransliteratorHelperが利用可能になりました:

 return Inflector::slug( TransliteratorHelper::process( $slug ), '-', true ); 


アルファベット以外の文字から明確に音訳し、スペースをダッシュ​​「-」に置き換えます。

文字変換が不要な場合:

 return $this->slug( $slug, '-', true ); 


スラッグ法(yii \ helpers \ Inflectorの短縮版::音訳なしのスラッグ):

 private function slug( $string, $replacement = '-', $lowercase = true ) { $string = preg_replace( '/[^\p{L}\p{Nd}]+/u', $replacement, $string ); $string = trim( $string, $replacement ); return $lowercase ? strtolower( $string ) : $string; } 


generateSlugに戻る:

 private function generateSlug( $slug ) { $slug = $this->slugify( $slug ); if ( $this->checkUniqueSlug( $slug ) ) { return $slug; } else { for ( $suffix = 2; !$this->checkUniqueSlug( $new_slug = $slug . '-' . $suffix ); $suffix++ ) {} return $new_slug; } } 


2行目では、データベースの一意性についてスラッグをチェックします。 テーブルからデータを抽出するために使用するため、一意でないスラッグは必要ありません。

 private function checkUniqueSlug( $slug ) { $pk = $this->owner->primaryKey(); $pk = $pk[0]; $condition = $this->out_attribute . ' = :out_attribute'; $params = [ ':out_attribute' => $slug ]; if ( !$this->owner->isNewRecord ) { $condition .= ' and ' . $pk . ' != :pk'; $params[':pk'] = $this->owner->{$pk}; } return !$this->owner->find() ->where( $condition, $params ) ->one(); } 


理論的には、主キーはidではない可能性があるため、primaryKey()関数で見つけることができます。 次に、このようなスラッグの存在をテーブルに要求します。 レコードが新しくなく、更新を行う場合(!$ This-> owner-> isNewRecord)、slugがすでに存在し、このidに対して例外を作成する場合があります。

 $condition .= ' and ' . $pk . ' != :pk'; 


この関数は、slugが一意の場合はtrueを返し、そうでない場合はfalseを返します。 次:

 if ( $this->checkUniqueSlug( $slug ) ) { return $slug; } else { for ( $suffix = 2; !$this->checkUniqueSlug( $new_slug = $slug . '-' . $suffix ); $suffix++ ) {} return $new_slug; } 


スラッグが一意である場合、それを返し、モデル属性に割り当てて、モデルをデータベースに保存します。 一意でない場合は、デジタルサフィックスtestovaya-novost-2を追加します

 for ( $suffix = 2; !$this->checkUniqueSlug( $new_slug = $slug . '-' . $suffix ); $suffix++ ) {} 


ブルートフォース法を使用して、最初の空き接尾辞を見つけてスラッグに追加します。 ソリューションはWordPressで作成されていますが、接尾辞がtestovaya-novost、testovaya-novost-2、testovaya-novost-3、testovaya-novost-4、testovaya-novost-5の場合は、それぞれの接尾辞に対してオンデマンドで実行します一意性を確認するには、6つのクエリを作成する必要があります。 誰もがより良い解決策を提供できるなら、私は感謝します。

したがって、スラッグが生成され、モデルに転送され、データベースに保存され、結果の動作を他のモデルで使用します。

動作の全文:
 <?php namespace common\behaviors; use dosamigos\helpers\TransliteratorHelper; use yii; use yii\base\Behavior; use yii\db\ActiveRecord; use yii\helpers\Inflector; class Slug extends Behavior { public $in_attribute = 'name'; public $out_attribute = 'slug'; public $translit = true; public function events() { return [ ActiveRecord::EVENT_BEFORE_VALIDATE => 'getSlug' ]; } public function getSlug( $event ) { if ( empty( $this->owner->{$this->out_attribute} ) ) { $this->owner->{$this->out_attribute} = $this->generateSlug( $this->owner->{$this->in_attribute} ); } else { $this->owner->{$this->out_attribute} = $this->generateSlug( $this->owner->{$this->out_attribute} ); } } private function generateSlug( $slug ) { $slug = $this->slugify( $slug ); if ( $this->checkUniqueSlug( $slug ) ) { return $slug; } else { for ( $suffix = 2; !$this->checkUniqueSlug( $new_slug = $slug . '-' . $suffix ); $suffix++ ) {} return $new_slug; } } private function slugify( $slug ) { if ( $this->translit ) { return Inflector::slug( TransliteratorHelper::process( $slug ), '-', true ); } else { return $this->slug( $slug, '-', true ); } } private function slug( $string, $replacement = '-', $lowercase = true ) { $string = preg_replace( '/[^\p{L}\p{Nd}]+/u', $replacement, $string ); $string = trim( $string, $replacement ); return $lowercase ? strtolower( $string ) : $string; } private function checkUniqueSlug( $slug ) { $pk = $this->owner->primaryKey(); $pk = $pk[0]; $condition = $this->out_attribute . ' = :out_attribute'; $params = [ ':out_attribute' => $slug ]; if ( !$this->owner->isNewRecord ) { $condition .= ' and ' . $pk . ' != :pk'; $params[':pk'] = $this->owner->{$pk}; } return !$this->owner->find() ->where( $condition, $params ) ->one(); } } 



動作コードは上記のとおりです。 音訳の例:

    test 我爱 中文 Ψ ᾉ Ǽ ß  => test-test-y-test-wo-ai-zhong-wen-ps-a-ae-ss-c 


参照:

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


All Articles