Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added method getByPath to post model #363

Open
wants to merge 10 commits into
base: 3.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
133 changes: 133 additions & 0 deletions src/Concerns/GetByPath.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
<?php

namespace Corcel\Concerns;

/**
* Trait GetByPath
*
* @package Corcel\Traits
* @author João Henrique S. Mendonça <joao.mendonca@pdmfc.com>
*/
trait GetByPath
{
/**
* Retrieves a post (usually pages) given its path.
*
* @param string $pagePath Page path.
* @param string|array $postType Optional. Post type or array of post types. Default 'page'.
* @return \Corcel\Model\Post|null \Corcel\Model\Post on success, or null on failure.
*/
public static function getByPath($pagePath, $postType = 'page')
{
$inString = self::sanitizePathToSql($pagePath);
$postTypeInString = self::sanitizeTypesToSql($postType);
$sql = "post_name IN ($inString) AND post_type IN ($postTypeInString)";

$pages = self::whereRaw($sql)->get()->keyBy('ID');

$reverseParts = self::reversePathParts($pagePath);

$foundId = self::searchIdInPath($pages, $reverseParts, $postType);

if ($foundId) {
return $pages[$foundId];
}
}

/**
* Returns a sql string with the sanitized and exploded path
*
* @param string $path
* @return string
*/
private static function sanitizePathToSql($path)
{
$parts = self::getPathParts($path);
$escapedParts = array_map('str_slug', $parts);

return "'" . implode("','", $escapedParts) . "'";
}

/**
* Returns an array of decoded path parts
*
* @param $path
* @return array
*/
private static function getPathParts($path)
{
$pagePath = rawurlencode(urldecode($path));
$pagePath = str_replace('%2F', '/', $pagePath);
$pagePath = str_replace('%20', ' ', $pagePath);
return explode('/', trim($pagePath, '/'));
}

/**
* Returns an array of reversed path parts
*
* @param $path
* @return array
*/
private static function reversePathParts($path)
{
return array_reverse(self::getPathParts($path));
}

/**
* Returns a sql string with the sanitized and exploded types
*
* @param string|array $type
* @return string
*/
private static function sanitizeTypesToSql($type)
{
if (is_array($type)) {
$postTypes = $type;
} else {
$postTypes = array($type, 'attachment');
}

$postTypes = array_map('str_slug', $postTypes);
return "'" . implode("','", $postTypes) . "'";
}

/**
* Loops through a collection of pages (or posts) looking for the id of the child
*
* @param $pages
* @param $reverseParts
* @param $postType
* @return int
*/
private static function searchIdInPath($pages, $reverseParts, $postType)
{
$foundId = 0;
$pagesWithTheSameName = $pages->filter(function ($page) use ($reverseParts) {
return $page->post_name == $reverseParts[0];
});
$pagesWithTheSameName->each(function ($page) use (&$foundId, $pages, $reverseParts, $postType) {
$count = 0;
$currentPage = $page;

/*
* Loop through the given path parts from right to left,
* ensuring each matches the post ancestry.
*/
while ($currentPage->post_parent != 0 && isset($pages[$currentPage->post_parent])) {
if (!isset($reverseParts[++$count]) || $pages[$currentPage->post_parent]->post_name != $reverseParts[$count]) {
break;
}
$currentPage = $pages[$currentPage->post_parent];
}

if ($currentPage->post_parent == 0 && $count + 1 == count($reverseParts) && $currentPage->post_name == $reverseParts[$count]) {
$foundId = $page->ID;
if ($page->post_type == $postType) {
return false;
}
}
});

return $foundId;
}
}
2 changes: 2 additions & 0 deletions src/Model/Post.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Corcel\Concerns\MetaFields;
use Corcel\Concerns\OrderScopes;
use Corcel\Concerns\Shortcodes;
use Corcel\Concerns\GetByPath;
use Corcel\Corcel;
use Corcel\Model;
use Corcel\Model\Builder\PostBuilder;
Expand All @@ -26,6 +27,7 @@ class Post extends Model
use AdvancedCustomFields;
use MetaFields;
use Shortcodes;
use GetByPath;
use OrderScopes;
use CustomTimestamps;

Expand Down