質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.91%

laravel5の2階層の一括ルーティング

解決済

回答 4

投稿

  • 評価
  • クリップ 0
  • VIEW 2,190

SeijiroKomatsu

score 10

前提・実現したいこと

全てアクセスに関して1つ1つルーティングしていくのはすごく面倒なので
https://ドメイン/ディレクトリ/コントローラファイル名/アクション名/id/
っていうふうにしたいです。
ルーティングの設定をどのようにすればいいのでしょうか?

発生している問題・エラーメッセージ

他のサイトをいくらぐぐっても無理でした。

エラーメッセージ

該当のソースコード

php

Route::any('{one?}/{two?}/{three?}/{four?}/{five?}/{six?}/{seven?}/{eight?}/{nine?}/{ten?}/'
, function($one='top',$two=null,$three=null,$four=null) {
$app        = app();

$two        = ucfirst($two);
$app_path    = app_path();
if (file_exists($app_path.'/Http/Controllers/'.$one.'/'.$two.'Controller.php')) {
$controller = "App\Http\Controllers\\".$one."\\".$two."Controller";
$foo = new $controller;
$foo->$three($four);
} else {
header("HTTP/1.0 404 Not Found");
die(View::make('common/404'));
}
});
```

試したこと

と書くとViewが動かなくなりました。
laravel4なら動いてたのに、5になって動かなくなりました。

補足情報(言語/FW/ツール等のバージョンなど)

laravel5 

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 4

+1

https://ドメイン/ディレクトリ/コントローラファイル名/アクション名/id/

このように決めているのであれば、以下のようにしてはどうでしょう。
(Laravelのバージョンは5.4)

ルーティング(汎用的なものに修正)

// その他ルーティング
Route::any('a/b/c', 'AbcsController@abc');

// [ 規定 ]
// https://ドメイン/ディレクトリ/コントローラファイル名/アクション名/id/ 
$paths = explode('/', Request::path());
if (!empty($paths) && count($paths) >= 3) {
    // 規定にマッチするが、別にルーティングをしたい場合
    // 規定と同じURLのものがある場合は、先に書いた方が優先して表示される
    Route::any('aa/bb/cc', 'FugasController@aaa');

    // 規定通りにルーティングをする場合
    $paths[0] = \Doctrine\Common\Inflector\Inflector::classify($paths[0]);
    $paths[1] = \Doctrine\Common\Inflector\Inflector::classify($paths[1]);
    Route::group(['namespace' => $paths[0]], function () use ($paths) {
        Route::any('{directory}/{controller}/{action}/{id?}/', $paths[1].'Controller@'.$paths[2]);
    });
}

コントローラーの例

namespace App\Http\Controllers\Hoge;

class HogesController extends \App\Http\Controllers\Controller
{
    public function show($directory, $controller, $action, $id=null)
    {
        dd([$directory, $controller, $action, $id]);
    }
}

例:
https://example.com/hoge/hoges/show/123/
(ドメイン:example.comを利用)
(ディレクトリー:App\Http\Controllers\Hogeにコントローラーがある)
(コントローラー:HogesController)
(アクション:showアクションにアクセス)
(ID:idは123)

上記ルーティングのコードの\Doctrine\Common\Inflector\Inflector::classify()は以下を使っています。

/**
 * Converts a word into the format for a Doctrine class name. Converts 'table_name' to 'TableName'.
 *
 * @param string $word The word to classify.
 *
 * @return string The classified word.
 */
public static function classify($word)
{
    return str_replace(" ", "", ucwords(strtr($word, "_-", "  ")));
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/07/07 10:07

    回答ありがとうございます。
    ディレクトリはView内ではなくコントローラ内にディレクトリがほしいです。

    キャンセル

  • 2017/07/07 12:41 編集

    修正しました。
    Route::group()の'namespace'でコントローラー内のディレクトリを指定します。
    ディレクトリが変わるので、コントローラーではnamespaceをApp\Http\Controllers\Hogeとして、Controllerについてもextends \App\Http\Controllers\Controllerのように指定します。

    キャンセル

  • 2017/07/08 14:40

    ありがとうございました。解決しました。namespaceを考慮する必要があったんですね。

    キャンセル

0

if文をついかすれば安全ですね。ありがとうございました。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

もうちょっと修正を加えました。 参考までに

$paths = explode('/', Request::path());
$paths[0] = isset($paths[0]) ? ucfirst($paths[0]) : '';
$paths[1] = isset($paths[1]) ? ucfirst($paths[1]) : '';
$paths[2] = isset($paths[2]) ? $paths[2] : 'default';
if (file_exists(app_path().'/Http/Controllers/'.$paths[0].'/'.$paths[1].'Controller.php')) {
$controller = 'App\Http\Controllers\\'.$paths[0].'\\'.$paths[1].'Controller';
$instance = new $controller;
if (method_exists($instance,$paths[2])) {
Route::group(['namespace' => $paths[0]], function () use ($paths) {
Route::any('{directory}/{controller}/{action?}/{id?}/{five?}/{six?}/{seven?}/', $paths[1] . 'Controller@' . $paths[2]);
});      
}
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

check解決した方法

-2

$paths = explode('/', Request::path());
$paths[0] = isset($paths[0]) ? ucfirst($paths[0]) : '';
$paths[1] = isset($paths[1]) ? ucfirst($paths[1]) : '';
$paths[2] = isset($paths[2]) ? $paths[2] : '';
if (file_exists(app_path().'/Http/Controllers/'.$paths[0].'/'.$paths[1].'Controller.php')) {
  Route::group(['namespace' => $paths[0]], function () use ($paths) {
    Route::any('{directory}/{controller}/{action}/{id?}/', $paths[1].'Controller@'.$paths[2]);
  });
}


ありがとうございました。解決しました。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/07/08 16:39

    解決してよかったです!
    でも「解決した方法」は細かいところを除いてまんま私のコードですよね…

    下記の回答では回答用にポイントを絞って書いており変なところがあったので、汎用的なものに書き換えました。

    ルーティングではファイルの有無をチェックする必要は基本的にはありません。
    ルーティングで拾えないものは404となるだけです。
    ただ、自分の規定通りのアクセスがきた場合のみ、500エラーにならないように気を付ける必要はあります。

    あと、以下は好みの話ですが……

    コントローラーの名前などは自分で好きにつければいいと思いますが、私はNamesControllerやTableNamesControllerとしたいです。
    また、\Doctrine\Common\Inflector\Inflector::classify()を使ってURLを変換したいです。
    なぜなら、URLを/table_names/…のように指定した場合、簡単に"TableNames"に変換することができるためです。
    ucfirst()を使う場合は"TableNames"に一発で変換するためには、URLを/tableNames/…のように一部大文字を使ってあらわす必要があるためです。
    URLに大文字は不格好なイメージがあります。
    すみません好みの問題ですが。

    キャンセル

  • 2017/07/08 21:11

    >ルーティングで拾えないものは404となるだけです。
    これは試してみたいと思います。
    \Doctrine\Common\Inflector\Inflector::classify()でそういう使い方ができるんですね。
    回答ありがとうございました。助かりました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.91%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る