Jump to content

Can $pages->get() be used with a path with segments? Returns 404


Vigilante
 Share

Recommended Posts

I have segments turned on for the root/home page. This is because I'm doing some custom routing to remove a path from the URL.

One of the grandchild pages itself has segments turned on.

So when I'm doing my custom routing from the home page, I look to see if the URL is valid by using a standard get lookup on the segment string. Something like `$pages->get("/myroute/".$input->urlSegmentStr()."/");`

The problem is, the segment string may have a path that itself includes segments, like "/route/allows-segments/segment".

So get() returns nothing, essentially going to 404, because it can't find that path which has a segment in it.

Is there a way to make get() smart enough to see that even though /segment/ isn't found as a page, its parent /allows-segments/ has segments turned on and thus it can get that page instead?

I already programmed my workaround, it's not that big of a deal. I had to specifically test for the segmented URL though. Luckily I only have one page like this, but I can see it being an issue if I had a lot of them.

Perhaps get() needs some kind of options (or another finder function entirely) that can deal with paths with segments. Where it will process the path and check for segments, returning the proper page.

Link to comment
Share on other sites

16 hours ago, Vigilante said:

Perhaps get() needs some kind of options (or another finder function entirely) that can deal with paths with segments.

$pages->get("selector") is not designed to be a Swiss Army Knife of solving custom routing logic or similar for that matter.

16 hours ago, Vigilante said:

Where it will process the path and check for segments, returning the proper page.

I think such a need is to broad to be implemented without knowing the actual logic required for a particular use case, so I cannot see how it could be standardized.

  • Like 1
Link to comment
Share on other sites

On 3/21/2018 at 2:48 PM, szabesz said:

I think such a need is to broad to be implemented without knowing the actual logic required for a particular use case, so I cannot see how it could be standardized.

I don't think it's that broad or mysterious really.

Let's say I have a path as a string that came from somewhere or is auto generated, etc. Something like "/this/should/be/a/page". 

Now I just need to check if that's a valid URL or not. If I simply throw it in get() it will return 404 because it won't find that exact hierarchy in the page tree.

It would be a relatively simple thing for the code to knock off "page" and instead search for "/this/should/be/a/". And if that doesn't exist, look for "/this/should/be/" and then bingo. If "be" exists, PW checks to see if segments are turned on and if they are, check if segments are limited to certain strings. If not, then get() ultimately would return the "be" page.

Of course, all this should be optional. So the default get() would return 404 as it does now. But if you had something like `get("/this/should/be/a/page/", array("look_for_segments"=>true));` then get() would search and return a segmented page if that exists.

 

The bottom line is this, I'm looking for a page "this/should/be/a/page/" which is a totally valid URL ("be" has segments turned on). But instead PW tells me it's a 404 not found. That automatically says something isn't right here. I can't have PW telling me a URL is a 404, but if I actually GO to the URL, it works fine due to segments.

The PW routing system already knows how to handle URLs with segments, I'm just thinking that functions such as get() need to make use of that logic as well.

It doesn't even need to be get(), it could be an alternate function, perhaps gets() where the 's' stands for "segments" and it will return the page relating to a URL where segmented pages are searched for and not just precise page tree location.

Link to comment
Share on other sites

You're mixing up routing and $pages->get($path), which are totally unrelated. The Pages class is using the PageFinder to retrieve pages from the database. In no way is that operation concerned with url segments or any routing operations. Url segments are resolved as part of the ProcessPageView module, which is doing the initial matching of request url to an actual page in the database.

  • Like 3
Link to comment
Share on other sites

yep, and if you are doing any custom routing, you can write your own function to get the real page, my theme engine module includes a getVirtualPage() method that can find real pages based on conditions of the segment(s), which templates exist at each segment level, using name matching combined with template; this doesnt help if you are rendering real virtual pages like tag, category or archive filters, or feeds etc.

	/**
	 * Given an array of expected templates used at each segment index, return the page we are on
	 * @param  array  $segmentTpls [plain array of template names used for segments]
	 * @return [Page]
	 */
	public function getVirtualPage(array $segmentTpls) {
		$pages 		= wire('pages');
		$sanitizer 	= wire('sanitizer');
		$input 		= wire('input');
		$maxSegs	= count($segmentTpls);
		$segsCount	= count($input->urlSegments);

		if($segsCount > $maxSegs) return false;

		if($segsCount) {
			$lastSeg = $input->urlSegments[$segsCount];
			$segPlate = $segmentTpls[$segsCount - 1];
			$pageName = $sanitizer->pageName($lastSeg);

			$vPage = $pages->get("template=$segPlate, name=$pageName");
			return $vPage;
		}
	}

 

  • Like 3
Link to comment
Share on other sites

It's not that I'm doing "custom routing", it's that I want to return the correct page that handles a particular URL.

If I have "/some/page/here" and I "look it up" with whatever function might exist, it should return "/some/page/" if that is the correct page that handles that particular URL (because segments are on).

I'm not trying to do custom routing here, I'm trying to lookup the correct page that handles a given URL.

 

I'm only talking about routing because the PW router obviously already uses/has this logic. It knows the correct page to open for a given URL. I'm simply looking for similar function in the API that works like get(). I pass in a path and it returns the page that handles it. For some reason I thought this would be a pretty common thing to want to do, unless very few people make use of segments?

Link to comment
Share on other sites

2 hours ago, Vigilante said:

It's not that I'm doing "custom routing", it's that I want to return the correct page that handles a particular URL.

you can just pass the path of the page that handles the segments; if you are on the page, then $page is what you want.

2 hours ago, Vigilante said:

If I have "/some/page/here" and I "look it up" with whatever function might exist, it should return "/some/page/" if that is the correct page that handles that particular URL (because segments are on).

how can the system know which part of the URL is the segment? The whole point of URL segments is that they are not real pages, so there is no way to "look them up".

  • Like 1
Link to comment
Share on other sites

8 hours ago, Vigilante said:

I'm simply looking for similar function in the API that works like get(). I pass in a path and it returns the page that handles it. For some reason I thought this would be a pretty common thing to want to do, unless very few people make use of segments?

All the logic you're talking about here is already there that's true, but it's quite inacceasable in the ProcessPageView class. 

Link to comment
Share on other sites

17 hours ago, Macrura said:

you can just pass the path of the page that handles the segments; if you are on the page, then $page is what you want.

Yes, if I build the logic myself to parse a given URL string and figure out which part of the path goes to the segmented page. I just thought a function like this might have already existed.

 

17 hours ago, Macrura said:

how can the system know which part of the URL is the segment? The whole point of URL segments is that they are not real pages, so there is no way to "look them up".

The logic would handle that. If "this/is/long/url" is a 404, then it looks for "this/is/long" and if that's a 404 then it looks for "this/is" and if it finds a page here, it would then check to see if segments are on. Then if so, it would return "this/is" as a page object. If segments are not on for that page (or accepted segment strings are defined and my string doesn't match them) then it would also return a 404 and give up.

Obviously this kind of recursive checking would be more costly in processing so that's why a dedicated function or a switch would turn it on only when necessary.

Link to comment
Share on other sites

The method @LostKobrakai mentions above gives you a clue about how you can make a simple function for the purpose...

// Get the page from a path which might include URL segments
function getPage($path) {
    $page = wire('pages')->get("path=$path");
    if($page->id) return $page; // If the path matches a page return that
    $pieces = explode('/', $path); // Break the path into pieces
    while(!$page->id) { // Until a page is matched...
        array_pop($pieces); // Pop off the last piece (a URL segment)
        $path = implode('/', $pieces); // Make a path from the remaining pieces
        $page = wire('pages')->get("path=$path"); // Try and get a page at that path
    }
    return $page; // Return a matching page or a NullPage if no match
}

If you wanted to get the URL segments from the path it would be easy to modify the function to return those also.

  • Like 3
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...