Extension Manager improvements

This commit is contained in:
Taras Machyshyn
2014-10-30 13:04:49 +02:00
parent 1efc8fe976
commit c8bfa823e5
19 changed files with 408 additions and 84 deletions
+1 -1
View File
@@ -143,7 +143,7 @@ class HookManager
foreach ($hookDirs as $hookDir) {
if (file_exists($hookDir)) {
$fileList = $this->getFileManager()->getFileList($hookDir, 1, '\.php$', 'file');
$fileList = $this->getFileManager()->getFileList($hookDir, 1, '\.php$', true);
foreach ($fileList as $scopeName => $hookFiles) {
+1 -1
View File
@@ -139,7 +139,7 @@ class ServiceFactory
foreach ($dirs as $dir) {
if (file_exists($dir)) {
$fileList = $this->getFileManager()->getFileList($dir, false, '\.php$', 'file');
$fileList = $this->getFileManager()->getFileList($dir, false, '\.php$', true);
foreach ($fileList as $file) {
$filePath = Util::concatPath($dir, $file);
$className = Util::getClassName($filePath);
+18 -11
View File
@@ -28,14 +28,6 @@ use Espo\Core\Utils\Util,
abstract class Base
{
private $container;
private $actionManager;
private $zipUtil;
private $fileManager;
private $config;
private $entityManager;
@@ -44,6 +36,14 @@ abstract class Base
protected $params = null;
private $container;
private $actionManager;
private $zipUtil;
private $fileManager;
protected $processId = null;
protected $manifestName = 'manifest.json';
@@ -311,12 +311,19 @@ abstract class Base
*
* @return boolen
*/
protected function deleteFiles()
protected function deleteFiles($withEmptyDirs = false)
{
$deleteFileList = $this->getDeleteFileList();
//remove directories, leave only files
foreach ($deleteFileList as $key => $filePath) {
if (!is_file($filePath)) {
unset($deleteFileList[$key]);
}
}
if (!empty($deleteFileList)) {
return $this->getFileManager()->remove($deleteFileList);
return $this->getFileManager()->remove($deleteFileList, null, $withEmptyDirs);
}
return true;
@@ -328,7 +335,7 @@ abstract class Base
$packagePath = $this->getPackagePath();
$filesPath = Util::concatPath($packagePath, self::FILES);
$this->data['fileList'] = $this->getFileManager()->getFileList($filesPath, true, '', 'all', true);
$this->data['fileList'] = $this->getFileManager()->getFileList($filesPath, true, '', true, true);
}
return $this->data['fileList'];
@@ -46,7 +46,7 @@ class Uninstall extends \Espo\Core\Upgrades\Actions\Base
if (file_exists($backupPath)) {
/* remove extension files, saved in fileList */
if (!$this->deleteFiles()) {
if (!$this->deleteFiles(true)) {
throw new Error('Permission denied to delete files.');
}
@@ -319,7 +319,7 @@ class Converter
{
$customTables = array();
$fileList = $this->getFileManager()->getFileList($this->customTablePath, false, '\.php$', 'file');
$fileList = $this->getFileManager()->getFileList($this->customTablePath, false, '\.php$', true);
foreach($fileList as $fileName) {
$fileData = $this->getFileManager()->getContents( array($this->customTablePath, $fileName) );
@@ -18,13 +18,13 @@
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
************************************************************************/
************************************************************************/
namespace Espo\Core\Utils\File;
use \Espo\Core\Utils\Util;
class ClassParser
class ClassParser
{
private $fileManager;
@@ -65,45 +65,44 @@ class ClassParser
$this->allowedMethods = $methods;
}
/**
* Return path data of classes
*
* @param string $cacheFile full path for a cache file, ex. data/cache/application/entryPoints.php
* @param string | array $paths in format array(
* 'corePath' => '',
* 'modulePath' => '',
* 'customPath' => '',
* );
* @return array
* @return array
*/
public function getData($paths, $cacheFile = false)
{
{
$data = null;
if (is_string($paths)) {
$paths = array(
'corePath' => $paths,
);
'corePath' => $paths,
);
}
if ($cacheFile && file_exists($cacheFile) && $this->getConfig()->get('useCache')) {
$data = $this->getFileManager()->getContents($cacheFile);
} else {
} else {
$data = $this->getClassNameHash($paths['corePath']);
if (isset($paths['modulePath'])) {
foreach ($this->getMetadata()->getModuleList() as $moduleName) {
$path = str_replace('{*}', $moduleName, $paths['modulePath']);
$path = str_replace('{*}', $moduleName, $paths['modulePath']);
$data = array_merge($data, $this->getClassNameHash($path));
}
}
}
if (isset($paths['customPath'])) {
$data = array_merge($data, $this->getClassNameHash($paths['customPath']));
}
$data = array_merge($data, $this->getClassNameHash($paths['customPath']));
}
if ($cacheFile && $this->getConfig()->get('useCache')) {
$result = $this->getFileManager()->putContentsPHP($cacheFile, $data);
if ($result == false) {
@@ -114,36 +113,35 @@ class ClassParser
return $data;
}
protected function getClassNameHash($dirs)
{
if (is_string($dirs)) {
$dirs = (array) $dirs;
$dirs = (array) $dirs;
}
$data = array();
foreach ($dirs as $dir) {
foreach ($dirs as $dir) {
if (file_exists($dir)) {
$fileList = $this->getFileManager()->getFileList($dir, false, '\.php$', 'file');
$fileList = $this->getFileManager()->getFileList($dir, false, '\.php$', true);
foreach ($fileList as $file) {
foreach ($fileList as $file) {
$filePath = Util::concatPath($dir, $file);
$className = Util::getClassName($filePath);
$fileName = $this->getFileManager()->getFileName($filePath);
$fileName = ucfirst($fileName);
$className = Util::getClassName($filePath);
$fileName = $this->getFileManager()->getFileName($filePath);
$fileName = ucfirst($fileName);
foreach ($this->allowedMethods as $methodName) {
if (method_exists($className, $methodName)) {
foreach ($this->allowedMethods as $methodName) {
if (method_exists($className, $methodName)) {
$data[$fileName] = $className;
}
}
}
}
}
}
return $data;
}
}
+130 -32
View File
@@ -53,12 +53,12 @@ class Manager
* @param string $path string - Folder path, Ex. myfolder
* @param bool | int $recursively - Find files in subfolders
* @param string $filter - Filter for files. Use regular expression, Ex. \.json$
* @param string $fileType [all, file, dir] - Filter for type of files/directories.
* @param bool $onlyFileType [null, true, false] - Filter for type of files/directories. If TRUE - returns only file list, if FALSE - only directory list
* @param bool $isReturnSingleArray - if need to return a single array of file list
*
* @return array
*/
public function getFileList($path, $recursively=false, $filter='', $fileType='all', $isReturnSingleArray = false)
public function getFileList($path, $recursively = false, $filter = '', $onlyFileType = null, $isReturnSingleArray = false)
{
if (!file_exists($path)) {
return false;
@@ -69,20 +69,20 @@ class Manager
$cdir = scandir($path);
foreach ($cdir as $key => $value)
{
if (!in_array($value,array(".","..")))
if (!in_array($value,array(".", "..")))
{
$add= false;
$add = false;
if (is_dir($path . Utils\Util::getSeparator() . $value)) {
if ($recursively || (is_int($recursively) && $recursively!=0) ) {
$nextRecursively = is_int($recursively) ? ($recursively-1) : $recursively;
$result[$value] = $this->getFileList($path.Utils\Util::getSeparator().$value, $nextRecursively, $filter, $fileType);
$result[$value] = $this->getFileList($path . Utils\Util::getSeparator() . $value, $nextRecursively, $filter, $onlyFileType);
}
else if (in_array($fileType, array('all', 'dir'))){
$add= true;
else if (!isset($onlyFileType) || !$onlyFileType){ /*save only directories*/
$add = true;
}
}
else if (in_array($fileType, array('all', 'file'))) {
$add= true;
else if (!isset($onlyFileType) || $onlyFileType) { /*save only files*/
$add = true;
}
if ($add) {
@@ -100,7 +100,7 @@ class Manager
}
if ($isReturnSingleArray) {
return $this->getSingeFileList($result);
return $this->getSingeFileList($result, $onlyFileType);
}
return $result;
@@ -110,20 +110,31 @@ class Manager
* Convert file list to a single array
*
* @param aray $fileList
* @param bool $onlyFileType [null, true, false] - Filter for type of files/directories.
* @param string $parentDirName
*
* @return aray
*/
protected function getSingeFileList(array $fileList, $parentDirName = '')
protected function getSingeFileList(array $fileList, $onlyFileType = null, $parentDirName = '')
{
$singleFileList = array();
foreach($fileList as $dirName => $fileName) {
if (is_array($fileName)) {
$currentDir = Utils\Util::concatPath($parentDirName, $dirName);
$singleFileList = array_merge($singleFileList, $this->getSingeFileList($fileName, $currentDir));
$currentDir = Utils\Util::concatPath($parentDirName, $dirName);
if (!isset($onlyFileType) || $onlyFileType == $this->isFile($currentDir)) {
$singleFileList[] = $currentDir;
}
$singleFileList = array_merge($singleFileList, $this->getSingeFileList($fileName, $onlyFileType, $currentDir));
} else {
$singleFileList[] = Utils\Util::concatPath($parentDirName, $fileName);
$currentFileName = Utils\Util::concatPath($parentDirName, $fileName);
if (!isset($onlyFileType) || $onlyFileType == $this->isFile($currentFileName)) {
$singleFileList[] = $currentFileName;
}
}
}
@@ -381,7 +392,7 @@ class Manager
}
}
} else {
$fileList = is_file($sourcePath) ? (array) $sourcePath : $this->getFileList($sourcePath, $recursively, '', 'file', true);
$fileList = is_file($sourcePath) ? (array) $sourcePath : $this->getFileList($sourcePath, $recursively, '', true, true);
}
/** Check permission before copying */
@@ -419,7 +430,9 @@ class Manager
$sourceFile = is_file($sourcePath) ? $sourcePath : $this->concatPaths(array($sourcePath, $file));
$destFile = $this->concatPaths(array($destPath, $file));
$res &= copy($sourceFile, $destFile);
if (file_exists($sourceFile)) {
$res &= copy($sourceFile, $destFile);
}
}
return $res;
@@ -459,7 +472,7 @@ class Manager
return false;
}
/**
* Remove file/files by given path
*
@@ -471,6 +484,22 @@ class Manager
return $this->removeFile($filePaths);
}
public function rmdir($dirPaths)
{
if (!is_array($dirPaths)) {
$dirPaths = (array) $dirPaths;
}
$result = true;
foreach ($dirPaths as $dirPath) {
if (is_dir($dirPath) && is_writable($dirPath)) {
$result &= rmdir($dirPath);
}
}
return (bool) $result;
}
/**
* Remove file/files by given path
*
@@ -523,12 +552,10 @@ class Manager
}
if ($removeWithDir) {
if (file_exists($dirPath)) {
rmdir($dirPath);
}
$result &= $this->rmdir($dirPath);
}
return $result;
return (bool) $result;
}
/**
@@ -538,7 +565,7 @@ class Manager
* @param string $dirPath
* @return boolean
*/
public function remove($items, $dirPath = null)
public function remove($items, $dirPath = null, $removeEmptyDirs = false)
{
if (!is_array($items)) {
$items = (array) $items;
@@ -551,13 +578,73 @@ class Manager
}
if (is_dir($item)) {
$result = $this->removeInDir($item, true);
$result &= $this->removeInDir($item, true);
} else {
$result = $this->removeFile($item);
$result &= $this->removeFile($item);
}
if ($removeEmptyDirs) {
$result &= $this->removeEmptyDirs($item);
}
}
return $result;
return (bool) $result;
}
/**
* Remove empty parent directories if they are empty
* @param string $path
* @return bool
*/
protected function removeEmptyDirs($path)
{
$parentDirName = $this->getParentDirName($path);
$res = true;
if ($this->isDirEmpty($parentDirName)) {
$res &= $this->rmdir($parentDirName);
$res &= $this->removeEmptyDirs($parentDirName);
}
return (bool) $res;
}
/**
* Check if $filename is file. If $filename doesn'ot exist, check by pathinfo
*
* @param string $filename
* @return boolean
*/
public function isFile($filename)
{
if (file_exists($filename)) {
return is_file($filename);
}
$fileExtension = pathinfo($filename, PATHINFO_EXTENSION);
if (!empty($fileExtension)) {
return true;
}
return false;
}
/**
* Check if directory is empty
* @param string $path
* @return boolean
*/
public function isDirEmpty($path)
{
if (is_dir($path)) {
$fileList = $this->getFileList($path, true);
if (is_array($fileList) && empty($fileList)) {
return true;
}
}
return false;
}
/**
@@ -588,7 +675,6 @@ class Manager
return end($exFileName);
}
/**
* Get a directory name from the path
*
@@ -597,17 +683,29 @@ class Manager
*
* @return array
*/
public function getDirName($path, $isFullPath = true)
public function getDirName($path, $isFullPath = true, $useIsDir = true)
{
$pathInfo = pathinfo($path);
$dirName = preg_replace('/\/$/i', '', $path);
$dirName = ($useIsDir && is_dir($dirName)) ? $dirName : pathinfo($dirName, PATHINFO_DIRNAME);
if (!$isFullPath) {
$pieces = explode('/', $pathInfo['dirname']);
return $pieces[count($pieces)-1];
$pieces = explode('/', $dirName);
$dirName = $pieces[count($pieces)-1];
}
return $pathInfo['dirname'];
return $dirName;
}
/**
* Get parent dir name/path
*
* @param string $path
* @param boolean $isFullPath
* @return string
*/
public function getParentDirName($path, $isFullPath = true)
{
return $this->getDirName($path, $isFullPath, false);
}
/**
+1 -1
View File
@@ -58,7 +58,7 @@ class Unifier
if (!empty($paths['modulePath'])) {
$customDir = strstr($paths['modulePath'], '{*}', true);
$dirList = $this->getFileManager()->getFileList($customDir, false, '', 'dir');
$dirList = $this->getFileManager()->getFileList($customDir, false, '', false);
foreach ($dirList as $dirName) {
$curPath = str_replace('{*}', $dirName, $paths['modulePath']);
@@ -67,7 +67,7 @@ class RotatingFileHandler extends StreamHandler
$filePattern = $this->getFilePattern();
$dirPath = $this->getFileManager()->getDirName($this->filename);
$logFiles = $this->getFileManager()->getFileList($dirPath, false, $filePattern, 'file');
$logFiles = $this->getFileManager()->getFileList($dirPath, false, $filePattern, true);
if (!empty($logFiles) && count($logFiles) > $this->maxFiles) {
+207 -8
View File
@@ -12,6 +12,7 @@ class ManagerTest extends \PHPUnit_Framework_TestCase
protected $objects;
protected $filesPath= 'tests/testData/FileManager';
protected $cachePath = 'tests/testData/cache/FileManager';
protected $reflection;
@@ -29,7 +30,6 @@ class ManagerTest extends \PHPUnit_Framework_TestCase
$this->object = NULL;
}
public function testGetFileName()
{
$this->assertEquals('Donwload', $this->object->getFileName('Donwload.php'));
@@ -47,7 +47,6 @@ class ManagerTest extends \PHPUnit_Framework_TestCase
$this->assertEquals($result, $this->object->getContents( array($this->filesPath, 'getContent/test.json') ));
}
public function testPutContents()
{
$testPath= $this->filesPath.'/setContent';
@@ -60,7 +59,6 @@ class ManagerTest extends \PHPUnit_Framework_TestCase
$this->assertTrue($this->object->putContents(array($testPath, 'test.json'), 'initial value'));
}
public function testConcatPaths()
{
$input = 'application/Espo/Resources/metadata/app/panel.json';
@@ -109,13 +107,14 @@ class ManagerTest extends \PHPUnit_Framework_TestCase
$this->assertEquals($result, $this->object->getDirName($input, false));
$input = 'application/Espo/Resources/metadata/entityDefs';
$result = 'metadata';
$result = 'entityDefs';
$this->assertEquals($result, $this->object->getDirName($input, false));
$input = 'application/Espo/Resources/metadata/entityDefs/';
$result = 'metadata';
$result = 'entityDefs';
$this->assertEquals($result, $this->object->getDirName($input, false));
//path doesn't exists. Be careful to use "/" at the beginning
$input = '/application/Espo/Resources/metadata/entityDefs';
$result = 'metadata';
$this->assertEquals($result, $this->object->getDirName($input, false));
@@ -123,8 +122,11 @@ class ManagerTest extends \PHPUnit_Framework_TestCase
$input = 'notRealPath/logs/espo.log';
$result = 'logs';
$this->assertEquals($result, $this->object->getDirName($input, false));
}
$input = 'tests/testData/FileManager/getContent';
$result = 'getContent';
$this->assertEquals($result, $this->object->getDirName($input, false));
}
public function testGetDirNameFullPath()
{
@@ -137,13 +139,14 @@ class ManagerTest extends \PHPUnit_Framework_TestCase
$this->assertEquals($result, $this->object->getDirName($input));
$input = 'application/Espo/Resources/metadata/entityDefs';
$result = 'application/Espo/Resources/metadata';
$result = 'application/Espo/Resources/metadata/entityDefs';
$this->assertEquals($result, $this->object->getDirName($input));
$input = 'application/Espo/Resources/metadata/entityDefs/';
$result = 'application/Espo/Resources/metadata';
$result = 'application/Espo/Resources/metadata/entityDefs';
$this->assertEquals($result, $this->object->getDirName($input));
//path doesn't exists. Be careful to use "/" at the beginning
$input = '/application/Espo/Resources/metadata/entityDefs';
$result = '/application/Espo/Resources/metadata';
$this->assertEquals($result, $this->object->getDirName($input));
@@ -151,6 +154,10 @@ class ManagerTest extends \PHPUnit_Framework_TestCase
$input = 'notRealPath/logs/espo.log';
$result = 'notRealPath/logs';
$this->assertEquals($result, $this->object->getDirName($input));
$input = 'tests/testData/FileManager/getContent';
$result = 'tests/testData/FileManager/getContent';
$this->assertEquals($result, $this->object->getDirName($input, true));
}
public function testUnsetContents()
@@ -167,6 +174,198 @@ class ManagerTest extends \PHPUnit_Framework_TestCase
$this->assertJsonStringEqualsJsonFile($testPath, $result);
}
public function testIsDirEmpty()
{
$this->assertFalse($this->object->isDirEmpty('application'));
$this->assertFalse($this->object->isDirEmpty('tests/Espo'));
$this->assertFalse($this->object->isDirEmpty('tests/Espo/Core/Utils/File'));
$dirPath = 'tests/testData/cache/EmptyDir';
if (file_exists($dirPath) || mkdir($dirPath, 0755)) {
$this->assertTrue($this->object->isDirEmpty($dirPath));
}
}
public function testGetParentDirName()
{
$input = 'application/Espo/Resources/metadata/entityDefs';
$result = 'metadata';
$this->assertEquals($result, $this->object->getParentDirName($input, false));
$input = 'application/Espo/Resources/metadata/entityDefs/';
$result = 'metadata';
$this->assertEquals($result, $this->object->getParentDirName($input, false));
//path doesn't exists. Be careful to use "/" at the beginning
$input = '/application/Espo/Resources/metadata/entityDefs';
$result = 'metadata';
$this->assertEquals($result, $this->object->getParentDirName($input, false));
//path doesn't exists. Be careful to use "/" at the beginning
$input = '/application/Espo/Resources/metadata/entityDefs';
$result = '/application/Espo/Resources/metadata';
$this->assertEquals($result, $this->object->getParentDirName($input));
$input = 'notRealPath/logs/espo.log';
$result = 'notRealPath/logs';
$this->assertEquals($result, $this->object->getParentDirName($input));
$input = 'tests/testData/FileManager/getContent';
$result = 'tests/testData/FileManager';
$this->assertEquals($result, $this->object->getParentDirName($input, true));
}
public function testGetSingeFileListAll()
{
$input = array (
'custom' =>
array (
'Espo' =>
array (
'Custom' =>
array (
'Modules' =>
array (
'ExtensionTest' =>
array (
0 => 'File.json',
1 => 'File.php',
),
),
),
),
),
);
$result = array (
'custom',
'custom/Espo',
'custom/Espo/Custom',
'custom/Espo/Custom/Modules',
'custom/Espo/Custom/Modules/ExtensionTest',
'custom/Espo/Custom/Modules/ExtensionTest/File.json',
'custom/Espo/Custom/Modules/ExtensionTest/File.php',
);
$this->assertEquals($result, $this->reflection->invokeMethod('getSingeFileList', array($input)));
}
public function testGetSingeFileListOnlyFiles()
{
$input = array (
'custom' =>
array (
'Espo' =>
array (
'Custom' =>
array (
'Modules' =>
array (
'ExtensionTest' =>
array (
0 => 'File.json',
1 => 'File.php',
),
),
),
),
),
);
$result = array (
'custom/Espo/Custom/Modules/ExtensionTest/File.json',
'custom/Espo/Custom/Modules/ExtensionTest/File.php',
);
$this->assertEquals($result, $this->reflection->invokeMethod('getSingeFileList', array($input, true)));
}
public function testGetSingeFileListOnlyDirs()
{
$input = array (
'custom' =>
array (
'Espo' =>
array (
'Custom' =>
array (
'Modules' =>
array (
'ExtensionTest' =>
array (
0 => 'File.json',
1 => 'File.php',
),
),
),
),
),
);
$result = array (
'custom',
'custom/Espo',
'custom/Espo/Custom',
'custom/Espo/Custom/Modules',
'custom/Espo/Custom/Modules/ExtensionTest',
);
$this->assertEquals($result, $this->reflection->invokeMethod('getSingeFileList', array($input, false)));
}
public function fileListSets()
{
return array(
array( 'Set1', array(
'custom',
'custom/Espo',
'custom/Espo/Custom',
'custom/Espo/Custom/Modules',
'custom/Espo/Custom/Modules/TestModule',
'custom/Espo/Custom/Modules/TestModule/SubFolder',
'custom/Espo/Custom/Modules/TestModule/SubFolder/Tester.txt',
)
),
array( 'Set2', array(
'custom',
'custom/Espo',
'custom/Espo/Custom',
'custom/Espo/Custom/Resources',
'custom/Espo/Custom/Resources/metadata',
'custom/Espo/Custom/Resources/metadata/entityDefs',
'custom/Espo/Custom/Resources/metadata/entityDefs/Account.json',
)
),
array( 'Set3', array(
'custom',
'custom/test.file',
)
),
);
}
/**
* @dataProvider fileListSets
*/
public function testRemoveWithEmptyDirs($name, $result)
{
$path = 'tests/testData/FileManager/Remove/' . $name;
$cachePath = $this->cachePath . '/' . $name;
$fileList = array (
$cachePath . '/custom/Espo/Custom/Modules/ExtensionTest/File.json',
$cachePath . '/custom/Espo/Custom/Modules/ExtensionTest/File.php',
);
$res = $this->object->copy($path, $cachePath, true);
if ($res) {
$this->assertTrue($this->object->remove($fileList, null, true));
$this->assertEquals($result, $this->object->getFileList($cachePath, true, '', null, true));
}
}
}
@@ -0,0 +1 @@
["File.json"]
@@ -0,0 +1,3 @@
<?php
//File.php
@@ -0,0 +1,3 @@
<?php
//File.php
@@ -0,0 +1,9 @@
{
"fields": {
"customField": {
"type": "varchar",
"required": false,
"isCustom": true
}
}
}
@@ -0,0 +1,3 @@
<?php
//File.php