/** * This function will use the resource cache to lookup all controllers and their methods. Then it * will create a Triumph_TemplateFileTag instance for each method. * * @param string $sourceDir the root directory of the project in question * @param string $detectorDbFileName the location of the resource cache SQLite file; as created by Triumph * @param boolean $doSkip out parameter; if TRUE then this detector does not know how * to detect templates for the given source directory; this situation * is different than zero templates being detected. * @return Triumph_TemplateFileTag[] array of Triumph_TemplateFileTag instances the detected template files and their variables */ function detectTemplates($sourceDir, $detectorDbFileName, &$doSkip) { $allTemplates = array(); if (!is_file($detectorDbFileName)) { return $allTemplates; } // need to check that this detector is able to recognize the directory structure of sourceDir // if not, then we need to skip detection by returning immediately and setting $doSkip to TRUE. // by skipping detection, we prevent any detected templates from the previous detection script // from being deleted. $doSkip = TRUE; // for laravel, we look for the artisan script. if we don't have the artisan script assume // that this source is not a laravel project. $sourceDir = \opstring\ensure_ends_with($sourceDir, DIRECTORY_SEPARATOR); if (!is_file($sourceDir . 'artisan')) { return $allTemplates; } $doSkip = FALSE; // add your logic here; usually it will consist of querying the SQLite database in $detectorDbFileName // recursing though the call stack and picking the method calls for templates. $pdo = Zend_Db::factory('Pdo_Sqlite', array("dbname" => $detectorDbFileName)); $callStackTable = new Triumph_CallStackTable($pdo); $callStacks = $callStackTable->load(); // figure out the variables $scopes = $callStackTable->splitScopes($callStacks); // now go through each scope, looking for calls to $this->load->view foreach ($scopes as $scope) { // list of all method calls used to find calls to view method $methodCalls = $callStackTable->getMethodCalls($scope); // list of all property accesses, make sure that calls to view method // are used on the loader member variables $propertyCalls = $callStackTable->getPropertyCalls($scope); $variableCalls = $callStackTable->getVariables($scope); foreach ($methodCalls as $destinationVariable => $call) { if (\opstring\compare_case($call->methodName, 'make') == 0 && \opstring\compare_case($call->objectName, 'View') == 0) { // get the function arguments to View::make // the first argument to make is the template file // the second argument is an array of data (the template vars) $template = $variableCalls[$call->functionArguments[0]]; $data = $variableCalls[$call->functionArguments[1]]; if ($template) { $currentTemplate = new Triumph_TemplateFileTag(); $currentTemplate->variables = array(); $currentTemplate->fullPath = ''; $currentTemplate->fullPath = $template->scalarValue; // view file may have an extension; if it has an extension use that; otherwise use the default (.php) if (stripos($currentTemplate->fullPath, '.') === FALSE) { $currentTemplate->fullPath .= '.php'; } // not using realpath() so that Triumph can know that a template file has not yet been created // or the programmer has a bug in the project. $currentTemplate->fullPath = \opstring\replace($currentTemplate->fullPath, '/', DIRECTORY_SEPARATOR); $currentTemplate->fullPath = \opstring\replace($currentTemplate->fullPath, '\\', DIRECTORY_SEPARATOR); $currentTemplate->fullPath = $sourceDir . 'app' . DIRECTORY_SEPARATOR . 'views' . DIRECTORY_SEPARATOR . $currentTemplate->fullPath; $allTemplates[] = $currentTemplate; } // argument 2 is an array of template variables if (isset($variableCalls[$call->functionArguments[1]])) { $variableCall = $variableCalls[$call->functionArguments[1]]; $arrayKeys = $callStackTable->getArrayKeys($scope, $variableCall->destinationVariable); foreach ($arrayKeys as $key) { // add the siguil here; editor expects us to return variables $currentTemplate->variables[] = '$' . $key; } $allTemplates[count($allTemplates) - 1] = $currentTemplate; } } } } return $allTemplates; }
function testCompareCase() { $this->assertEquals(-1, \opstring\compare_case('that', 'this')); $this->assertEquals(-1, \opstring\compare_case('that', 'thIS')); $this->assertEquals(0, \opstring\compare_case('this', 'this')); $this->assertEquals(0, \opstring\compare_case('this', 'thIS')); $this->assertEquals(1, \opstring\compare_case('this', 'that')); $this->assertEquals(1, \opstring\compare_case('this', 'thAT')); }
/** * This function will lookup all database connections for the given source. Then it * will create a Triumph_DatabaseTag connection. * * @param string $sourceDir the root directory of the project in question * @param boolean $doSkip out parameter; if TRUE then this detector does not know how * to detect databases for the given source directory; this situation * is different than zero databases being detected. * @return Triumph_DatabaseTag[] array of Triumph_DatabaseTag instances the detected databases */ function detectDatabases($sourceDir, &$doSkip) { $doSkip = TRUE; $allDatabases = array(); $sourceDir = \opstring\ensure_ends_with($sourceDir, DIRECTORY_SEPARATOR); if (!is_file($sourceDir . 'application/config/development/database.php') && !is_file($sourceDir . 'application/config/database.php')) { return $allDatabases; } // need to check that this detector is able to recognize the directory structure of sourceDir // if not, then we need to skip detection by returning immediately and setting $doSkip to TRUE. // by skipping detection, we prevent any detected databases from the previous detection script // from being deleted. $doSkip = FALSE; // need this define so that we can include code igniter files directly define('BASEPATH', ''); // database config file can be in the environment directory // for now just get the development environment info if (is_file($sourceDir . 'application/config/development/database.php')) { include $sourceDir . 'application/config/development/database.php'; if ($db) { foreach ($db as $groupName => $groupConnection) { if (strcasecmp('mysql', $groupConnection['dbdriver']) == 0) { $tag = tagFromDbArray($groupName, $groupConnection); $allDatabases[] = $tag; } } } } else { if (is_file($sourceDir . 'application/config/database.php')) { $db = array(); include $sourceDir . 'application/config/database.php'; if ($db) { foreach ($db as $groupName => $groupConnection) { if (\opstring\compare_case('mysql', $groupConnection['dbdriver']) == 0 || \opstring\compare_case('mysqli', $groupConnection['dbdriver']) == 0) { $tag = tagFromDbArray($groupName, $groupConnection); $allDatabases[] = $tag; } } } } } return $allDatabases; }
/** * This function will use the resource cache to lookup all controllers and their methods. Then it * will create a Triumph_TemplateFile instance for each method. * * @param string $sourceDir the root directory of the project in question * @param string $detectorDbFileName the location of the resource cache SQLite file; as created by Triumph * @param boolean $doSkip out parameter; if TRUE then this detector does not know how * to detect templates for the given source directory; this situation * is different than zero templates being detected. * @return Triumph_TemplateFile[] array of Triumph_TemplateFile instances the detected template files and their variables */ function detectTemplates($sourceDir, $detectorDbFileName, &$doSkip) { $doSkip = TRUE; $allTemplates = array(); if (!is_file($detectorDbFileName)) { return $allTemplates; } // need to check that this detector is able to recognize the directory structure of sourceDir // if not, then we need to skip detection by returning immediately and setting $doSkip to TRUE. // by skipping detection, we prevent any detected templates from the previous detection script // from being deleted. $sourceDir = \opstring\ensure_ends_with($sourceDir, DIRECTORY_SEPARATOR); if (!is_file($sourceDir . 'application/config/routes.php') || !is_file($sourceDir . 'application/config/config.php')) { // this source directory does not contain a code igniter directory. return $allTemplates; } $doSkip = FALSE; // add your logic here; usually it will consist of querying the SQLite database in $detectorDbFileName // recursing though the call stack and picking the method calls for templates. $pdo = Zend_Db::factory('Pdo_Sqlite', array("dbname" => $detectorDbFileName)); $callStackTable = new Triumph_CallStackTable($pdo); $callStacks = $callStackTable->load(); // figure out the variables $scopes = $callStackTable->splitScopes($callStacks); // now go through each scope, looking for calls to $this->load->view foreach ($scopes as $scope) { // list of all method calls used to find calls to view method $methodCalls = $callStackTable->getMethodCalls($scope); // list of all property accesses, make sure that calls to view method // are used on the loader member variables $propertyCalls = $callStackTable->getPropertyCalls($scope); $variableCalls = $callStackTable->getVariables($scope); foreach ($methodCalls as $destinationVariable => $call) { if (\opstring\compare_case($call->methodName, 'view') == 0 && isset($propertyCalls[$call->objectName])) { // is this view call of a loader object ? $propertyCall = $propertyCalls[$call->objectName]; if (\opstring\compare('$this', $propertyCall->objectName) == 0 && (\opstring\compare('load', $propertyCall->propertyName) == 0 || \opstring\compare('loader', $propertyCall->propertyName) == 0)) { $currentTemplate = new Triumph_TemplateFileTag(); $currentTemplate->variables = array(); $currentTemplate->fullPath = ''; if (count($call->functionArguments) >= 1) { // argument 1 of the view method call is the template file // most of the time views are given as relative relatives; starting from the application/views/ directory // for now ignore variable arguments if (isset($variableCalls[$call->functionArguments[0]])) { $variableCall = $variableCalls[$call->functionArguments[0]]; if ($variableCall->type == Triumph_CallStack::SCALAR) { $currentTemplate->fullPath = $variableCall->scalarValue; // view file may have an extension; if it has an extension use that; otherwise use the default (.php) if (stripos($currentTemplate->fullPath, '.') === FALSE) { $currentTemplate->fullPath .= '.php'; } // not using realpath() so that Triumph can know that a template file has not yet been created // or the programmer has a bug in the project. $currentTemplate->fullPath = \opstring\replace($currentTemplate->fullPath, '/', DIRECTORY_SEPARATOR); $currentTemplate->fullPath = \opstring\replace($currentTemplate->fullPath, '\\', DIRECTORY_SEPARATOR); $currentTemplate->fullPath = $sourceDir . 'application' . DIRECTORY_SEPARATOR . 'views' . DIRECTORY_SEPARATOR . $currentTemplate->fullPath; // push it now just in case the template does not get any variables $allTemplates[] = $currentTemplate; } } } if (count($call->functionArguments) >= 2 && !empty($currentTemplate->fullPath)) { // argument 2 is an array of template variables if (isset($variableCalls[$call->functionArguments[1]])) { $variableCall = $variableCalls[$call->functionArguments[1]]; $arrayKeys = $callStackTable->getArrayKeys($scope, $variableCall->destinationVariable); foreach ($arrayKeys as $key) { // add the siguil here; editor expects us to return variables $currentTemplate->variables[] = '$' . $key; } $allTemplates[count($allTemplates) - 1] = $currentTemplate; } } } } } } return $allTemplates; }
/** * This function will use the resource cache to lookup all controllers and their methods. Then it * will create a Triumph_Url instance for each method; note that the routes file is * also consulted and we will generate URLs for the default controller. * * @param string $sourceDir the root directory of the project in question * @param string $resourceDbFileName the location of the resource cache SQLite file; as created by Triumph * @param string $host the hostname of the application; this will be used a the prefix on all URLs * @param boolean $doSkip out parameter; if TRUE then this detector does not know how * to detect URLs for the given source directory; this situation * is different than zero URLs being detected. * @return Triumph_Url[] array of Triumph_Url instances the detected URLs */ function detectUrls($sourceDir, $resourceDbFileName, $host, &$doSkip) { $doSkip = TRUE; if (!is_file($resourceDbFileName)) { return array(); } $sourceDir = \opstring\ensure_ends_with($sourceDir, DIRECTORY_SEPARATOR); $host = \opstring\ensure_ends_with($host, '/'); // TODO: handle multiple apps // need this define so that we can include code igniter files directly if (!defined('BASEPATH')) { define('BASEPATH', ''); } if (!is_file($sourceDir . 'application/config/routes.php') || !is_file($sourceDir . 'application/config/config.php')) { // this source directory does not contain a code igniter directory. return array(); } $doSkip = FALSE; // get the code igniter configuration so that we can use it to build the // correct routes $config = array(); $route = array(); include $sourceDir . 'application/config/routes.php'; include $sourceDir . 'application/config/config.php'; $allUrls = array(); // lookup all controller files from the resource cache, only controllers are accessible via URLs // since file names in the cache are OS dependant, need to use the correct directory separators $pdo = Zend_Db::factory('Pdo_Sqlite', array("dbname" => $resourceDbFileName)); $fileItemTable = new Triumph_FileItemTable($pdo); $controllerDir = $sourceDir . 'application' . DIRECTORY_SEPARATOR . 'controllers'; $matchingFiles = $fileItemTable->MatchingFiles($controllerDir); // lookup all of the methods for all controller files. $resourceTable = new Triumph_ResourceTable($pdo); $methods = $resourceTable->PublicMethodsFromFiles($matchingFiles); foreach ($methods as $resource) { // need to handle any sub-directories underneath the controllers; as the subdirectory // is propagated in the URL $controllerFile = \opstring\after($resource->fullPath, $controllerDir); $subDirectory = dirname($controllerFile); if ('\\' == $subDirectory || '/' == $subDirectory) { // hack to work around special case when there is no subdirectory $subDirectory = ''; } // constructors are not web-accessible // code igniter makes methods that start with underscore if (\opstring\compare_case('__construct', $resource->identifier) && !\opstring\begins_with($resource->identifier, '_')) { // TODO: any controller arguments ... should get these from the user somehow $extra = ''; $appUrl = makeUrl($route, $config, $subDirectory, $resource->fullPath, $resource->className, $resource->identifier, $extra); $appUrl->url = $host . $appUrl->url; $allUrls[] = $appUrl; } } return $allUrls; }