Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Sign In with Google Sign In with OpenID

maximum levels of urlpath

edited December 2012 in Framework

Hi,

i have a question concerning the controller and routing. I'm trying to built a website for an acoustic engeneer. The page is bilingual and one navigation item deals with references of his work. The path to a specific reference should look like this: /en/references/small-studios/name_of_a_studio or /en/references/cinemas/name_of_a_cinema But the routing is ignoring everything beyond the third level and handles the path as /en/references/small-studios/ or /en/references/cinemas/

Is there a way to handle more then 3 levels?

Best Regards betaman

«13

Comments

  • edited December 2012

    That's strange. I created a test handler at apps/test/handlers/one/two/three/four.php with the following:

    <?php
    
    $page->layout = false;
    
    info ($this->params);
    
    ?>
    

    Calling it at the URL http://www.elefant.lo/test/one/two/three/four/five/six/seven produced the following output:

    Array
    (
        [0] => five
        [1] => six
        [2] => seven
    )
    

    To make sure the language negotiation wasn't affecting it, I set negotiation_method = url in conf/config.php and tested it at the URL http://www.elefant.lo/en/test/one/two/three/four/five/six/seven and the output was the same.

    Edit: I should add that www.elefant.lo is an alias in my /etc/hosts that points to a local virtualhost :)

  • Hi Johnny,

    the problem occurs when I used the navigation admin menu. That's probably the problem. Here are some screeners to illustrate it:

    http://download.die-symbionten.de/elefant/nav_levels_1.jpg

    http://download.die-symbionten.de/elefant/nav_levels_2.jpg

    Check the adressbar in the second screenshot, it doesn't fit the page..

    Do I have to specify a custom handling for this sowhere?

    I saw that there is such a thing as customhandlers in the blogs config file:

    [Custom Handlers]
    
    ; You can override some of the built-in handlers with your own
    ; by changing them here. You can also disable any of them by setting
    ; them to Off.
    
    blog/index = blog/index
    
  • I think you just uncovered a bug:

    https://github.com/jbroadway/elefant/commit/bdd3a817d10d182fcbc1ca2825f6ad64a04bb732

    Elefant doesn't nest pages in the URL, so to access the Services page, you would just use /services and not /about/consulting/services. The page ID it should have used in nav_levels_2.jpg was about, but the bug you found caused it to use the second element instead, since it wasn't expecting the URL to be nested that way.

    If you would rather have it chose the last element as the page ID so you could have nested URLs like that, you could duplicate apps/admin/handlers/page.php to another handler and change the default_handler setting in conf/config.php to your new handler, then just change line 11 of the file to this:

    $id = count ($this->params) ? $this->params[count ($this->params) - 1] : 'index';
    

    That will cause the URL /about/consulting/services to show the Services page.

  • Hi Johnny,

    thanks for the help. Just one question to completly understand: This is only affecting the default_handler If i call a url with a defined handler, the parameters will be used as usual, is that right?

    Personally I prefer using the last parameter, because of talking urls and I think it's a better match to the navigation admin page..

    I will gist some nav suggestions for:

    • link to a page considering the path from the navigation.json

    • add an active class to menu Items who have a child which is the current page

    Have a nice new year

    betaman

  • You're correct that this only affects the default_handler.

    One issue that I'm not sure the best way to handle with nested URLs is this: If a page has a nested URL like /about/consulting/services, what happens when a parent page changes its ID, for example about becoming about-us? The path would presumably become /about-us/consulting/services, which means a single page ID change could break the links of several other pages, instead of just its own.

    If we decided not to modify the child page links when a parent ID changes, then a visitor might assume that /about/consulting and /about are valid links too, but while the first would still work, the second would now be a broken link.

  • If I change an ID the navigation.json seems to be updated. So we are save if we consruct the links from the json. What will be a problem if someone hardcodes a link to some file and the path changed, but i guess there is no solution for this...

    I started something, but its not finished yet, but you will see where its going... https://gist.github.com/4420336

  • Thinking about how fragile this makes URLs, since one page's ID change would change every page underneath it, I'm not sure it's a great idea. The navigation structure is a tree you can use to make site maps, sections, breadcrumbs, etc already, but I'm not a fan of changing the URLs to include its full path due to this side-effect.

    Each page being just a /my-page-id leaves you with enough control over the URL of every page (up to 72 characters for each page ID) without one page affecting others. So I'm not convinced the pros of using nested URLs are worth it.

  • Hey Johnny, this is not as fragile as it would seem at first glance..

    Check out my page and play around with the navs or change the page-ids:

    http://elefantcms.die-symbionten.de/

    I messaged you the credentials in this forum...

    Notice the highlighting of the top Nav and the completly wrong link..

    Cheers betaman

  • Perhaps we could make this a setting in the global config for how it builds page URLs, something like:

    ; Determines whether page URLs all appear as top-level
    ; links, or as nested URLs under their parent page IDs.
    ; Default is flat.
    
    page_url_style = flat ; ex: /flowbee-videos
    ;page_url_style = nested ; ex: /products/flowbee/videos
    

    Then in admin/page it would check the setting and switch which element from $this->params it choses:

    $id = count ($this->params)
        ? $this->params[
                (conf ('General', 'page_url_style') === 'flat')
                    ? 0
                    : count ($this->params) - 1
            ]
        : 'index';
    

    And in the navigation/* handlers, it could read that same setting and render the URLs accordingly.

  • Sounds great. I'll prepare something, atm i have to integrate i18n properly. I believe the original navugation/top has to be tweaked as well, cause it Shows All the languages Homepages when you implement it the way you suggest in the Multilanguage tutorial. I'll let you know when I got something to show..

  • I was wondering: Do you like it, or do you tolerate it? cause if you don't like it I can keep it as an app, like I did Implement it atm And its kept out of the core...

  • Mainly I'm just cautious when it comes to changing or adding core features, because they have the biggest chance of causing side effects or slowing things down. Before adding new features, if you want to keep a project from growing into a mess over time, you have to play devil's advocate and really challenge them from all angles :)

    In this case the default behaviour is the same, so there should be no side effects that I can see, and it adds only one ternary operation, a call to conf(), and a call to count() only if the setting is not the default. And since the navigation handlers are cached, the extra work generating the nested URLs is pretty negligible too. So it shouldn't really affect overall speed.

    For my own sites, I would probably stick with the default just because I'm lazy ;) But I know many people want more control over their URLs, so we should make it available as an option for those that do.

  • Ok, great! I'm glad it stood the lazy devils advocates challenge :-)

  • Did you know why my head is cut off at the top on my profile picture:

    flowbee

  • Hi johnny,

    I added navigation/top and navigation/section to my newest fork of elefant: https://github.com/betaman/elefant/commit/299b1ed7a2e5a1794236d038bf456cf0b6ca2a13

    Can you please check if that's the way to go. If so I would add the breadcrump and sitemap handlers as well.

    There is one thing I don't know how to solve: Its a problem with the negotiation_method = http Its working fine as long as you dont enter the admin area. When you enter the admin area to edit a page the language Prefix in the URL is lost once you return to the page. And you see the english Navigation, although you are on a german site. This has nothing to do with my new implementation, the problem was there before. Do you have any Ideas?

    Here is a link to my testPage: http://elefantcms.die-symbionten.de/de/index-de

    I guess you still got the credentials..

    Cheers Jens

  • Thinking about it, I don't really liki it, that I have so many ifs in the handlers, although the conf general and the conf I18n probably will never change. It would be nice if there was a way to check this once, and then use the respective handler (eg navigation/top or navigation/top_url) throughout the rest of thr time surfing.

    Like a function that upon first call returns a function with all ther init stuff done...

    But I don't know how to do that in PHP

  • Haven't had a chance to look too closely, but wanted to mention a couple things that may help:

    When the negotiation method is set to 'http' then Elefant is supposed to use the HTTP Accept-Language header to determine which language to show. It's only when it's set to 'url' that Elefant cares about the /lang/ prefix in the URL. So if you're using the URL prefix, then that setting should be set to 'url'.

    And for reducing the complexity of the handler, you could look at splitting it into multiple handlers and have the main navigation/top call the appropriate one using echo $this->run(). To see whether a handler has been called before, and only load initializations on the first call, you can also do this:

    if (! isset (self::$called['navigation/top'])) {
        // load initializations
    }
    

    You can see this in action in the social/twitter/follow handler that shares social/twitter/init with the other twitter handlers and makes sure it's only loaded once.

    I should probably replace social/twitter/init with a call to $page->add_script() instead, since multiple calls will only load the script once, but it still serves to show how this could work for you :)

  • Ok, thats my latest try. Check it out when you are in the mood.. https://github.com/betaman/elefant/commit/92fd584460ed2b20c111001a104c13aa8171a9b6

    Cheers Betaman

  • thanks for the hints by the way, the socual/twitter/init is not what I meant. Its more something like that. http://jsfiddle.net/RKRFp/

    But in the aproach above I dont need that init thing anymore..

  • Ack, hoped to have time today but I've been preparing for a demo I'm putting on in 10 min... Wish me luck!

    Tomorrow's my day off, so after I catch up on sleep I'll be on it! :)

  • Good Luck with your demo, and take it easy...

  • Got a fresh clone of your repo installed and checking this out now.

    One thing I'm hesitant about is removing the caching, so I'm wondering if we can't find a solution that works with it, like caching the top menu for each language separately if negotiation_method = url. The navigation_clear_cache() function could delete '_navigation_top' and also loop through the $i18n->languages list to call $cache->delete ('_navigation_top_' . $lang); on each language.

    And for adding class="active" to parents of class="current" in navigation/section, that could also be done with one line of JS, although that's not an ideal compromise:

    $('.current').parents ('li').addClass ('active');
    

    Anyway, still setting up a site structure to test this some more. I knocked my mouse off the desk this morning and broke it... I forgot how slow I am with the laptop touchpad, haha

  • Hi Johnny,

    How did your Demo run? the JavaScript idea is pretty good, but it only works if the current li item is in the dom. If the li is in a deeper level it won't work :-(

    I stumbled across another issue. I made comments in the latest commit. The problem is, that the homepage is on multilingual pages one level above the pages which are actually it's siblings.

  • I think you forgot to push your latest commit ;)

  • edited February 2013

    I had that cached version for each language navigation/Top and it worked, I had a replacing function, for the current class which took both id an lang into considaration, which worked as well. But the active got to complicated. I could probably run this replacement on each id which is identified by the navigation_has_active_child. But the question is when the replacing will be more effortful as recreating it.

  • Ill try sth out i'll replace the items we got in the REQUEST_URI similar like u did it with the page-> id, this might work without touching the navigation class

  • I see what you mean, since determining which li to add the class to in a string is not straight-forward. There's no parents() equivalent in a regex, sadly... ;)

    It seems like everything else can be done simply and efficiently (and sorry, I was looking at the wrong file in my earlier comment about navigation/top), but adding the active to the parents is really the only thing that complicates it in navigation/section. With caching, you'll need a cache for each page id/language combo, and without caching, it means loading navigation.json and generating the menu for each request, neither of which is a great option.

    I think simplicity may be a good reason to keep the class="current" on the server-side, but to move the class="active" to the client. We can just add a bit of JavaScript via $this->add_script() in navigation/section then that would keep things fast and simpler on the server.

    If it wrapped this in a $.parents_active() function, then it could be called again if the DOM is updated, or via setInterval(), so even if you dynamically change which li has class="current", then calling $.parents_active() again could reset which li elements have class="active".

  • edited February 2013

    The active wrapper is cool.

Sign In or Register to comment.