2012-08-08 12 views
6

Yii-jedis!Come usare beforeAction in Yii o problemi di lumaca

Sto lavorando ad un vecchio progetto Yii e devo aggiungere alcune funzionalità. Yii è una struttura abbastanza logica ma ha alcune cose che non riesco a capire. Forse non ho ancora capito il modo Yii. Quindi descriverò il mio problema passo dopo passo. Per gli impazienti - domanda breve alla fine.

Intro: Desidero aggiungere URL leggibili da un utente al mio progetto. Ora URL assomiglia: www.site.com/article/359
E voglio loro di simile a questa: www.site.com/article/how-to-make-pretty-urls~~V~~3rd
Molto importante: i vecchi articoli devono essere disponibili su URL di vecchio formato e nuovi su nuovi URL.

Fase 1: In primo luogo, ho aggiornato le regole di riscrittura in config/main.php:

'<controller:\w+>/<id:\S+>' => '<controller>/view', 

E ho aggiunto nuovo texturl colonna alla tabella article. Quindi archiviamo qui -read-of-url leggibile dall'uomo per nuovi articoli. Quindi ho aggiornato un articolo con texturl per i test.

Fase 2: applicazione Visualizza articoli in ActionView di ArticleController così Ho aggiunto là di questo codice per preproccessing parametro ID:

if (is_numeric($id)) { 
    // User try to get /article/359 
    $model = $this->loadModel($id); // Article::model()->findByPk($id); 
    if ($model->text_url !== null) { 
     // If article with ID=359 have text url -> redirect to /article/text-url 
     $this->redirect(array('view', 'id' => $model->text_url), true, 301); 
    } 
} else { 
    // User try to get /article/text-url 
    $model = Article::model()->findByAttributes(array('text_url' => $id)); 
    $id = ($model !== null) ? $model->id : null ; 
} 

E poi iniziare il codice legacy:

$model = $this->loadModel($id); // Load article by numeric ID 
// etc 

It funziona perfettamente con lo! Ma ...

Passaggio 3: Ma abbiamo molte azioni con parametro ID! Cosa dobbiamo fare? Aggiorna tutte le azioni con quel codice? Penso che sia brutto. Ho trovato il metodo CController::beforeAction. Sembra buono! Quindi dichiaro beforeAction e luogo ID preproccessing lì:

protected function beforeAction($action) { 
    $actionToRun = $action->getId(); 
    $id = Yii::app()->getRequest()->getQuery('id'); 
    if (is_numeric($id)) { 
     $model = $this->loadModel($id); 
     if ($model->text_url !== null) { 
      $this->redirect(array('view', 'id' => $model->text_url), true, 301); 
     } 
    } else { 
     $model = Article::model()->findByAttributes(array('text_url' => $id)); 
     $id = ($model !== null) ? $model->id : null ; 
    } 
    return parent::beforeAction($action->runWithParams(array('id' => $id))); 
} 

Sì, funziona sia con URL-formati, ma esegue ActionViewDUE VOLTE e mostra la pagina due volte! Cosa posso fare con questo? Sono totalmente confuso. Ho scelto il modo giusto per risolvere il mio problema?

Brevemente: È possibile elaborare ID (parametro GET) prima di eseguire qualsiasi azione e quindi eseguire l'azione richiesta (una volta!) Con il parametro ID solo modificato?

+0

puoi provare con parametro vuoto .. return parent :: beforeAction(); Cosa viene emesso? – VibhaJ

+0

@VibhaJ genitore :: beforeAction() restituisce 404 e parent :: beforeAction ($ azione) restituisce 404 –

+0

aggiornato il mio codice ... Controlla ora – VibhaJ

risposta

12

Ultima riga dovrebbe essere:

return parent::beforeAction($action); 

anche per chiederti i didnt get vostro passo: 3.

Come hai detto tu hai molti controller e non hai bisogno di scrivere codice in ogni file, quindi stai usando beforeAction: Ma hai solo text_url relativo all'articolo per tutti i controller ??

$ model = Articolo :: model() -> findByAttributes (array ('text_url' => $ id));

===== aggiornati risposta ======

Ho cambiato questa funzione, controllare ora.

Se $ id non è nummeric, troveremo il suo id utilizzando il modello e imposteremo $ _GET ['id'], quindi nel controller successivo userà quell'id numerico.

protected function beforeAction($action) {   
     $id = Yii::app()->getRequest()->getQuery('id'); 
     if(!is_numeric($id)) // $id = how-to-make-pretty-urls 
     { 
      $model = Article::model()->findByAttributes(array('text_url' => $id)); 
      $_GET['id'] = $model->id ; 
     } 
     return parent::beforeAction($action); 
    } 
+0

No. Ho MOLTE azioni con il parametro $ id in un controller (_ArticleController_). Ora, queste azioni ottengono l'ID numerico come parametro ... Tutto ciò di cui ho bisogno è pre-elaborare questo id (da GET) e quindi eseguire l'azione con esso. –

+0

hai controllato la risposta aggiornata e la funzione beforeAction che ho aggiunto sopra? – VibhaJ

+0

Il codice delle azioni precedenti deve essere eseguito con un parametro $ id numerico! Quindi, per prima cosa dobbiamo "convertire" $ id dal formato slug in numerico (_load model by slug e return id_). Se usiamo: 'return parent :: beforeAction ($ action); l'azione verrà eseguita con il parametro $ id invariato. –

2

Mi dispiace, non l'ho letto tutto con attenzione, ma avete considerato utilizzando this extension?

+0

Se l'avessi vista prima, forse l'avrei scelta per il mio compito :) –

+0

non è mai troppo tardi. Conosco l'autore dell'estensione: dovresti "comprarlo" ;-) –