Jump to content
Larry Ullman's Book Forums

Please Explain Routing Rules Precisely !


Ziggi
 Share

Recommended Posts

Hey Yii guys - please, explain your ideas precisely!

 

For whatever reason Yii routing rules are not well covered.

 

Can you explain exactly what the following rule if for:

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

 

 

And can you explain this one:

'<view:\w+>' => 'site/page'

 

What is this going to do actually - step by step???

 

Can you provide some exhaustive list of possible markups?

 

The routing rules explainations available are completely minimalistic - where are routing rules explained in a more comprehensive manner??? Can your help, please!

Link to comment
Share on other sites

First of all, there really are no "Yii guys" here. If you want "Yii guys", I'd use the Yii site's forums. I will, however, be covering routes in detail in "The Yii Book".

 

Other than that, I can't tell if you're just expressing frustration with the lack of good documentation about this particular subject or if you actually need answers to questions (other than "provide exhaustive list of possible markups", which isn't practical).

  • Upvote 2
Link to comment
Share on other sites

Hi Larry,

 

Actually, it was a little bit of frustration. Simply speaking - routing rules are confusing and available explanations not comprehensive.

 

As I already bought your "Yii Book" a few days ago - I tried to find some info right there and... nope. Very little clues on the subject for the time being.

 

My problem has started with hangling static pages in Yii.

 

As you know, default site controller handle static pages through statically assigning "page" action to CViewAction class. This class render a view file residing in "site/page" folder and the name of the file is provided as query string: http://mydomain/index.php?r=site/page&view=FileName.

 

Well - I am unable to find a good routing rule what would convert such an URL into something more SEO friendly like: http://mydomain/site/page/FileName. No way - nothing works!

 

OK - there are some solutions descripted on Yii forums but they all require to manually specify routing rule for each and every static page on the website. This is nonsense.

 

So, finally I found a workaround, but I am unsure is it an "elegant" one:

 

Simply speaking, I consider static pages are pages what are actually served "as they are" - so no specific controller action is necessary to to serve them. Consequently - they can be served by the "missingAction" handler. So I have decided to create a new StaticController like this:

 

class StaticController extends Controller
{

   public function missingAction($actionID)
  {
    if(file_exists($this->getViewPath() . '/' . $actionID . '.php')){
	    $this->render($actionID);
    }else{
	    throw new CHttpException(404, 'Page not found!');
    }
   }

}

 

And this controller can serve any view file residing in "/static" folder by its name. If given page is not found - proper exception is thrown. Consequently - there is no need to update anything while new static page is added. This is working nice but the only problem is... Menu item is not highlighted with given static page is displayed... Perhaps you can provide better solution?

 

Best regards,

Ziggi

Link to comment
Share on other sites

There are some things covered on getting url's to look nice in the Yii book, in your main.php file in the config folder change to the code urlManager code to that of below in the return array. This will tidy things up for you.

 

'urlManager'=>array(
  'showScriptName'=>false,
  'urlFormat'=>'path',
  'rules'=>array(
   '<controller:\w+>/<id:\d+>'=>'<controller>/view',
   '<controller:\w+>/<action:\w+>/<id:\d+>'=>'<controller>/<action>',
   '<controller:\w+>/<action:\w+>'=>'<controller>/<action>',
  ),
 ),

 

Also make sure you have a .htaccess file in your index.php folder which should have the contents as follows:

(Of course your mod rewrite engine must be on in order for the rewrite rules to work.

 

<ifModule mod_rewrite.c>
# Turn on the engine:
RewriteEngine on
# Do not perform redirects for files and directories that exist:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# For everything else, redirect to index.php:
RewriteRule . index.php
</ifModule>

Link to comment
Share on other sites

Dear Mr Edward,

 

Please notice - I already know resources you've mentioned. Such general advisory is pointless. If I knew how to do the task based on this information I would not bother you with my questions.

 

If you know the solution - please share. If not...

 

Rgs,

Ziggi

Link to comment
Share on other sites

Sorry,

 

I do not even see where I was unpolite. Is "hi, Yii guys" unpolite? Can you tell me exactly what my phrase was so unpolite actually?

And I do not understand what is the value of Edward's "advisory" not really more helpful than "Google it!".

 

IMHO - what is this forum for? What is Larry's book for? Is it for people who already know Yii by heart? For renown Yii experts? Nope - this is for the people like me - who just started with this framework and have many issues. And if I tell you given subject is unclear - that means it is - it least for beginners.

 

Think a little bit: if Larry is asking the readers of his book for "helpful opinions" - does he expect advices like "here you are a link to a website about proper English - go there and figure out on your own" - can you cope?

 

This is not very friendly at all !

I repeat - If I were able to "figure it out" based on the link provided - I would not bother you asking.

 

Rgs,

Ziggi

Link to comment
Share on other sites

You may try defending yourself by hypothetical questions all you want. I'm not buying it. It's not single phrases that is the problem here. The problem is that you demand an explanation to an undefined problem, and you don't even do that politely. Why should anyone invest time solving a problem for you considering that?

 

Next, you did not even provide that link yourself, referring to what you may have tried. I would deem that as an obvious attempt at helping, even though you don't recognize it. This is an attitude problem...

 

This is a book covering 22 books, with YII as the newest addition. Obviously, this is not the place looking for people that know YII by heart. Another reason to ask politely, as some of does people might understand the documentation while not knowing this beforehand.

 

You harvest as you sow.

 

Edit: Ok. I think you get the point. Here's several ways to implement the rules you want.

 

1.) Write a class extending CBaseUrlRule that implements these rules you want. Use this rule object in the controllers where you want this behavior. This is more elegant as the object will encapsulate the rules needed.

2.) Write an abstract controller holding these rules. All implementing controllers extends from this one instead.

3.) Alter the main CBaseURLRule class. Not recommended.

4.) Implement the same ActionMissiong method, but do it in an abstract controller, or even add it to the main YII controller.

 

Ask if you need more help, but please ask nicely. I don't care if you think you already do. You are not perceived that way.

Link to comment
Share on other sites

>> you demand an explanation to an undefined problem...

 

My entire post #3 in this thread is defining the problem very precisely, I even tried to explain my "workaround".

If this is not enough than I do not know what can be more comprehensive...

 

Sorry - I completely do not understand this sentence of yours:

 

"This is a book covering 22 books, with YII as the newest addition."

 

What do you mean? What 22 books you are talking about? I do not cope at all.

Link to comment
Share on other sites

And last but not least - you may try Googling yourself: try please this phrase:

 

yii clean url static pages

 

You may find many results and no working solution actually. At least not working as it should: like this one:

 

http://learnyiiframework.blogspot.com/2012/07/creating-url-rules-for-static-pages-in.html

 

So - IMHO - this is not that obvious.

 

Rgs,

Ziggi

Link to comment
Share on other sites

It should be "This is a forum". You should be able to comprehend that, but ok.

 

And last but not least - you may try Googling yourself: try please this phrase:

 

That pretty much sums up why you are acting like a total douche bag. Why should we do the job for you? We can sure try help you find a solution, but don't demand it on a silver platter. Get some manners, please...

 

I have provided you a couple of possible solutions. Hope those helps.

Link to comment
Share on other sites

For the time being you were so kind to provide me one worthy feedback - when I asked about user folders...

 

But not this time. Actually I start to believe you simply miss my point and try to guide me to answer not really matching my problem. So, I continue developing my "workaround" extending CMenu to highlite active menu items pointing to static pages. Perhaps this is not the best solution, perhaps I turned the wrong way but I will not beg you on my knees... Sorry if you really found my attitude wrong but this is more about personal choices. If I know the answer - I give the solution in plain language. I do not pretend a "professor" like you do.

Link to comment
Share on other sites

Ziggi, sometimes when we try to help people on this forum, we don't get it right the first time.

Quite often, the reason someone is asking a question and the reason they don't understand something is not very clear to us. We don't intentionally try to not answer someone's question.

Antonio and Edward were both doing the best they could to help you. The fact that they (unintentionally) missed the mark and didn't give you the answer you wanted right away is no reason to act the way you did.

 

A more civil approach would have been to reanalyze your original post(s), think about why Antonio and Edward perhaps weren't able to answer your question, and then politely reprhase your question to hopefully reach a reasonable solution eventually. I guarantee that if you had been polite about it, both Antonio and Edward would have been more than happy to continue helping you until you got the answer you were looking for.

 

It seems like you're not a native English speaker, so perhaps the source of the arguments was all just a simple misunderstanding on both sides, but at this point, you really have no hope of ever getting any more relevant information to your question. And more than likely, you've ruined any chances you have of ever getting any help on this forum again. Both Antonio and Edward are the two most active and knowledgeable posters on the Yii forum here, so you're probably SOL.

 

I think you have one of two choices:

 

1) Apologize for your previous posts, and with time, I think tempers will cool down and we can get back to having civil discussions and everyone can get answers to questions and be happy. Please note that I am not asking you to beg on your knees, but at this point, I think a sincere apology would be nice.

 

2) Don't post on this forum anymore and consider this a lesson learned for future interactions on forums.

 

The choice is yours. I also had to swallow my pride recently and apologize for stepping over the line on this forum, and even though it didn't feel good at the time, I'm glad I did apologize and everyone was able to go back to being civil and helping out again. I'd recommend the same for you.

  • Upvote 3
Link to comment
Share on other sites

To clearify, this is what you want? Specify if I'm missing your point

1. You want to have "static files", not really related to any controller, located in the folder /static?

2. You need this implementation to work with a CMenu object, as you need to highlight URLs that should be considered static?

 

Another way to do this would be to:

- Define a ignore rule in your .htaccess file. Specify that calls to the "static" folder should not be routed by YII.

- The CMenu is more tricky. I think this can be solved very simple. You define a CMenu trough Items, right? This is what the manual says:

 

linkOptions: array, optional, additional HTML attributes to be rendered for the link or span tag of the menu item.

 

You could provide a CSS class here, like "static". You'd then be able to style static items differently. If this solution is to manual, my first (tricky) approach might work:

 

Look inside CMenu. It has a method call normalizeItems. It takes the items specified when calling CMenu, and work with them. This is how the logic for active items is done:

if(!isset($item['active']))
{
  if($this->activateParents && $hasActiveChild || $this->activateItems && $this->isItemActive($item,$route))
      $active=$items[$i]['active']=true;
  else
      $items[$i]['active']=false;
}
else if($item['active'])
  $active=true;

The important test is CMenu::isItemActive(). You could write a similar test like isItemStatic() and set each item to conforming to the rule with:

$items[$i]['static'] = true;

 

- The next step is CMenu::renderMenuRecursive(). You can see a boolean check for "active" here. It looks like this and ads the $activeCssClass (swap with staticCssClass) to item[n]:

if($item['active'] && $this->activeCssClass!='')
  $class[]=$this->activeCssClass;

  • Upvote 1
Link to comment
Share on other sites

@HartleySan

 

I can agree my INITIAL post was dictated by frustration after spending hours trying to fit information collected from Yii wiki and Larry's book to my problem. And as soon as Larry answered - I tried to explain my problem in a very precise manner.

 

This is why I found Edwards' post so confusing - it was like "hi man but.... did you check you have a power plugged on?" - this sort of feedback is acting like red scarf on a bully. Honestly speaking - now I seriously doubt Edward really ever read my post #3. Most probably he just passed his eyes over my initial post and provided very routine, obvious and... pointless answer.

 

@All

 

Well - I am not on the position to make enemies on discussion fora. This is not a good way. If I offenced someone or even hurt - I feel sory. The only excuse I may have is that I found Edward's feedback so... laying me off.

 

I do not know is this enough for the group but I repeat - I always try to be friendly. If incidentally I know an answer - I provide a clear feedback without unnecessary disputes. I do not complain that I "open my cards against a person who did not even try to find the answer through reading books or spending hours on documentation". This is not my point to judge why the question was asked. If I would not want to be helpful I simply did not bother to read someone's posts...

 

So please - do not think I am a nasty bug as I am not. I apologize once more - sure I could be more modest - that is right. I hope you can accept it.

 

Rgs,

Ziggi

Link to comment
Share on other sites

@Antonio

 

Thank you for attempting to help me. Sorry again for too much disputing. But we are just nomal people - we should not keep anger in heart. I apologise you and Edward. Please forgive.

 

I need some time to think about your feedback on static pages. For the time being I was thinking about setting a menu item 'active' through passing missingActionID to extended CMenu and comparing it with menu routing. If missingActionID == url then set menuitem active...

Link to comment
Share on other sites

And last but not least - you may try Googling yourself: try please this phrase:

 

yii clean url static pages

 

You may find many results and no working solution actually. At least not working as it should: like this one:

 

http://learnyiiframe...c-pages-in.html

 

So - IMHO - this is not that obvious.

 

Rgs,

Ziggi

 

The information from the linked page you have there was copied from the Yii 1.1 Application Development Cookbook (Alexander Makarov). I think Alexander may be part of the Yii Development team, correct me if i am wrong? It was the solution i was just testing for static pages.

 

I added a new controller to my protected/controllers folder

 

<?php
class WebsiteController extends CController
{
public function actionPage1($alias)
{
 echo "Page is $alias.";
}

public function actionPage2($alias)
{
 echo "Page is $alias.";
}

public function actionPage3($alias)
{
 echo "Page is $alias.";
}
}

 

You can see in the code i have actions for the static pages which i would need page1, page2 and page3.

 

I was then required to add the new rewrite rules below for the 3 static pages.

 

'urlManager'=>array(
  'showScriptName'=>false,
  'urlFormat'=>'path',
  'rules'=>array(
   '<alias:page1>' => 'website/page1',
   '<alias:page2>' => 'website/page2',
   '<alias:page3>' => 'website/page3',
   '<controller:\w+>/<id:\d+>'=>'<controller>/view',
   '<controller:\w+>/<action:\w+>/<id:\d+>'=>'<controller>/<action>',
   '<controller:\w+>/<action:\w+>'=>'<controller>/<action>',
  ),
 ),

 

This works for urls /page1, /page2, /page3

Link to comment
Share on other sites

Edward,

 

Of course Sasha Makarov is right!

 

But this is not the solution I am looking for !!!

Please - try to understand that in my humble opinion adding:

'<alias:page1>' => 'website/page1',
'<alias:page2>' => 'website/page2',
'<alias:page3>' => 'website/page3',

 

to routing rules, as well as adding:

 

public function actionPage1($alias)
{
echo "Page is $alias.";
}

public function actionPage2($alias)
{
echo "Page is $alias.";
}

public function actionPage3($alias)
{
echo "Page is $alias.";
}

 

in case of each and every new static page added to a website is a COMPLETE DISASTER !!!

 

Simply speaking - this is the most nasty way I could ever imagine to handle static pages!

Having static pages organized like that it is impossible to add new ad-hoc menuitems programatically.

 

I am looking for a clean generic solution:

 

- one routing rule

- one controller

- clean URLs

 

for ALL static pages. - Can you cope now???

 

Best regards,

Ziggi

Link to comment
Share on other sites

OK,

 

Here you are my "generic solution v. 1.0" :

 

Assumption:

All static pages are residing in a single folder: protected/views/static. No pages in subdirectories!

 

 

We use UrlManager normally to serve clean URLs:

'urlManager'=>array(
'showScriptName'=>false,
'urlFormat'=>'path',
'rules'=>array(
'<controller:\w+>/<id:\d+>'=>'<controller>/view',
'<controller:\w+>/<action:\w+>/<id:\d+>'=>'<controller>/<action>',
'<controller:\w+>/<action:\w+>'=>'<controller>/<action>',
),
),

 

as well as .htaccess:

 

<ifModule mod_rewrite.c>
# Turn on the engine:
RewriteEngine on
# Do not perform redirects for files and directories that exist:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# For everything else, redirect to index.php:
RewriteRule . index.php
</ifModule>

 

Then we create a 'StaticControler.php':

 

<?php

class StaticController extends Controller
{
private $akcja;

private function setAkcja($akcja)
{
 $this->akcja = $akcja;
}

public function getAkcja()
{
 return $this->akcja;
}

/**
 * This is the action to render static files as missing actions.
 */
public function missingAction($akcja){
 $this->setAkcja($akcja);
 $views = $this->getViewPath();
 if(file_exists($views . "/" . $akcja . ".php")){
	 $this->render($akcja);
 }else{
	 throw new CHttpException(404,'Page not found!');
 }
}

}

as well as a new component 'XMenu.php':

 


<?php

Yii::import('zii.widgets.CMenu');

class XMenu extends CMenu
{

protected function getStaticPage()
{
 $ctrl = $this->getController();

 if($ctrl->id == 'static'){
	 return $ctrl->getAkcja();
 }else{
	 return '/';
 }
}

protected function isItemActive($item, $route)
{

 if($route == 'static')
 {
	 $akcja = (explode('/', $item[url][0]));
	 if($akcja[2] == $this->getStaticPage())
	 {
		 return true;
	 }
 }

 return parent::isItemActive($item,$route);

}
}

 

Then we generate a menu like this:

 

<div id="mainmenu">
<?php $this->widget('XMenu',array(
'items'=>array(
array('label'=>'Home', 'url'=>array('/site/index')),
array('label'=>'About', 'url'=>array('/static/about'), 'url'=>array('/static/about')),
array('label'=>'License', 'url'=>array('/static/license'), 'url'=>array('/static/license')),
array('label'=>'Contact', 'url'=>array('/site/contact')),
array('label'=>'Login', 'url'=>array('/site/login'), 'visible'=>Yii::app()->user->isGuest),
array('label'=>'Logout ('.Yii::app()->user->name.')', 'url'=>array('/site/logout'), 'visible'=>!Yii::app()->user->isGuest)
),
)); ?>
</div><!-- mainmenu -->

 

 

You may see all is working as expected - you put a view file into the 'static' folder, you add a position into a menu in a regular manner and bingo - new static page is served with a clean URL and menu items are highlited flawlessly. No more nasty routing rules, no more countless controller actions. Perhaps there are more clever solutions - you are welcome to share!

 

Rgs,

Ziggi

  • Upvote 1
Link to comment
Share on other sites

@Edward

 

Between simple "add static page" and full-featured CMS a huge gap exists - please, do not overestimate my capabilities :-)

 

But very often I have demand from customers to let them manage static pages by their own - sort of minimalistic approach they use for special communication, promotions, extra bit of information - something what was unexpected and unpredictable but does not require special sophistication. Presuming they have the application layout template - they can assemble simple static pages themselves - even in WordPad, drop them into 'static' folder and - wow! - they can immediately link these pages in their e-mails as they are served within the application scope readily!

 

And on top of that - I strongly believe from aestetical point of view and code reusability - my solution seems to be simply more clean...

 

But of course - if you know how to achive the same using some "magical' routing rules I am not aware of - as I confirm - I do not understand all these rules well enough - you can share. No offence!

 

@HartleySan

 

Sure - thank you for your very kind moderation! I really appreciate!

Link to comment
Share on other sites

Glad you solved it! :)

 

Was not my point to go all professor on you. Nice to offer an apology. I'm sorry too. No hard feelings.

 

I think this is a pretty clean and good solution after all. I'm sure you could solve this even more elegant than this, but for such a specialized case, I think it's very good.

 

If you want to improve it, I would look into splitting some methods and adding a constant. Very small alterations, but the code is easier to follow now. You could also look into improving the controller ever so slightly. No need for the private staticController::setAkja for example. (As an object can use their own private properties)

 

<?php

Yii::import('zii.widgets.CMenu');

class XMenu extends CMenu
{

   const STATIC_LABEL = "static";

   protected function getStaticPage()
   {
       $ctrl = $this->getController();

       if($ctrl->id == self::STATIC_LABEL){
           return $ctrl->getAkcja();
       }else{
           return '/';
       }
   }

   protected function isItemActive($item, $route)
   {
       // Check for static item
       if ( $this->isItemStatic($item, $route) ) { return true; }

       return parent::isItemActive($item,$route);
   }

   private function isItemStatic($item, $route)
   {
       // Make sure route is static
       if ( $route != self::STATIC_LABEL) {
           return false;    
       }

       // Split route to parts
       $akcja = (explode('/', $item['url'][0]));
       // Make sure part three exists, then compare
       if ( ! empty($akcja[2]) ) {
           return ($akcja[2] == $this->getStaticPage());
       }

       // Item is not static
       return false;
   }

}
?>

 

I have not tested the code above, so it depends on your own code working as expected. I added small checks to make sure $akja[2] exists, etc.

 

If you should ever need to implement subdirectories here, look into the method renderMenuRecursive(). You'll understand quite quickly how it is solved.

Link to comment
Share on other sites

Antionio,

 

I really apreciate - good lesson in OOP coding style!

 

BTW - if you just know - would yu be so kind to let me know how to call CAccessControlFilter in an explicit manner?

Simply speaking, I wanted to implement some basic accessRule chcecking for static pages (not RBAC) so, to resolve user access right to given action I need to use its methods... Frankly speaking - this is always confusing... is there some 'magic skill' necessary to read documentation in a purpose to guess how to call given class within an application scope?

Link to comment
Share on other sites

 Share

×
×
  • Create New...