Кохана 3.2. - Как я могу использовать дефисы в URI? - PullRequest
3 голосов
/ 13 сентября 2011

Недавно я провел некоторое исследование SEO и того, как URI, использующие дефисы или подчеркивания, трактуются по-разному, особенно в Google, который рассматривает дефисы в качестве разделителей.По этим критериям я обнаружил, что поскольку Kohana использует имена функций для определения страниц, я получал неожиданное предупреждение «-».

Мне было интересно, есть ли способ включить использование URI в Kohana, например:

http://www.mysite.com/controller/function-name

Очевидно, я мог бы настроить для этого routeHandler ... но если бы у меня был пользовательский контент, то есть новости.Затем мне нужно было бы получить все статьи из базы данных, создать URI, а затем выполнить маршрутизацию для каждой из них.

Существуют ли альтернативные решения?

Ответы [ 5 ]

3 голосов
/ 06 января 2012

Примечание. Это тот же подход, что и в ответ Лорана , только немного более ООП.Kohana позволяет очень легко перегрузить любой системный класс, поэтому мы можем использовать его для экономии времени при наборе текста, а также для более чистых обновлений в будущем.

Мы можем подключиться к потоку запросовв Kohana и исправить черточки в части действия URL.Для этого мы переопределим системный класс Request_Client_Internal и его метод execute_request ().Там мы проверим, есть ли в запросе-> действие тире, и если это так, мы переключим их на подчеркивания, чтобы позволить php правильно вызывать наш метод.

Шаг 1. Откройте ваш application / bootstrap.php и добавьте эту строку:

define('URL_WITH_DASHES_ONLY', TRUE);

Эта константа используется для быстрого отключения этой функции в некоторых запросах, если вам нужно подчеркнуть подчеркивание в URL.

Шаг 2. Создайте новый php-файл в: application / classes / request / client / internal.php и вставьте этот код:

<?php defined('SYSPATH') or die('No direct script access.');

class Request_Client_Internal extends Kohana_Request_Client_Internal {

    /**
     * We override this method to allow for dashes in the action part of the url
     * (See Kohana_Request_Client_Internal::execute_request() for the details)
     *
     * @param   Request $request
     * @return  Response
     */
    public function execute_request(Request $request)
    {
        // Check the setting for dashes (the one set in bootstrap.php)
        if (defined('URL_WITH_DASHES_ONLY') and URL_WITH_DASHES_ONLY == TRUE) 
        {
            // Block URLs with underscore in the action to avoid duplicated content
            if (strpos($request->action(), '_') !== false)
            {
                throw new HTTP_Exception_404('The requested URL :uri was not found on this server.', array(':uri' => $request->uri()));
            }

            // Modify action part of the request: transform all dashes to underscores
            $request->action( strtr($request->action(), '-', '_') );
        }
        // We are done, let the parent method do the heavy lifting
        return parent::execute_request($request);
    }

} // end_class Request_Client_Internal

Это просто заменяет все дефисы в действии $ request-> на подчеркивания, поэтому, если url был / что-то / foo-bar , Kohana теперь с радостью направит его в наш action_foo_bar ()метод.

В то же время мы блокируем все действия с подчеркиванием, чтобы избежать проблем с дублированным контентом.

1 голос
/ 19 сентября 2011

Вы можете сделать это с помощью лямбда-функций: http://forum.kohanaframework.org/discussion/comment/62581#Comment_62581

1 голос
/ 13 сентября 2011

Нет способа напрямую отобразить дефисную строку в функцию PHP, поэтому вам придется выполнять маршрутизацию.

Что касается пользовательского контента, вы можете сделать что-то вроде Stack Exchange.Каждый раз, когда пользовательский контент сохраняется в базе данных, создается слаг для него (kohana-3-2-how-can-i-use-hyphens-in-uris) и сохраняется его вместе с другой информацией.Затем, когда вам нужно сделать ссылку на него, используйте уникальный идентификатор и добавьте слаг в конец (например: /4285354/kohana-3-2-kak-ya-mogu-ispolzovat-defisy-v-uri) для удобства чтения.

0 голосов
/ 19 сентября 2011

Перепробовав различные решения, я обнаружил, что самый простой и надежный способ - переопределить Kohana_Request_Client_Internal::execute_request. Для этого добавьте файл в папку application в «application \ classes \ kohana \ request \ client \ internal.php», а затем установите его содержимое на:

<?php defined('SYSPATH') or die('No direct script access.');
class Kohana_Request_Client_Internal extends Request_Client {

    /**
     * @var    array
     */
    protected $_previous_environment;

    /**
     * Processes the request, executing the controller action that handles this
     * request, determined by the [Route].
     *
     * 1. Before the controller action is called, the [Controller::before] method
     * will be called.
     * 2. Next the controller action will be called.
     * 3. After the controller action is called, the [Controller::after] method
     * will be called.
     *
     * By default, the output from the controller is captured and returned, and
     * no headers are sent.
     *
     *     $request->execute();
     *
     * @param   Request $request
     * @return  Response
     * @throws  Kohana_Exception
     * @uses    [Kohana::$profiling]
     * @uses    [Profiler]
     * @deprecated passing $params to controller methods deprecated since version 3.1
     *             will be removed in 3.2
     */
    public function execute_request(Request $request)
    {
        // Create the class prefix
        $prefix = 'controller_';

        // Directory
        $directory = $request->directory();

        // Controller
        $controller = $request->controller();

        if ($directory)
        {
            // Add the directory name to the class prefix
            $prefix .= str_replace(array('\\', '/'), '_', trim($directory, '/')).'_';
        }

        if (Kohana::$profiling)
        {
            // Set the benchmark name
            $benchmark = '"'.$request->uri().'"';

            if ($request !== Request::$initial AND Request::$current)
            {
                // Add the parent request uri
                $benchmark .= ' « "'.Request::$current->uri().'"';
            }

            // Start benchmarking
            $benchmark = Profiler::start('Requests', $benchmark);
        }

        // Store the currently active request
        $previous = Request::$current;

        // Change the current request to this request
        Request::$current = $request;

        // Is this the initial request
        $initial_request = ($request === Request::$initial);

        try
        {
            if ( ! class_exists($prefix.$controller))
            {
                throw new HTTP_Exception_404('The requested URL :uri was not found on this server.',
                                                    array(':uri' => $request->uri()));
            }

            // Load the controller using reflection
            $class = new ReflectionClass($prefix.$controller);

            if ($class->isAbstract())
            {
                throw new Kohana_Exception('Cannot create instances of abstract :controller',
                    array(':controller' => $prefix.$controller));
            }

            // Create a new instance of the controller
            $controller = $class->newInstance($request, $request->response() ? $request->response() : $request->create_response());

            $class->getMethod('before')->invoke($controller);

            // Determine the action to use
            /* ADDED */ if (strpos($request->action(), '_') !== false) throw new HTTP_Exception_404('The requested URL :uri was not found on this server.', array(':uri' => $request->uri()));
            /* MODIFIED */ $action = str_replace('-', '_', $request->action()); /* ORIGINAL: $action = $request->action(); */

            $params = $request->param();

            // If the action doesn't exist, it's a 404
            if ( ! $class->hasMethod('action_'.$action))
            {
                throw new HTTP_Exception_404('The requested URL :uri was not found on this server.',
                                                    array(':uri' => $request->uri()));
            }

            $method = $class->getMethod('action_'.$action);

            $method->invoke($controller);

            // Execute the "after action" method
            $class->getMethod('after')->invoke($controller);
        }
        catch (Exception $e)
        {
            // Restore the previous request
            if ($previous instanceof Request)
            {
                Request::$current = $previous;
            }

            if (isset($benchmark))
            {
                // Delete the benchmark, it is invalid
                Profiler::delete($benchmark);
            }

            // Re-throw the exception
            throw $e;
        }

        // Restore the previous request
        Request::$current = $previous;

        if (isset($benchmark))
        {
            // Stop the benchmark
            Profiler::stop($benchmark);
        }

        // Return the response
        return $request->response();
    }
} // End Kohana_Request_Client_Internal

Затем, чтобы добавить действие с дефисами, например, «controller / my-action», создайте действие под названием «my_action ()».

Этот метод также выдает ошибку, если пользователь пытается получить доступ к «controller / my_action» (чтобы избежать дублирования содержимого).

Я знаю, что некоторым разработчикам этот метод не нравится, но его преимущество в том, что он не переименовывает действие, поэтому, если вы проверите текущее действие, его везде будут постоянно называть «моим действием». При использовании метода функции Route или lambda действие иногда будет называться my_action, иногда my-action (поскольку оба метода переименовывают действие).

0 голосов
/ 13 сентября 2011

Вы можете сделать что-то вроде

Route::set('route', '<controller>/<identifier>', array(
    'identifier' => '[a-zA-Z\-]*'
))
->defaults(array(
    'controller' => 'Controller',
    'action'     => 'show',
));

Затем получить идентификатор контента в функции с помощью Request::current()->param('identifier') и проанализировать его вручную, чтобы найти соответствующие данные.

...