0

How do you change the order of files in the file system? I am using Fetch.

The reason I ask is because I have a menu bar that automatically lists the pages in my website by what is in the "pages" folder. The way I see it on fetch, they are in alphabetical order "blog.ctp, games.ctp, home.ctp, news.ctp". So I would expect the menu bar to list the pages as "BLOG GAMES HOME NEWS", but instead it lists them as "GAMES NEWS BLOG HOME". Ultimately I want the order to be "HOME GAMES BLOG NEWS". How do I change the order of the files?

Here is my code in case it is helpful. But my code is not the problem...I just need to know how to change the file order in the folder "Pages".

if ($handle=opendir('../View/Pages/'))
{
    while (false !== ($entry = readdir($handle))) 
    {
        if(strpos($entry,".ctp")!==False) 
            echo "<div class='menubarItem'>".$this->Html->link(substr($entry,0,-4),
                array('controller'=>'pages','action'=>'display',substr($entry,0,-4)),
                array('escape' => false)).'</div>';

    }
}
Nick Manning
  • 2,828
  • 1
  • 29
  • 50
  • See here: [Sort and display directory list alphabetically using opendir() in php](http://stackoverflow.com/questions/884974/sort-and-display-directory-list-alphabetically-using-opendir-in-php) – Matt Cain Mar 13 '13 at 09:45
  • Matt I want a custom sort, not alphabetical. I just made a side comment that I thought they would be alphabetical by default but to my surpise they were in some other order. – Nick Manning Mar 13 '13 at 11:31

2 Answers2

1

Add a priority flag to your file names at the beginning or end. I.e. GAMES_1, HOME_2 ...etc... Sort the array of file names using PHP sort() and replace the last two character from file name using substr($filename, -2).

Jay Bhatt
  • 5,601
  • 5
  • 40
  • 62
  • This is a pretty good work-around, thanks. I am still wondering if it is possible to simply change the order of the files manually. I don't want the name of the file to define the order, I want the order to define the order. – Nick Manning Mar 13 '13 at 11:34
  • This work around will give you the ability to set manual order to your file names giving you more flexibility.... – Jay Bhatt Mar 13 '13 at 11:37
  • I know your answer will work, and I will implement it if I need to, but changing the name of the file will break cakephp conventions so I'd prefer not to do it. I want to simply be able to drag the file I want to be read first to the top of the file list, causing the PHP to read the first file first, second file second, etc...but Fetch doesn't let me click and drag files to change the order manually. If there is no way to do this either with Fetch or some other method, I will implement your work around because it is a good solution. – Nick Manning Mar 13 '13 at 11:43
  • In that case you can try PHP's usort() function and write your own sorting function... – Jay Bhatt Mar 13 '13 at 12:19
  • Changing the name of the file breaks CakePHP convention and defining my own sort function defeats the purpose of what I am doing. I am building a feature into the CakePHP framework to use on all of my websites from this point forward. This feature will read through the "pages" folder in my file system, which will contain all of the main pages in my website. Then it will automatically generate links to the pages in my header. How can I access the file system to change the order of the files so that it reads the files in a different order? Fetch doesn't allow me to change the order of the files. – Nick Manning Mar 13 '13 at 13:09
  • If you want to have full control over the order, why not just define the order in an array, if put fixed HTML in your output? That way you don't have to rely on the file system for generating the menu, or move it to a database? – thaJeztah Mar 15 '13 at 07:50
0

The CakePHP Folder utility has the option to sort the result;

http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#Folder::find

App::uses('Folder', 'Utility');
App::uses('Folder', 'Utility');
$myFolder = new Folder('/path/to/directory');
$files = $myFolder->find('*.ctp', true);

foreach ($files as $filename) {

   // your code here 

}

However, If you do not want to show the pages alphabetically, either prefix the file names with a number and create a special route or don't use the filename for sorting but manually specify the order.

In the end, the only reason for dynamically creating the menu based on the View files is to automatically have the menu generated for you. However, chances are that these changes won't occur often and based on your comment (prefered order) you do have a specific order in mind.

The best solution is to just manually specify the sort order. This will also improve performance as the server will not have to do a directory-scan for each request

For example:

/**
 * MenuItems
 *
 * preferable pass this as a viewVar to the View
 *
 * file => title
 */
$menuItems = array(
    'home' => 'HOME',
    'blog' => 'BLOG',
    ....
);

foreach($menuItems as $file => $title) {
     // your code here
}

moving this to a Model

Retrieving the file list inside your View is not the location where this should be done. It's best to read the files beforehand and pass them to the View via a viewvar. Because reading the files is actually 'retrieving data', you may want to create a Model for this that is not connected to a database table.

example

app/Model/Menuoption.php

App::uses('Folder', 'Utility');

class Menuoption extends AppModel {
    // this model does not use a database table
    public $useTable = false;


    public function getOptions()
    {
        // NOTE: or use the 'manually' created menuItems here
        $myFolder = new Folder('/path/to/directory');
        return $myFolder->find('*.ctp', true);
    }
}

Inside your controller; for example in the beforeRender() callback, or inside a regular action;

public function beforeRender()
{
     $this->set('files', ClassRegistry::init('Menuoption')->getOptions());

}

inside your view, you can now access the results via the $files variable;

 foreach ($files as $filename) {

   // your code here 

}
thaJeztah
  • 27,738
  • 9
  • 73
  • 92