kohana 3 – rozdzielenie wywołań wewnętrznych i zewnętrznych

Dzisiaj ze wsparciem Zbyszka napisałem troszkę bardziej dopracowane rozwiązanie rozdzielania wywołań.

Wywołania jakie będziemy tu rozróżniać to wywołanie bezpośrednie, ajaxowe i wewnętrzne (internal), a kod poszczególnych akcji będziemy wywoływać w sposób następujący:

public function action_index() {
//akcja bezpośrednia
}
public function action_ajax_index() {
//akcja ajaxowa
}
public function action_internal_index() {
//akcja wewnętrzna wywołana przez Request::factory('controller/index');
}

Kontroler który będzie wykrywał co to za request nazwałem Controller_Application i wygląda on tak:

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

class Controller_Application extends Controller_Template {

	public function __construct(Request $req) {
		parent::__construct($req);

		if (Request::$is_ajax OR $this->request !== Request::instance()) {
			$this->auto_render = FALSE;
			$this->request->action = Request::$is_ajax ?
								"ajax_".$this->request->action :
								"internal_".$this->request->action;

		} else if (preg_match("/^internal|ajax/", $this->request->action)) {
			throw new Internal_Exception('called internal method');
		}
	}
}

Dodatkowym zabezpieczeniem jest wyrzucenie wyjątku kiedy ktoś stara się dostać do nie przeznaczonej do tego akcji bezpośrednio (czyli akcji które mają w nazwie internal lub ajax). Wyjątek ten pozwala nam rozpoznać takowy czyn i w późniejszym czasie go przechwycić i wykonać jakąś akcję. W tym wypadku wyrzucimy stronę z błędem 404, aby to zrobić w bootstrapie dodajemy coś takiego:

$request = Request::instance($_SERVER['PATH_INFO']);

try { // Attempt to execute the response
	$request->execute();
} catch (Exception $e) {
	// Create a error response
	if ($e instanceof Internal_Exception) {
		$request->status = 404;
	}
	$_status = $request->status;
	switch($request->status) {
		case 500: // other errors handling by errors controller
			break;
		default:
			$_status = 404;
	}
	$request->response = Request::factory("errors/{$_status}")->execute()->response;
}

Kontroler errors jest już prostym kontrolerem wyświetlającym stronę błędu.

Dodano poniedziałek, Marzec 29th, 2010 w kategoriach Kohana framework, Programowanie.

Tagi: ,

9 komentarze

  1. Ok po chwili zakumałem po co to. Mógłbyś napisać otwartym tekstem, że chodzi o możliwość definiowania akcji których wywołanie można ograniczyć tylko do wywołań via ajax lub tylko z innego kontrolera.

    Z kolei zamiast przekierowywać na errors/404 lepszym rozwiązaniem byłoby wywołanie Request::factory(‘errors/404′);

  2. l1em1on1 pisze:

    no może trochę namieszałem ;)

    a co do Request::factory(‘errors/404′); to nie do końca się zgodzę.. bo strona 404 jest dla mnie całkowicie odrębnym elementem, więc wywoływanie jej wewnętrznym requestem trochę mija się z celem.

  3. Nie zgodzę się z Tobą l1em1on1. W wielu przypadkach stronę 404 chcemy wyświetlić w „ramce” całej strony (przykłady: SmashingMagazine.com, Digg.com), a i sama Kohana3 napisana została z wykorzystaniem wzorca HMVC właśnie po to, aby była bardziej elastyczna i pozwalała m.in. na wywołania kontrolerów z kontrolerów (tutaj np. kontrolera error404).

  4. l1em1on1 pisze:

    po części się z Tobą zgadzam co do możliwości HMVC, ale nie koniecznie w tym wypadku ;) przynajmniej ja traktuję stronę błędu jako całkowicie oddzielna strona z całkowicie innym szablonem.. to że będzie z takim samym wyglądem nie znaczy, że jest jakkolwiek połączona. poza tym jednym wywołaniem nie nadpiszesz wszystkich zmiennych wyświetlanych w szablonie nadrzędnym. więc jedyne co można zrobić to wywołać $this->request->response = Request::factory(‘errors/404′)->execute()->response; co będzie skutkowało tym samym co redirect ;)

  5. Łukasz Sawicki pisze:

    poprzednie komentarze są jakby nie aktualne jeśli chodzi o powyższy kod, choć dały jakieś światło na problem.

  6. Problem polegał na tym aby nie wykonywać przekierowania np. z nagłówkiem 301Moved Permanently na stronę z błędem 404 Error page, tylko sprawić aby nagłówek 404 był zwracany od razu, a jednocześnie trzeba było zapobiec wykonaniu akcji zdefiniowanej jako wewnętrzna.

  7. Przyznam, że w Kohanie dopiero raczkuje, ale jedno co mnie ciekawi to czemu konstruktor, a nie before()? Ze względów wydajnościowych? Czy jest jeszcze jakieś ‘drugie dno’?

    Pozdrawiam

  8. Nie zgodzę się z Tobą l1em1on1. W wielu przypadkach stronę 404 chcemy wyświetlić w „ramce” całej strony (przykłady: SmashingMagazine.com, Digg.com), a i sama Kohana3 napisana została z wykorzystaniem wzorca HMVC właśnie po to, aby była bardziej elastyczna i pozwalała m.in. na wywołania kontrolerów z kontrolerów (tutaj np. kontrolera error404).

  9. Łukasz Sawicki pisze:

    @Marek
    Generalnie __construct() jest wywoływany wcześniej niż before() więc wydaje się to oczywistym wyborem, zwłaszcza dlatego, że wartość $this->auto_render jest sprawdzana w funkcji before() controllera widoku.

    Czyli podsumowując w before() mamy już przygotowanie do generowania danego widoku, więc jest to też ze względów wydajnościowych, bo po co niepotrzebnie generować coś co może okazać się zbędne.

    @Steve
    zgadzam się co do HMVC ale nie do wszystkiego musi być to wykorzystywane, prawda? ;) ja wyszedłem z założenia, że chce mieć stronę404 niezależną. Z kolei w wielu innych przypadkach właśnie z HMVC korzystam (logowanie, modularność itp.).
    Wszystko kwestia wyboru, nic nikomu nie narzucam ;) to jest moja propozycja, której nikt tak na prawdę nie musi wykorzystać.

    Oczywiście nic nie stoi na przeszkodzie aby obsługę błędów wyświetlać właśnie w „ramce”.

Napisz komentarz