I need to write the class in PHP. Input takes the path (directory name). The class has two methods:
files - returns an array of file names of this directory.
table - returns a generated html table with a list of files in this directory.
How do I do this?
You don't need to create a class for this. In fact, you should not. That is overly complex and entirely unnecessary.
If you need to read the list of files in a directory, you have three options: readdir, glob, or DirectoryIterator.
If you need to read the list of files in a directory, and all the directories inside of it, then you want to use RecursiveDirectoryIterator.
There are adequate usage examples on the linked documentation pages.
Using these, you can get your list'o'files and build your HTML.
I think it is good to create a class for such functionaliteit, because you can much better predict its behaviour and work around subtle changes in PHP over different versions. Also, you can create different classes to read lists of files from other locations like a database or csv file.
In this case, I extended a renderer class from the base class, because I figured the rendering shouldn't be part of the base class. In fact, it might be better to create a separate class for this that uses any descendant of Folder to render it. But I'll leave it to you to figure out what suits you best.
<?
class Folder
{
private $folder = '';
public function getFolder()
{
return $this->folder;
}
protected function setFolder($value)
{
$this->folder = (string)$folder;
}
public __construct($folder)
{
this->setFolder($folder);
}
public function readFileNames()
{
$folder = (string)$this->getFolder();
if ($folder === '')
{
throw new exception("Folder name is empty");
}
if (is_dir($folder) !== true)
{
throw new exception("'$folder' is not a directory.");
}
$dir = #opendir($this->folder);
if ($dir === false)
{
throw new exception("Cannot open directory '$folder'.");
}
$result = array();
while (false !== ($fileName = readdir($dir)))
{
if (is_file($fileName) === true)
{
$result[] = $fileName;
}
}
return $result;
}
public function readFiles()
{
$fileNames = $this->readFileNames();
$fileNames = array_flip($fileNames);
foreach($fileNames as $fileName=>&$fileContents)
{
if (false === ($file = #readFile($fileName)))
{
$fileContents = null;
}
else
{
$fileContents = $file;
}
}
}
}
class FolderTableRenderer extends Folder
{
public function renderTable()
{
?>
<table>
<thead><tr><th>File name</th></tr></thead>
<tbody>
<?
foreach ($this->readFileNames() as $fileName)
{
?>
<tr><td><?=$fileName?></td></tr>
<?
}
?>
</tbody>
</table>
<?
}
}
Very simple example of class.
class MyFiles {
public static function files($path) {
// Logic used to get the files found at path and return an array
// Just use the built-in functionality of PHP
$filesArray = array();
if (!is_dir($path)) {
return $filesArray;
}
$dir = opendir($path);
while (false !== ($filename = readdir($dir))) {
if (!is_dir($filename)) {
$filesArray[] = $filename;
}
}
return $filesArray;
}
public static function table($path) {
$files = self::files($path);
$c_files = count($files);
if ($c_files == 0) {
return "<table><tbody><tr><td>No files at $path</td></tr></tbody></table>";
}
$table = "";
for ($i = 0; $i < $c_files; $i++) {
$table .= "<tr><td>{$files[$i]}</td></tr>";
}
return "<table><tbody>$table</tbody></table>";
}
}
$fileTable = MyFiles::table('/my/path/with/files');
Related
I am trying to load (include file) the GetRiskSummaryCommandHandler.php (GetRiskSummary\CommandHandler) at runtime dynamically, while resolving Route api/risks to HandleCommand (of class CommandHandler) method.
How can I do this? If not can I modify any taken approach including modifying autoloader?
My api class snippet looks like this:
API.php
<?php
abstract class API
{
public function processRequest()
{
$id1 = $this->requestObj->id1;
//$id2 = $this->requestObj->id2;
$endpoint1 = $this->requestObj->endpoint1;
$endpoint2 = $this->requestObj->endpoint2;
$isDestination = in_array($id1, ['first', 'prev', 'next', 'last']);
$numSetEndpoints = (int)isset($endpoint1) + (int)isset($endpoint2);
switch($numSetEndpoints)
{
case 0:
if ($isDestination)
return json_decode($this->_response("No Endpoint: ", $endpoint1));
return json_decode($this->_response("ProjectAIM API"));
case 1:
$className = $endpoint1.'Controller';
break;
case 2:
$className = $endpoint2.'Controller';
break;
}
$class = "GetRiskSummaryCommandHandler";
$method = "HandleCommand";
if (class_exists($class))
{
if (method_exists($class, $method))
{
$response = (new $class($this->requestObj))->{$method}($this->requestObj);
if ($response['Succeeded'] == false)
{
return $response['Result'];
}
else if ($response['Succeeded'] == true)
{
header("Content-Type: application/json");
return $this->_response($response);
}
else if ($response['Result'])
{
header("Content-Type: text/html");
return $this->_response($response);
}
}
}
}
**Command Handler Snippet, uses a Route Attiribute
GetRiskSummaryCommandHandler.php
<?php
namespace GetRiskSummary;
use Infrastructure\CommandHandler;
class GetRiskSummaryCommandHandler extends CommandHandler
{
#[Route("/api/risks", methods: ["GET"])]
public function HandleCommand()
{
$qb = $this->getEntityManager()
->createQueryBuilder();
$qb->select('*')
->from('Risks', 'Risks')
->orderBy('RiskID', 'DESC');
$query = $qb->getQuery();
return $query->getResult();
}
}
Autoloader.php
<?php
namespace Autoloader;
class Autoloader
{
private static function rglob($pattern, $flags = 0) {
$files = glob($pattern, $flags);
foreach (glob(dirname($pattern).'/*', GLOB_ONLYDIR|GLOB_NOSORT) as $dir) {
$files = array_merge($files, self::rglob($dir.'/'.basename($pattern), $flags));
}
return $files;
}
public static function ClassLoader($path)
{
$pathParts = explode("\\", $path);
$path = $pathParts[array_key_last($pathParts)];
$matches = self::rglob("*/$path*");
foreach ($matches as $name)
{
$filePath = realpath($name);
if (file_exists($filePath))
include $filePath;
}
}
}
spl_autoload_register("AutoLoader\AutoLoader::ClassLoader");
I think the biggest missing feature of PHP Attributes would be that as far as I'm aware PHP Attributes are static and aren't evaluated at runtime. They are just glorified comments.
If it was true, we could do some truly amazing things like non-intrusively attaching pre/post-processing functions, just like what you wrote.
They work just like in symfony or doctrine. You can't use variables in them and you must write your own code to search your php class tree for attributes in the code and use php reflection to obtain the information and run the attributes.
To be honest it's pretty disappointing, although maybe it's just the first step that will be fixed in later versions of PHP.
But for now, I think what you're asking for is impossible. Because they are not running dynamically like you appear to be asking.
Is there any way to use a variable of a method, after a recursive call (without sending that as a parameter).
For example:
class Doc {
public function readDoc($file, $recursion = false) {
if ($recursion != false) {
// DO SOMETHING;
}
$filename = $file."Some added text";
$this->readDoc($filename, 1);
}
}
Here, is it possible to use the value of $file sent in the first call (when the readDoc() function is called recursively).
You can create a simple stack with an array, e.g.
class Doc {
private $stack = [];
public function readDoc($file, $recursion=false) {
if($recursion != false)
DO SOMETHING
$this->stack[] = $file;
$filename = $file."Some added text";
$this->readDoc($filename, 1);
}
}
And then get the first index of the array as your $file variable.
you could also use an anonymous function to work in a different scope something like this:
public function test($file, $recursion = false)
{
$rec = function($r) use ($file, &$rec)
{
if($r !== false) {
}
$filename = $file.'test';
return $rec($r);
};
return $rec($recursion);
}
in this case the $file variable always stays the same
(be aware that the above example creates an infinite-loop)
Lets say I have a lot of files, some of those are in these paths:
root/fonts/folder1/font1.ttf
root/fonts/folder1/font2.ttf
root/fonts/folder2/font1.ttf
root/fonts/folder2/font2.ttf
root/scripts/file.php
Remember that there are also other types of files in those folders. How can my "/scripts/file.php" iterate through the "../fonts/" directory tree and store all the TrueType font (.ttf) files into an array? Could you show me an example?
SPL's recursive iterators are particularly useful for this type of functionality:
abstract class FilesystemRegexFilter extends RecursiveRegexIterator {
protected $regex;
public function __construct(RecursiveIterator $it, $regex) {
$this->regex = $regex;
parent::__construct($it, $regex);
}
}
class FilenameFilter extends FilesystemRegexFilter {
// Filter files against the regex
public function accept() {
return ( ! $this->isFile() || preg_match($this->regex, $this->getFilename()));
}
}
class DirnameFilter extends FilesystemRegexFilter {
// Filter directories against the regex
public function accept() {
return ( ! $this->isDir() || preg_match($this->regex, $this->getFilename()));
}
}
$directory = new RecursiveDirectoryIterator(realpath(__DIR__ . '../fonts'));
$filter = new DirnameFilter($directory, '/^(?!\.)/');
$filter = new FilenameFilter($filter, '/(?:ttf)$/i');
$myArray = [];
foreach(new RecursiveIteratorIterator($filter) as $file) {
$myArray[] = $file;
}
Though not sure why you need to build an array, and don't simply work with the files inside your foreach loop
This may be not the most elegant solution, but I once did the following:
$all_files = scandir("path/to/your/dir");
$selected_files = array();
foreach($all_files as $file)
{
$tmp = explode(".", $file);
if($tmp[1] == "ttf") {
array_push($selected_files, $file);
}
}
Now the selected files are stored in selected_files array.
EDIT:
Of course, in this solution, your files' names can have only one dot.
I'm trying to make a prototype of a simple plugin system I plan on implementing into one of my projects. I have 4 files:
Index.php
Plugins/__BASE.php
Plugins/Sample.php
The index file checks if the 'oncall' method belongs to a class in the Plugins folder using functions I defined in the Plugins class (__BASE.php). If it does exist, it will execute it.
require_once 'Plugins/__BASE.PHP';
$func = 'oncall';
$plugins = new Plugins();
if($plugins->IsPluginMethod($func)) {
$obj = $plugins->GetObject($func);
call_user_func(array($obj, $func));
}
else
echo "'$func' isn't part of a plugin!";
__BASE.php is the base plugin class which all of the plugins will extend. It has two methods: IsPluginMethod() and GetObject(). IsPluginMethod checks if the method name supplied belongs to a class and GetObject returns an instance of the class the method belongs to.
class Plugins {
public $age = "100";
public function IsPluginMethod($func) {
foreach(glob('*.php') as, $file) {
if($file != '__BASE.php') {
require_once $file;
$class = basename($file, '.php');
if(class_exists($class)) {
$obj = new $class;
if(method_exists($obj, $func))
return true;
else
return false;
}
}
}
}
public function GetObject($func) {
foreach(glob('*.php') as $file) {
if($file != '__BASE.php') {
require_once $file;
$class = basename($file, '.php');
if(class_exists($class)) {
$obj = new $class;
return $obj;
}
}
}
}
}
Sample.php is a sample plugin which prints $this->age which is defined in the Plugins class.
class Sample extends Plugins {
public function oncall() {
echo "Age: {$this->age}";
}
}
This is what I see in index.php:
'oncall' isn't part of a plugin!
Can anyone help? Thanks.
In __BASE.php file change (glob('*.php') to glob('Plugins/*.php')
I have been trying to figure out a way to load models from different directory other than "application/models" directory.
I want to load my model from "application/modules".
I have tried the instructions by extending CI_Loader by following instructions provided in
http://ellislab.com/forums/viewthread/103276/#
but it is giving me error "Unable to locate the specified class: Model.php" whereas my core "Model.php" is there under "system/core" folder.
Even ,I have also tried to load model using
$this->load->model (APPPATH.'modules/mymodel.php');
but no success.
UPDATE:
I want my model loader to behave like this :
$this->load->module('mymodel')
and
$this->mymodel->mymodelmethod() !!
NOT like: $this->load->models('mymodel')
Is there any way i could load models from outside the "application/modules" folder ?
Please advise .Thanks
The problem is that the code you reference is for an older version of codeigniter. In older versions of codeigniter the CI_Model class was named Model. As the class Model doesn't exist in the latest version of php you are getting the error:
Unable to locate the specified class: Model.php
The part of the code where this is happening is towards the end (line 114):
if ( ! class_exists('Model'))
{
load_class('Model', FALSE);
}
If you check your system/core/Loader.php you will see that in the version of codeigniter you are using this has been replaced with:
if ( ! class_exists('CI_Model'))
{
load_class('Model', 'core');
}
You need to re-write the MY_Loader.php to make it compatible with the version of codeigniter you are using, presumably 2.1.
The best way to do this would be to grab the Codeigniter 2.1 version of the core Loader.php and use the model() method from it as a base for re-writing your MY_Loader.php.
Something to bare in mind when re-writing your MY_Loader.php is that constructors also changed in later versions of codeigniter, so your MY_Loader class should look something like this:
class MY_Loader extends CI_Loader {
function __construct()
{
parent::__construct();
}
public function model($model, $name = '', $db_conn = FALSE)
{
...
}
}
More details on extending core classes can be found in the Codeigniter Documentation
UPDATE
I noticed you changed your functionality, so I updated the answer. You can create a whole new loader and base it off the core CI_Model class, although it seems like a lot of effort when you could just extend the model loader and be done.
class MY_Loader extends CI_Loader {
protected $_ci_module_paths = array();
protected $_ci_modules = array();
function __construct()
{
parent::__construct();
$this->_ci_module_paths = array(APPPATH);
}
public function initialize()
{
$this->_ci_classes = array();
$this->_ci_loaded_files = array();
$this->_ci_models = array();
$this->_ci_modules = array();
$this->_base_classes =& is_loaded();
$this->_ci_autoloader();
return $this;
}
public function module($module, $name = '', $db_conn = FALSE)
{
if (is_array($module))
{
foreach ($module as $babe)
{
$this->$module($babe);
}
return;
}
if ($module == '')
{
return;
}
$path = '';
// Is the $module in a sub-folder? If so, parse out the filename and path.
if (($last_slash = strrpos($module, '/')) !== FALSE)
{
// The path is in front of the last slash
$path = substr($module, 0, $last_slash + 1);
// And the module name behind it
$module = substr($module, $last_slash + 1);
}
if ($name == '')
{
$name = $module;
}
if (in_array($name, $this->_ci_modules, TRUE))
{
return;
}
$CI =& get_instance();
if (isset($CI->$name))
{
show_error('The module name you are loading is the name of a resource that is already being used: '.$name);
}
$module = strtolower($module);
foreach ($this->_ci_module_paths as $mod_path)
{
if ( ! file_exists($mod_path.'modules/'.$path.$module.'.php'))
{
continue;
}
if ($db_conn !== FALSE AND ! class_exists('CI_DB'))
{
if ($db_conn === TRUE)
{
$db_conn = '';
}
$CI->load->database($db_conn, FALSE, TRUE);
}
if ( ! class_exists('CI_Model'))
{
load_class('Model', 'core');
}
require_once($mod_path.'modules/'.$path.$module.'.php');
$module = ucfirst($module);
$CI->$name = new $module();
$this->_ci_modules[] = $name;
return;
}
// couldn't find the model
show_error('Unable to locate the module you have specified: '.$module);
}
public function add_package_path($path, $view_cascade=TRUE)
{
$path = rtrim($path, '/').'/';
array_unshift($this->_ci_library_paths, $path);
array_unshift($this->_ci_model_paths, $path);
array_unshift($this->_ci_module_paths, $path);
array_unshift($this->_ci_helper_paths, $path);
$this->_ci_view_paths = array($path.'views/' => $view_cascade) + $this->_ci_view_paths;
// Add config file path
$config =& $this->_ci_get_component('config');
array_unshift($config->_config_paths, $path);
}
public function remove_package_path($path = '', $remove_config_path = TRUE)
{
$config =& $this->_ci_get_component('config');
if ($path == '')
{
$void = array_shift($this->_ci_library_paths);
$void = array_shift($this->_ci_model_paths);
$void = array_shift($this->_ci_module_paths);
$void = array_shift($this->_ci_helper_paths);
$void = array_shift($this->_ci_view_paths);
$void = array_shift($config->_config_paths);
}
else
{
$path = rtrim($path, '/').'/';
foreach (array('_ci_library_paths', '_ci_model_paths', '_ci_module_paths', '_ci_helper_paths') as $var)
{
if (($key = array_search($path, $this->{$var})) !== FALSE)
{
unset($this->{$var}[$key]);
}
}
if (isset($this->_ci_view_paths[$path.'views/']))
{
unset($this->_ci_view_paths[$path.'views/']);
}
if (($key = array_search($path, $config->_config_paths)) !== FALSE)
{
unset($config->_config_paths[$key]);
}
}
// make sure the application default paths are still in the array
$this->_ci_library_paths = array_unique(array_merge($this->_ci_library_paths, array(APPPATH, BASEPATH)));
$this->_ci_helper_paths = array_unique(array_merge($this->_ci_helper_paths, array(APPPATH, BASEPATH)));
$this->_ci_model_paths = array_unique(array_merge($this->_ci_model_paths, array(APPPATH)));
$this->_ci_module_paths = array_unique(array_merge($this->_ci_module_paths, array(APPPATH)));
$this->_ci_view_paths = array_merge($this->_ci_view_paths, array(APPPATH.'views/' => TRUE));
$config->_config_paths = array_unique(array_merge($config->_config_paths, array(APPPATH)));
}
private function _ci_autoloader()
{
if (defined('ENVIRONMENT') AND file_exists(APPPATH.'config/'.ENVIRONMENT.'/autoload.php'))
{
include(APPPATH.'config/'.ENVIRONMENT.'/autoload.php');
}
else
{
include(APPPATH.'config/autoload.php');
}
if ( ! isset($autoload))
{
return FALSE;
}
// Autoload packages
if (isset($autoload['packages']))
{
foreach ($autoload['packages'] as $package_path)
{
$this->add_package_path($package_path);
}
}
// Load any custom config file
if (count($autoload['config']) > 0)
{
$CI =& get_instance();
foreach ($autoload['config'] as $key => $val)
{
$CI->config->load($val);
}
}
// Autoload helpers and languages
foreach (array('helper', 'language') as $type)
{
if (isset($autoload[$type]) AND count($autoload[$type]) > 0)
{
$this->$type($autoload[$type]);
}
}
// A little tweak to remain backward compatible
// The $autoload['core'] item was deprecated
if ( ! isset($autoload['libraries']) AND isset($autoload['core']))
{
$autoload['libraries'] = $autoload['core'];
}
// Load libraries
if (isset($autoload['libraries']) AND count($autoload['libraries']) > 0)
{
// Load the database driver.
if (in_array('database', $autoload['libraries']))
{
$this->database();
$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));
}
// Load all other libraries
foreach ($autoload['libraries'] as $item)
{
$this->library($item);
}
}
// Autoload models
if (isset($autoload['model']))
{
$this->model($autoload['model']);
}
// Autoload modules
if (isset($autoload['module']))
{
$this->module($autoload['module']);
}
}
}
You can use the above in your controller via:
$this->load->module('test_module');
$this->test_module->method();
If i am getting your problem correctly , you have to initialize the instance of CI.
Example :-
In your external file do this :-
class modules
{
var $CI;
function __construct()
{
$this->CI =& get_instance();
}
function retrieve_data()
{
// Load Model
$this->CI->load->model('YOUR MODEL NAME'); // Give the name of your model that you want to laod
}
}
Hope it helps you :)
As far as i understand your question the answer lies here.
Moduler Extension
download it and install according to the instructions. then you can simply access any thing with these steps.
In your controller load the module like this.
$this->load->module('pages');
Make sure you have a directory Modules under application. And your Module pages should exist there. Pages module can have controller , models , views , helpers , config and libraries etc.
Now you need to call model. Here is how you can do it.
$this->pages->model->test_model->get_test_data();
Also you should note that loading module loads all the resources.
If nothing works, try this
public function setPackagePaths($path, $view_cascade=TRUE, $model_cascade=TRUE, $library_cascade=TRUE, $helper_cascade=TRUE) {
$path = rtrim($path, '/').'/';
///$this->_ci_view_paths = $this->_ci_library_paths = $this->_ci_model_paths = array();
$this->_ci_library_paths = array($path.'libraries/' => $library_cascade) + $this->_ci_library_paths ;
$this->_ci_helper_paths = array($path.'helpers/' => $helper_cascade) + $this->_ci_helper_paths ;
$this->_ci_model_paths = array($path.'models/' => $model_cascade) + $this->_ci_model_paths ;
$this->_ci_view_paths = array($path.'views/' => $view_cascade) + $this->_ci_view_paths;
// Add config file path
$config =& $this->_ci_get_component('config');
array_unshift($config->_config_paths, $path);
}
Its a hardcore way to update this function to Loader Class. But works fine.