便利なURL生成(CNC)。 Laravel 4 +サードパーティパッケージ

URLとその使用例を生成するための便利なツールを共有したいと思います。



タスクはそれほど大きくはありませんが、常に発生するものであり、それを解決するために自転車書くのに費やす時間を減らしたいと思います。 また、さまざまなクラス、メソッド、関数などの呼び出しの広範な使用を取り除き、必要に応じてURLを生成します。 ああ、私はLaravelを使用していますが、そのためにツールが投獄されています。



ツールリンク







これで十分です。



問題の声明



/ resource / 1の代わりに/ resource / unique-resource-urlを介してアクセスするためのデータベーステーブルのエントリの一意のURLの自動生成。





降りる



ユーザーがサイト製品のリストを表示するときにどの地域/都市が選択されているかを簡単にナビゲートできるように、国と都市でサイトの検索を中断する必要があるとします。



新しいプロジェクトを作成することから始めましょう。



composer create-project laravel/laravel habr_url --prefer-dist
      
      





次に、 habr_urlのルートでcomposer.jsonを開き必要なパッケージを追加します。



 { "name": "laravel/laravel", "description": "The Laravel Framework.", "keywords": ["framework", "laravel"], "license": "MIT", "require": { "laravel/framework": "4.1.*", "ivanlemeshev/laravel4-cyrillic-slug": "dev-master", "cviebrock/eloquent-sluggable": "1.0.*", "way/generators": "dev-master" }, "autoload": { "classmap": [ "app/commands", "app/controllers", "app/models", "app/database/migrations", "app/database/seeds", "app/tests/TestCase.php" ] }, "scripts": { "post-install-cmd": [ "php artisan optimize" ], "post-update-cmd": [ "php artisan clear-compiled", "php artisan optimize" ], "post-create-project-cmd": [ "php artisan key:generate" ] }, "config": { "preferred-install": "dist" }, "minimum-stability": "dev" }
      
      





"way/generators": "dev-master"



は、迅速なプロトタイプ作成のために追加します。



コンソールでcomposer update



コマンドを実行し、パッケージが正常にインストールされた後、 app / config / app.phpに変更を加えます。



 <?php return array( // ... 'providers' => array( // ... 'Ivanlemeshev\Laravel4CyrillicSlug\SlugServiceProvider', 'Cviebrock\EloquentSluggable\SluggableServiceProvider', 'Way\Generators\GeneratorsServiceProvider', ), // ... 'aliases' => array( // ... 'Slug' => 'Ivanlemeshev\Laravel4CyrillicSlug\Facades\Slug', 'Sluggable' => 'Cviebrock\EloquentSluggable\Facades\Sluggable', ), ); ?>
      
      





標準のStrクラスはラテン語でのみ機能するため、 Slugクラスを使用するとキリル文字からURLを生成できます。 Sluggableについては後ほど説明します。



コードを生成する


 php artisan generate:scaffold create_countries_table --fields="name:string:unique, code:string[2]:unique" php artisan generate:scaffold create_cities_table --fields="name:string, slug:string:unique, country_id:integer:unsigned" php artisan generate:scaffold create_products_table --fields="name:string, slug:string:unique, price:integer, city_id:integer:unsigned"
      
      





外部キーを追加して新しいファイルを変更します。



 //  app/database/migrations/____create_cities_table.php class CreateCitiesTable extends Migration { // ... public function up() { Schema::create('cities', function(Blueprint $table) { $table->increments('id'); $table->string('name'); $table->string('slug')->unique(); $table->integer('country_id')->unsigned()->index(); $table->foreign('country_id')->references('id')->on('countries')->onDelete('cascade'); $table->timestamps(); }); } // ... }
      
      





 //  app/database/migrations/____create_products_table.php class CreateProductsTable extends Migration { // ... public function up() { Schema::create('products', function(Blueprint $table) { $table->increments('id'); $table->string('name'); $table->string('slug')->unique(); $table->integer('price'); $table->integer('city_id')->unsigned()->index(); $table->foreign('city_id')->references('id')->on('cities')->onDelete('cascade'); $table->timestamps(); }); } // ... }
      
      





また、 seeds



を通じてデータベースにいくつかの国と都市を追加します。 app / database / seedsフォルダーを開き、2つのファイルを変更します。



 //  app/database/seeds/CountriesTableSeeder.php class CountriesTableSeeder extends Seeder { public function run() { $countries = array( array('name' => '', 'code' => 'ru'), array('name' => '', 'code' => 'ua') ); // Uncomment the below to run the seeder DB::table('countries')->insert($countries); } }
      
      





 //  app/database/seeds/CitiesTableSeeder.php class CitiesTableSeeder extends Seeder { public function run() { // Uncomment the below to wipe the table clean before populating // DB::table('cities')->truncate(); $cities = array( array('name' => '', 'slug' => Slug::make(''), 'country_id' => 1), array('name' => '-', 'slug' => Slug::make('-'), 'country_id' => 1), array('name' => '', 'slug' => Slug::make(''), 'country_id' => 2), ); // Uncomment the below to run the seeder DB::table('cities')->insert($cities); } }
      
      





これはSlug::make($input)



を使用します。これは$input



を文字列として受け取り、そこからmoskva



またはsankt-peterburg



似たものを生成sankt-peterburg



ます。



次に、データベース設定を変更します。



 //  app/config/database.php return array( // ... 'connections' => array( // ... 'mysql' => array( 'driver' => 'mysql', 'host' => 'localhost', 'database' => 'habr_url', 'username' => 'habr_url', 'password' => 'habr_url', 'charset' => 'utf8', 'collation' => 'utf8_unicode_ci', 'prefix' => '', ), ), // ... );
      
      





そして、スキームとデータをデータベースに取り込みます。



 php artisan migrate --seed
      
      





そして、これが私たちが得たものです:









リンクモデルに追加し、属性のルールを追加します。



 //  app/models/Product.php class Product extends Eloquent { protected $guarded = array(); public static $rules = array( 'name' => 'required|alpha_num|between:2,255', 'slug' => 'required|alpha_num|between:2,255|unique:products,slug', 'price' => 'required|numeric|between:2,255', 'city_id' => 'required|exists:cities,id' ); public function city() { return $this->belongsTo('City'); } }
      
      





 //  app/models/City.php class City extends Eloquent { protected $guarded = array(); public static $rules = array( 'name' => 'required|alpha_num|between:2,255', 'slug' => 'required|alpha_num|between:2,255|unique:cities,slug', 'country_id' => 'required|exists:countries,id' ); public function country() { return $this->belongsTo('Country'); } public function products() { return $this->hasMany('Product'); } }
      
      





 //  app/models/Country.php class Country extends Eloquent { protected $guarded = array(); public static $rules = array( 'name' => 'required|alpha_num|between:2,255|unique:countries,name', 'code' => 'required|alpha|size:2|unique:countries,code' ); public function cities() { return $this->hasMany('City'); } public function products() { return $this->hasManyThrough('Product', 'City'); } }
      
      





CitiesController



およびProductsController



store



メソッドをCitiesController



ます。



 //  app/models/CitiesController.php class CitiesController extends BaseController { // ... public function store() { $input = Input::all(); $input['slug'] = Slug::make(Input::get('name', '')); // ! $validation = Validator::make($input, City::$rules); if ($validation->passes()) { $this->product->create($input); return Redirect::route('products.index'); } return Redirect::route('products.create') ->withInput() ->withErrors($validation) ->with('message', 'There were validation errors.'); } // ... }
      
      





 //  app/models/ProductsController.php class ProductsController extends BaseController { // ... public function store() { $input = Input::all(); $input['slug'] = Slug::make(Input::get('name', '')); // ! $validation = Validator::make($input, Product::$rules); if ($validation->passes()) { $this->product->create($input); return Redirect::route('products.index'); } return Redirect::route('products.create') ->withInput() ->withErrors($validation) ->with('message', 'There were validation errors.'); } // ... }
      
      





アプリ/ビュー/都市/create.blade.phpアプリ/ビュー/都市/edit.blade.phpアプリ/ビュー/製品/create.blade.phpアプリ/ビュー/製品/edit.blade.phpから削除します対応するフォーム要素。



素晴らしい、 URL



生成されURL



、それらが複製されるとどうなりますか? エラーが発生します。 そしてこれを避けるために- slug



一致する場合、接頭辞を追加する必要があり、接頭辞がある場合はそれをインクリメントします。 多くの作業がありますが、優雅さはありません。 これらのジェスチャーを避けるために、 Eloquent Sluggable



を使用しEloquent Sluggable







まず、 Eloquent Sluggable



の構成をプロジェクトにドロップしましょう。



 php artisan config:publish cviebrock/eloquent-sluggable
      
      





ここにある設定ファイルapp / config / cviebrock / eloquent-sluggable / config.phpで 、オプション'method' => null



'method' => array('Slug', 'make')



ます。 したがって、キリル文字から音訳への変換とURL



作成のタスクは、(キリル文字の操作方法を知らない標準のStrではなく) Slugクラスとそのmakeメソッドに割り当てられURL







このパッケージは何に適していますか? この原則に基づいて動作します。データベースにレコードを保存するeloquent.saving*



イベントを想定し、生成されたslug



をモデル設定で指定されたフィールドに書き込みます。 設定例:



 //  app/models/City.php class City extends Eloquent { protected $guarded = array(); public static $rules = array( 'name' => 'required|alpha_num|between:2,255', 'country_id' => 'required|exists:countries,id' ); //   public static $sluggable = array( 'build_from' => 'name', 'save_to' => 'slug', ); public function country() { return $this->belongsTo('Country'); } public function products() { return $this->hasMany('Product'); } }
      
      





既存のslug



と一致する場合、接頭辞-1-2などが新しいものに追加されます。 さらに、 slug



CitiesController@store



ルールを取り除き、 CitiesController@store



メソッドの$input['slug'] = Slug::make(Input::get('name', ''));



というCitiesController@store



$input['slug'] = Slug::make(Input::get('name', ''));







Product



についても同じことを行います。



 //  app/models/Product.php class Product extends Eloquent { protected $guarded = array(); public static $rules = array( 'name' => 'required|alpha_num|between:2,255', 'price' => 'required|numeric|between:2,255', 'city_id' => 'required|exists:cities,id' ); public static $sluggable = array( 'build_from' => 'name', 'save_to' => 'slug', ); public function city() { return $this->belongsTo('City'); } }
      
      





City



Modelで$sluggable



を次のように書き換えると、このslug



でさらに興味深いことができます。



 //  app/models/City.php class City extends Eloquent { protected $guarded = array(); public static $rules = array( 'name' => 'required|alpha_num|between:2,255', 'slug' => 'required|alpha_num|between:2,255|unique:cities,slug', 'country_id' => 'required|exists:countries,id' ); public static $sluggable = array( 'build_from' => 'name_with_country_code', 'save_to' => 'slug', ); public function country() { return $this->belongsTo('Country'); } public function products() { return $this->hasMany('Product'); } public function getNameWithCountryCodeAttribute() { return $this->country->code . ' ' . $this->name; } }
      
      





はい、オブジェクトから存在しないフィールドを選択し、ヘルパーとして追加できます。



CitiesTableSeeder



をわずかに変更して、目的の結果を達成します。



 //  app/database/seeds/CitiesTableSeeder.php class CitiesTableSeeder extends Seeder { public function run() { // Uncomment the below to wipe the table clean before populating // DB::table('cities')->truncate(); $cities = array( array('name' => '', 'country_id' => 1), array('name' => '-', 'country_id' => 1), array('name' => '', 'country_id' => 2), ); // Uncomment the below to run the seeder foreach ($cities as $city) { City::create($city); } } }
      
      





次に、移行をロールバックし、データとともに新しい移行を入力します。



 php artisan migrate:refresh --seed
      
      











いくつかのルートを追加します。



 //  app/routes.php // ... Route::get('country/{code}', array('as' => 'country', function($code) { $country = Country::where('code', '=', $code)->firstOrFail(); return View::make('products', array('products' => $country->products)); })); Route::get('city/{slug}', array('as' => 'city', function($slug) { $city = City::where('slug', '=', $slug)->firstOrFail(); return View::make('products', array('products' => $city->products)); })); Route::get('product/{slug}', array('as' => 'product', function($slug) { $product = Product::where('slug', '=', $slug)->firstOrFail(); return View::make('product', compact('product')); }));
      
      





そして、いくつかのパターンを追加します。



 <!--  app/views/nav.blade.php --> <ul class="nav nav-pills"> @foreach(Country::all() as $country) <li><a href="{{{ route('country', $country->code) }}}">{{{ $country->name }}}</a> @endforeach </ul>
      
      





 <!--  app/views/products.blade.php --> @extends('layouts.scaffold') @section('main') @include('nav') <h1>Products</h1> @if ($products->count()) <table class="table table-striped table-bordered"> <thead> <tr> <th>Name</th> <th>Price</th> <th>City</th> </tr> </thead> <tbody> @foreach ($products as $product) <tr> <td><a href="{{{ route('product', $product->slug)}}}">{{{ $product->name }}}</a></td> <td>{{{ $product->price }}}</td> <td><a href="{{{ route('city', $product->city->slug) }}}">{{{ $product->city->name }}}</a></td> </tr> @endforeach </tbody> </table> @else There are no products @endif @stop
      
      





 <!--  app/views/product.blade.php --> @extends('layouts.scaffold') @section('main') @include('nav') <h1>Product</h1> <table class="table table-striped table-bordered"> <thead> <tr> <th>Name</th> <th>Price</th> <th>City</th> </tr> </thead> <tbody> <tr> <td>{{{ $product->name }}}</td> <td>{{{ $product->price }}}</td> <td><a href="{{{ route('city', $product->city->slug) }}}">{{{ $product->city->name }}}</a></td> </tr> </tbody> </table> @stop
      
      





以上です。



デモとGit







PMでの通常のエラー。 提案と批判-コメントで。 ご清聴ありがとうございました。



All Articles