Get all "pages" in YII?
Asked Answered
C

5

8

I'm trying to create my own xml sitemap. Everything is done except for the part that I thought was going to be the easiest. How do you get a list of all the pages on the site? I have a bunch of views in a /site folder and a few others. Is there a way to explicitly request their URLs or perhaps via the controllers?

I do not want to make use of an extension

Comply answered 14/1, 2013 at 9:37 Comment(2)
You might wanna use an extension for this? yiiframework.com/extensions/?tag=sitemapIngeborg
I don't want to use an extension. I am basically writing my own extension that plugs in with other SEO components I use and need.Comply
A
9

You can use reflection to iterate through all methods of all your controllers:

Yii::import('application.controllers.*');
$urls = array();

$directory = Yii::getPathOfAlias('application.controllers');
$iterator = new DirectoryIterator($directory);
foreach ($iterator as $fileinfo)
{
    if ($fileinfo->isFile() and $fileinfo->getExtension() == 'php')
    {
        $className = substr($fileinfo->getFilename(), 0, -4); //strip extension
        $class = new ReflectionClass($className);

        foreach ($class->getMethods(ReflectionMethod::IS_PUBLIC) as $method)
        {
            $methodName = $method->getName();
            //only take methods that begin with 'action', but skip actions() method
            if (strpos($methodName, 'action') === 0 and $methodName != 'actions')
            {   
                $controller = lcfirst(substr($className, 0, strrpos($className, 'Controller')));
                $action = lcfirst(substr($methodName, 6));
                $urls[] = Yii::app()->createAbsoluteUrl("$controller/$action");
            }
        }
    }
}
Asti answered 4/3, 2013 at 13:32 Comment(0)
S
1

You need to know what content you want to include in your sitemap.xml, I don't really think you want to include ALL pages in your sitemap.xml, or do you really want to include something like site.com/article/edit/1 ?

That said, you may only want the result from the view action in your controllers. truth is, you need to know what you want to indexed.

Do not think in terms of controllers/actions/views, but rather think of the resources in your system that you want indexed, be them articles, or pages, they are all in your database or stored somehow, so you can list them, and they have a URI that identifies them, getting the URI is a matter of invoking a couple functions.

Supremacy answered 14/1, 2013 at 15:6 Comment(0)
B
1

There are two possiblities -

Case 1:

You are running a static website then you can find all your HTML inside 1 folder - protected/views/site/pages http://www.yiiframework.com/wiki/22/how-to-display-static-pages-in-yii/

Case 2:

Website is dynamic. Tasks such as generating and regenerating Sitemaps can be classified into background tasks.

Running background taks can be achieved by emulating the browser which is possible in linux using - WGET, GET or lynx commands

Or, You can create a CronController as a CConsoleCommand. How to use Commands in YII is shown in link below - http://tariffstreet.com/yii/2012/04/implementing-cron-jobs-with-yii-and-cconsolecommand/

Sitemap is an XML which lists your site's URL. But it does more than that. It helps you visualize the structure of a website , you may have

  • category
  • subcategories.

While making a useful extension, above points can be kept into consideration before design.

Frameworks like Wordpress provide way to generate categorical sitemap. So the metadata for each page is stored from before and using that metadata it discovers and group pages.

Solution by Reflection suggested by @Pavle is good and should be the way to go. Consider there may be partial views and you may or may not want to list them as separate links.

So how much effort you want to put into creating the extension is subject to some of these as well.

You may either ask user to list down all variables in config fie and go from there which is not bad or you have to group pages and list using some techniques like reflection and parsing pages and looking for regex.

For ex - Based on module names you can group them first and controllers inside a module can form sub-group.

Bricole answered 4/3, 2013 at 14:49 Comment(0)
L
1

One first approach could be to iterate over the view files, but then you have to take into account that in some cases, views are not page destinations, but page sections included in another pages by using CController::renderPartial() method. By exploring CController's Class Reference I came upon the CController::actions() method.

So, I have not found any Yii way to iterate over all the actions of a CController, but I used php to iterate over all the methods of a SiteController in one of my projects and filter them to these with the prefix 'action', which is my action prefix, here's the sample

class SiteController extends Controller{
    public function actionTest(){
        echo '<h1>Test Page!</h1></p>';
        $methods = get_class_methods(get_class($this));
        // The action prefix is strlen('action') = 6
        $actionPrefix = 'action';
        $reversedActionPrefix = strrev($actionPrefix);
        $actionPrefixLength = strlen($actionPrefix);
        foreach ($methods as $index=>$methodName){
            //Always unset actions(), since it is not a controller action itself and it has the prefix 'action'
            if ($methodName==='actions') {
                unset($methods[$index]);
                continue;
            }
            $reversedMethod = strrev($methodName);
            /* if the last 6 characters of the reversed substring === 'noitca', 
             * it means that $method Name corresponds to a Controller Action,
             * otherwise it is an inherited method and must be unset.
             */
            if (substr($reversedMethod, -$actionPrefixLength)!==$reversedActionPrefix){
                unset($methods[$index]);
            } else $methods[$index] = strrev(str_replace($reversedActionPrefix, '', $reversedMethod,$replace=1));
        }
        echo 'Actions '.CHtml::listBox('methods', NULL, $methods);
    }
    ...
}

And the output I got was..

All the actions in a ListBox!

I'm sure it can be furtherly refined, but this method should work for any of the controllers you have...

So what you have to do is:

For each Controller: Filter out all the not-action methods of the class, using the above method. You can build an associative array like

array(
    'controllerName1'=>array(
        'action1_1',
        'action1_2'),
    'controllerName2'=>array(
        'action2_1',
        'action2_2'),
);

I would add a static method getAllActions() in my SiteController for this.

get_class_methods, get_class, strrev and strlen are all PHP functions.

Lm answered 4/3, 2013 at 16:14 Comment(0)
S
1

Based on your question: 1. How do you get a list of all the pages on the site?

Based on Yii's way of module/controller/action/action_params and your need to construct a sitemap for SEO.

  1. It will be difficult to parse automatically to get all the urls as your action params varies indefinitely. Though you could simply get controller/action easily as constructed by Pavle Predic. The complexity comes along when you have customized (SERF) URL rules meant for SEO.

The next best solution is to have a database of contents and you know how to get each content via url rules, then a cron console job to create all the urls to be saved as sitemap.xml.

Hope this helps!

Seat answered 8/3, 2013 at 7:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.