change instance
This commit is contained in:
Executable
+3
@@ -0,0 +1,3 @@
|
||||
data/logs/*
|
||||
/test.php
|
||||
/test2.php
|
||||
Executable
+10
@@ -0,0 +1,10 @@
|
||||
RewriteEngine On
|
||||
|
||||
# Some hosts may require you to use the `RewriteBase` directive.
|
||||
# If you need to use the `RewriteBase` directive, it should be the
|
||||
# absolute physical path to the directory that contains this htaccess file.
|
||||
#
|
||||
# RewriteBase /
|
||||
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteRule ^ index.php [QSA,L]
|
||||
Executable
+130
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
require_once('../bootstrap.php');
|
||||
|
||||
use \Espo\Utils\Api as Api,
|
||||
\Slim;
|
||||
|
||||
require 'vendor/Slim/Slim.php';
|
||||
\Slim\Slim::registerAutoloader();
|
||||
|
||||
//$app = new \Slim\Slim();
|
||||
|
||||
$app = new \Slim\Slim(array(
|
||||
'mode' => 'development'
|
||||
));
|
||||
$app->add(new Api\Auth());
|
||||
|
||||
$app->hook('slim.after.router', function () use (&$app) {
|
||||
$app->contentType('application/json');
|
||||
//$app->contentType('text/javascript');
|
||||
});
|
||||
|
||||
|
||||
//Setup routes
|
||||
$app->get('/', '\Espo\Utils\Api\Rest::main');
|
||||
|
||||
$app->get('/metadata/', '\Espo\Utils\Api\Rest::getMetadata');
|
||||
$app->put('/metadata/:type/:scope/', '\Espo\Utils\Api\Rest::putMetadata');
|
||||
|
||||
$app->get('/settings/', '\Espo\Utils\Api\Rest::getSettings')->conditions( array('auth' => false) );
|
||||
$app->map('/settings/', '\Espo\Utils\Api\Rest::patchSettings')->via('PATCH');
|
||||
//$app->get('/settings/', '\Espo\Utils\Api\Rest::getSettings')->conditions( array('auth' => false) );
|
||||
|
||||
$app->get('/:controller/layout/:name/', '\Espo\Utils\Api\Rest::getLayout');
|
||||
$app->map('/:controller/layout/:name/', '\Espo\Utils\Api\Rest::patchLayout')->via('PATCH');
|
||||
$app->put('/:controller/layout/:name/', '\Espo\Utils\Api\Rest::putLayout');
|
||||
|
||||
$app->get('/app/user/', '\Espo\Utils\Api\Rest::getAppUser');
|
||||
|
||||
|
||||
/*$app->put('/settings/', 'Rest::putSettings');
|
||||
|
||||
//$app->map('/hello/', 'Rest::putSettings')->via('PATCH');
|
||||
|
||||
$app->get('/app/user/', 'Rest::getUserPreferences');
|
||||
$app->map('/app/:action', 'Rest::appAction')->via('GET', 'POST');
|
||||
|
||||
$app->get('/metadata/:type/:scope/', 'Rest::getMetadata');
|
||||
$app->put('/metadata/:type/:scope/', 'Rest::putMetadata');
|
||||
$app->get('/metadata/:type/', 'Rest::getMetadataByType');
|
||||
|
||||
$app->get('/:controller/', 'Rest::getControllerList');
|
||||
$app->get('/:controller/:id/', 'Rest::getController');
|
||||
|
||||
$app->get('/:controller/layout/:type/', 'Rest::getLayout');
|
||||
|
||||
*/
|
||||
|
||||
|
||||
//$app->put('/:controller/layout/:type/', 'Rest::putLayout');
|
||||
//$app->map('/:controller/layout/:type/', 'Rest::patchLayout')->via('PATCH');
|
||||
|
||||
//$app->put('/:controller/layout/:type/', 'Rest::putLayout');
|
||||
|
||||
|
||||
/*$app->put( '/:controller/layout/:type/', function ($controller, $type) use ( $app ) {
|
||||
|
||||
|
||||
|
||||
$mysqli = new mysqli('localhost', 'root', '', 'projects_jet');
|
||||
|
||||
$query= "SELECT * FROM layouts
|
||||
WHERE controller='".$controller."' AND layout_type='".$type."' LIMIT 1";
|
||||
$result = $mysqli->query($query);
|
||||
$selectRow = $result->fetch_assoc();
|
||||
|
||||
$data = $app->request()->getBody();
|
||||
//$data = $app->request()->params('payload');
|
||||
//$dataFull = array_keys($dataPut);
|
||||
//$data= $dataFull[0];
|
||||
|
||||
|
||||
if (empty($selectRow)) {
|
||||
//insert
|
||||
$query= "INSERT INTO layouts (
|
||||
controller,
|
||||
layout_type,
|
||||
data
|
||||
)
|
||||
VALUES (
|
||||
'".$controller."',
|
||||
'".$type."',
|
||||
'".$data."'
|
||||
);";
|
||||
}
|
||||
else {
|
||||
$query= "UPDATE layouts SET data='".$data."'
|
||||
WHERE id='".$selectRow['id']."' ";
|
||||
//update
|
||||
}
|
||||
|
||||
$result = $mysqli->query($query);
|
||||
|
||||
echo $data;
|
||||
}); */
|
||||
|
||||
/*$app->map('/app/:action', 'appAction')->via('GET', 'POST');
|
||||
$app->get('/:controller/', 'getControllerList');
|
||||
$app->get('/:controller/:id/', 'getController');*/
|
||||
|
||||
/*
|
||||
// POST route
|
||||
$app->post('/post', function () {
|
||||
echo 'This is a POST route';
|
||||
});
|
||||
|
||||
// PUT route
|
||||
$app->put('/put', function () {
|
||||
echo 'This is a PUT route';
|
||||
});
|
||||
|
||||
// DELETE route
|
||||
$app->delete('/delete', function () {
|
||||
echo 'This is a DELETE route';
|
||||
});
|
||||
*/
|
||||
|
||||
$app->run();
|
||||
|
||||
?>
|
||||
Executable
+103
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
namespace Espo\Core;
|
||||
|
||||
use Doctrine\ORM\Tools\Setup,
|
||||
Espo\Utils\Doctrine\ORM\Mapping\Driver\EspoPHPDriver,
|
||||
Espo\Utils as Utils;
|
||||
|
||||
class Base
|
||||
{
|
||||
|
||||
/**
|
||||
* @var EntityManager of doctrine
|
||||
*/
|
||||
public $em;
|
||||
|
||||
/**
|
||||
* @var Object of Configurator
|
||||
*/
|
||||
public $utils;
|
||||
|
||||
/**
|
||||
* @var Object of Log
|
||||
*/
|
||||
public $log;
|
||||
|
||||
/**
|
||||
* @var Object of config
|
||||
*/
|
||||
public $config;
|
||||
|
||||
/**
|
||||
* @var Object of config
|
||||
*/
|
||||
public $currentUser;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
protected function __construct()
|
||||
{
|
||||
$this->config = $this->getUtils()->getObject('Configurator');
|
||||
$this->em = $this->getEntityManager();
|
||||
/*$doctrineConfig->em->getConfiguration()->getMetadataDriverImpl()->addPaths(array(
|
||||
"Modules"
|
||||
));*/
|
||||
|
||||
$this->log = $this->getUtils()->getObject('Log');
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the app
|
||||
*/
|
||||
public static function start()
|
||||
{
|
||||
return new Base();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create or get an EntityManager object
|
||||
*
|
||||
*/
|
||||
private function getEntityManager()
|
||||
{
|
||||
if (isset($this->em) && is_object($this->em)) {
|
||||
return $this->em;
|
||||
}
|
||||
|
||||
//EspoPHPDriver for Doctrine
|
||||
$devMode= !$this->config->get('useCache');
|
||||
$doctrineConfig = Setup::createConfiguration($devMode, null, null);
|
||||
$doctrineConfig->setMetadataDriverImpl(new EspoPHPDriver(
|
||||
array(
|
||||
$this->config->get('metadataConfig')->doctrineCache,
|
||||
$this->config->get('defaultsPath').'/doctrine/metadata'
|
||||
)
|
||||
));
|
||||
//END: EspoPHPDriver for Doctrine
|
||||
|
||||
$doctrineConn = (array) $this->config->get('database');
|
||||
|
||||
// obtaining the entity manager
|
||||
return \Doctrine\ORM\EntityManager::create($doctrineConn, $doctrineConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create or get a Configurator object
|
||||
*
|
||||
*/
|
||||
private function getUtils()
|
||||
{
|
||||
if (isset($this->utils) && is_object($this->utils)) {
|
||||
return $this->utils;
|
||||
}
|
||||
|
||||
return new Utils\BaseUtils();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
return array (
|
||||
'Espo\\Entities\\User' =>
|
||||
array (
|
||||
'table' => 'users',
|
||||
'type' => 'entity',
|
||||
'id' =>
|
||||
array (
|
||||
'id' =>
|
||||
array (
|
||||
'type' => 'string',
|
||||
'generator' =>
|
||||
array (
|
||||
'strategy' => 'UUID',
|
||||
),
|
||||
),
|
||||
),
|
||||
'fields' =>
|
||||
array (
|
||||
'username' =>
|
||||
array (
|
||||
'type' => 'string(30)',
|
||||
),
|
||||
'password' =>
|
||||
array (
|
||||
'type' => 'string(255)',
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
?>
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
[{
|
||||
"label":"Overview",
|
||||
"rows": [
|
||||
[{"name":"name"}]
|
||||
]
|
||||
}]
|
||||
@@ -0,0 +1,6 @@
|
||||
[{
|
||||
"label":"",
|
||||
"rows": [
|
||||
[{"name":"name"}]
|
||||
]
|
||||
}]
|
||||
+1
@@ -0,0 +1 @@
|
||||
["name"]
|
||||
@@ -0,0 +1 @@
|
||||
["name"]
|
||||
+1
@@ -0,0 +1 @@
|
||||
[{"name":"name","link":true,"width":"30"}]
|
||||
@@ -0,0 +1 @@
|
||||
[{"name":"name"},{"name":"email","type":"base","sortable":false,"params":{}},{"name":"city"}]
|
||||
@@ -0,0 +1 @@
|
||||
[{"name":"name","link":true,"width":"30"}]
|
||||
@@ -0,0 +1 @@
|
||||
["assignedUser", "teams"]
|
||||
@@ -0,0 +1 @@
|
||||
[]
|
||||
+1
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"name":"TestModuleName",
|
||||
"var1": {
|
||||
"subvar1":"subval1",
|
||||
"subvar2":"subval2"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"name":"TestModuleName",
|
||||
"var1": {
|
||||
"subvar1":"subval1",
|
||||
"subvar2":"subval2"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"name":"CustomTestModuleName",
|
||||
"var1": {
|
||||
"subvar1":"subval1",
|
||||
"subvar2":"subval2"
|
||||
}
|
||||
}
|
||||
Executable
+67
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
return array (
|
||||
'configPath' => 'application/config.php',
|
||||
'customPath' => 'application/Custom',
|
||||
'cachePath' => 'data/cache',
|
||||
'defaultsPath' => 'application/Espo/Core/defaults',
|
||||
'unsetFileName' => 'unset.json',
|
||||
|
||||
'metadataConfig' =>
|
||||
array (
|
||||
'name' => 'metadata',
|
||||
'cachePath' => 'data/cache/application',
|
||||
'corePath' => 'application/Espo/Metadata',
|
||||
'customPath' => 'application/Modules/{*}/Metadata',
|
||||
'doctrineCache' => 'data/cache/doctrine/metadata',
|
||||
),
|
||||
|
||||
'layoutConfig' =>
|
||||
array (
|
||||
'name' => 'layouts',
|
||||
'corePath' => 'application/Espo/Layouts',
|
||||
'customPath' => 'application/Modules/{*}/Layouts',
|
||||
),
|
||||
|
||||
'languageConfig' =>
|
||||
array (
|
||||
'name' => '{lang}',
|
||||
'cachePath' => 'data/cache/application/Language',
|
||||
'corePath' => 'application/Espo/Language',
|
||||
'customPath' => 'application/Modules/{*}/Language',
|
||||
),
|
||||
|
||||
'defaultPermissions' =>
|
||||
array (
|
||||
'dir' => '0775',
|
||||
'file' => '0664',
|
||||
'user' => '',
|
||||
'group' => '',
|
||||
),
|
||||
'dateFormat' => 'MM/DD/YYYY',
|
||||
'timeFormat' => 'HH:mm',
|
||||
'systemItems' =>
|
||||
array (
|
||||
'systemItems',
|
||||
'adminItems',
|
||||
'configPath',
|
||||
'cachePath',
|
||||
'metadataConfig',
|
||||
'layoutConfig',
|
||||
'languageConfig',
|
||||
'database',
|
||||
'customPath',
|
||||
'defaultsPath',
|
||||
'unsetFileName',
|
||||
'configPathFull',
|
||||
'configCustomPathFull',
|
||||
),
|
||||
'adminItems' =>
|
||||
array (
|
||||
'defaultPermissions',
|
||||
'logger',
|
||||
'devMode',
|
||||
),
|
||||
);
|
||||
|
||||
?>
|
||||
Executable
+122
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
|
||||
namespace Espo\Entities;
|
||||
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
|
||||
/**
|
||||
* @Entity(repositoryClass="BugRepository") @Table(name="bugs")
|
||||
*/
|
||||
class Bug
|
||||
{
|
||||
/**
|
||||
* @Id @Column(type="integer") @GeneratedValue
|
||||
*/
|
||||
protected $id;
|
||||
/**
|
||||
* @Column(type="string")
|
||||
*/
|
||||
protected $description;
|
||||
/**
|
||||
* @Column(type="datetime")
|
||||
*/
|
||||
protected $created;
|
||||
/**
|
||||
* @Column(type="string")
|
||||
*/
|
||||
protected $status;
|
||||
|
||||
/**
|
||||
* @ManyToOne(targetEntity="User", inversedBy="assignedBugs")
|
||||
*/
|
||||
protected $engineer;
|
||||
|
||||
/**
|
||||
* @ManyToOne(targetEntity="User", inversedBy="reportedBugs")
|
||||
*/
|
||||
protected $reporter;
|
||||
|
||||
/**
|
||||
* @ManyToMany(targetEntity="Product")
|
||||
*/
|
||||
protected $products;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->products = new ArrayCollection();
|
||||
}
|
||||
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getDescription()
|
||||
{
|
||||
return $this->description;
|
||||
}
|
||||
|
||||
public function setDescription($description)
|
||||
{
|
||||
$this->description = $description;
|
||||
}
|
||||
|
||||
public function setCreated(DateTime $created)
|
||||
{
|
||||
$this->created = $created;
|
||||
}
|
||||
|
||||
public function getCreated()
|
||||
{
|
||||
return $this->created;
|
||||
}
|
||||
|
||||
public function setStatus($status)
|
||||
{
|
||||
$this->status = $status;
|
||||
}
|
||||
|
||||
public function getStatus()
|
||||
{
|
||||
return $this->status;
|
||||
}
|
||||
|
||||
public function setEngineer($engineer)
|
||||
{
|
||||
$engineer->assignedToBug($this);
|
||||
$this->engineer = $engineer;
|
||||
}
|
||||
|
||||
public function setReporter($reporter)
|
||||
{
|
||||
$reporter->addReportedBug($this);
|
||||
$this->reporter = $reporter;
|
||||
}
|
||||
|
||||
public function getEngineer()
|
||||
{
|
||||
return $this->engineer;
|
||||
}
|
||||
|
||||
public function getReporter()
|
||||
{
|
||||
return $this->reporter;
|
||||
}
|
||||
|
||||
public function assignToProduct($product)
|
||||
{
|
||||
$this->products[] = $product;
|
||||
}
|
||||
|
||||
public function getProducts()
|
||||
{
|
||||
return $this->products;
|
||||
}
|
||||
|
||||
public function close()
|
||||
{
|
||||
$this->status = "CLOSE";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Executable
+47
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
// repositories/BugRepository.php
|
||||
|
||||
namespace Espo\Entities;
|
||||
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
|
||||
|
||||
class BugRepository extends EntityRepository
|
||||
{
|
||||
public function getRecentBugs($number = 30)
|
||||
{
|
||||
//$dql = "SELECT b, e, r FROM Bug b JOIN b.engineer e JOIN b.reporter r ORDER BY b.created DESC";
|
||||
$dql = "SELECT b FROM Bug b ORDER BY b.created DESC";
|
||||
|
||||
$query = $this->getEntityManager()->createQuery($dql);
|
||||
$query->setMaxResults($number);
|
||||
return $query->getResult();
|
||||
}
|
||||
|
||||
public function getRecentBugsArray($number = 30)
|
||||
{
|
||||
$dql = "SELECT b, e, r, p FROM Bug b JOIN b.engineer e ".
|
||||
"JOIN b.reporter r JOIN b.products p ORDER BY b.created DESC";
|
||||
$query = $this->getEntityManager()->createQuery($dql);
|
||||
$query->setMaxResults($number);
|
||||
return $query->getArrayResult();
|
||||
}
|
||||
|
||||
public function getUsersBugs($userId, $number = 15)
|
||||
{
|
||||
$dql = "SELECT b, e, r FROM Bug b JOIN b.engineer e JOIN b.reporter r ".
|
||||
"WHERE b.status = 'OPEN' AND e.id = ?1 OR r.id = ?1 ORDER BY b.created DESC";
|
||||
|
||||
return $this->getEntityManager()->createQuery($dql)
|
||||
->setParameter(1, $userId)
|
||||
->setMaxResults($number)
|
||||
->getResult();
|
||||
}
|
||||
|
||||
public function getOpenBugsByProduct()
|
||||
{
|
||||
$dql = "SELECT p.id, p.name, count(b.id) AS openBugs FROM Bug b ".
|
||||
"JOIN b.products p WHERE b.status = 'OPEN' GROUP BY p.id";
|
||||
return $this->getEntityManager()->createQuery($dql)->getScalarResult();
|
||||
}
|
||||
}
|
||||
Executable
+84
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
namespace Espo\Entities;
|
||||
|
||||
use Doctrine\Common\Collections\ArrayCollection,
|
||||
\Espo\Core as Core;
|
||||
|
||||
/**
|
||||
* @Entity @Table(name="users")
|
||||
*/
|
||||
class User extends Core\Base
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $username;
|
||||
protected $password;
|
||||
protected $isAdmin;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
//$this->reportedBugs = new ArrayCollection();
|
||||
//$this->assignedBugs = new ArrayCollection();
|
||||
}
|
||||
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getUsername()
|
||||
{
|
||||
return $this->username;
|
||||
}
|
||||
|
||||
public function getIsAdmin()
|
||||
{
|
||||
return $this->isAdmin;
|
||||
}
|
||||
|
||||
public function setName($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check user's credentials (NEED TO REWRITE)
|
||||
*/
|
||||
public function login($username, $password)
|
||||
{
|
||||
$dbUsername= 'admin';
|
||||
$dbPassword= '1';
|
||||
|
||||
if ($username==$dbUsername && $password==$dbPassword) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//NEED TO REWRITE
|
||||
public function isAdmin($username='')
|
||||
{
|
||||
if (empty($username)) {
|
||||
$username= $this->getUsername();
|
||||
}
|
||||
|
||||
if ( !isset($this->id) || empty($this->id) ) {
|
||||
global $base;
|
||||
return $base->em->getRepository('\Espo\Entities\User')->findOneBy(array('username' => $username))->getIsAdmin(); //$this->getEntityManager()
|
||||
}
|
||||
|
||||
if ($this->getUsername() == $username) {
|
||||
return $this->getIsAdmin();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Executable
+1
@@ -0,0 +1 @@
|
||||
{"theme":"default","language":"en"}
|
||||
+1
@@ -0,0 +1 @@
|
||||
[{"label":"MyLabel"}]
|
||||
+1
@@ -0,0 +1 @@
|
||||
[{"oldlabel":"MyLabeldddd","label":"MyLabel"}]
|
||||
Executable
+1
@@ -0,0 +1 @@
|
||||
[[{"name":"Opportunities","id":1},{"name":"Leads","id":2},{"name":"OpportunitiesByStatus","id":5}],[{"name":"Calendar","id":3},{"name":"Tasks","id":4}]]
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
[{
|
||||
"label": "Locale",
|
||||
"rows": [
|
||||
[{"name": "dateFormat"}, {"name": "timeFormat"}],
|
||||
[{"name": "timeZone"}, {"name": "weekStart"}],
|
||||
[{"name": "defaultCurrency"}],
|
||||
[{"name": "thousandSeparator"}, {"name": "decimalMark"}]
|
||||
]
|
||||
}]
|
||||
+1
@@ -0,0 +1 @@
|
||||
["users", "teams"]
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
[
|
||||
{
|
||||
"label": "SMTP",
|
||||
"rows": [
|
||||
[{"name": "smtpServer"}, {"name": "smtpPort"}],
|
||||
[{"name": "smtpAuth"}, {"name": "smtpSecurity"}],
|
||||
[{"name": "smtpUsername"}],
|
||||
[{"name": "smtpPassword"}]
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "Configuration",
|
||||
"rows": [
|
||||
[{"name": "outboundEmailFromName"}, {"name": "outboundEmailFromAddress"}],
|
||||
[{"name": "outboundEmailIsShared"}]
|
||||
]
|
||||
}
|
||||
]
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
[
|
||||
{
|
||||
"label": "System",
|
||||
"rows": [
|
||||
[{"name": "useCache"}]
|
||||
]
|
||||
},{
|
||||
"label": "Locale",
|
||||
"rows": [
|
||||
[{"name": "dateFormat"}, {"name": "timeZone"}],
|
||||
[{"name": "timeFormat"}, {"name": "weekStart"}],
|
||||
[{"name": "thousandSeparator"}, {"name": "decimalMark"}],
|
||||
[{"name": "defaultCurrency"}, {"name": "currencyList"}]
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,9 @@
|
||||
[
|
||||
{
|
||||
"label": "Configuration",
|
||||
"rows": [
|
||||
[{"name": "recordsPerPage"},{"name": "recordsPerPageSmall"}],
|
||||
[{"name": "tabList"},{"name": "quickCreateList"}]
|
||||
]
|
||||
}
|
||||
]
|
||||
+1
@@ -0,0 +1 @@
|
||||
["users"]
|
||||
Executable
+1
@@ -0,0 +1 @@
|
||||
[{"label":"Overview","rows":[[{"name":"userName"},{"name":"isAdmin"}],[{"name":"defaultTeam"},{"name":"title","0":false}],[{"name":"name"},{"name":"title"}],[{"name":"email"},{"name":"phone"}]]}]
|
||||
+1
@@ -0,0 +1 @@
|
||||
[{"label":"","rows":[[{"name":"name"}],[{"name":"userName"}],[{"name":"isAdmin"}],[{"name":"email"}]]}]
|
||||
Executable
+1
@@ -0,0 +1 @@
|
||||
["name","userName","email"]
|
||||
+1
@@ -0,0 +1 @@
|
||||
["title"]
|
||||
Executable
+1
@@ -0,0 +1 @@
|
||||
[{"name":"name","width":30,"link":true},{"name":"userName"},{"name":"email"}]
|
||||
Executable
+1
@@ -0,0 +1 @@
|
||||
[{"name":"name","width":30,"link":true},{"name":"userName"},{"name":"email"}]
|
||||
+1
@@ -0,0 +1 @@
|
||||
["teams","roles"]
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
{
|
||||
"system":{
|
||||
"label":"System",
|
||||
"items":[
|
||||
{
|
||||
"url":"#admin/settings",
|
||||
"label":"Settings",
|
||||
"description":"System settings of application."
|
||||
},
|
||||
{
|
||||
"url":"#admin/clear-cache",
|
||||
"label":"Clear Cache",
|
||||
"description":"Clear all server side cache."
|
||||
}
|
||||
]
|
||||
},
|
||||
"users":{
|
||||
"label":"Users",
|
||||
"items":[
|
||||
{
|
||||
"url":"#user",
|
||||
"label":"Users",
|
||||
"description":"Users management."
|
||||
},
|
||||
{
|
||||
"url":"#team",
|
||||
"label":"Teams",
|
||||
"description":"Teams management."
|
||||
},
|
||||
{
|
||||
"url":"#role",
|
||||
"label":"Roles",
|
||||
"description":"Roles management."
|
||||
}
|
||||
]
|
||||
},
|
||||
"email":{
|
||||
"label":"Email",
|
||||
"items":[
|
||||
{
|
||||
"url":"#admin/outbound-email",
|
||||
"label":"Outbound Emails",
|
||||
"description":"SMTP settings for outgoing emails."
|
||||
},
|
||||
{
|
||||
"url":"#inbound-email",
|
||||
"label":"Inbound Emails",
|
||||
"description":"Group IMAP email accouts. Email import and Email-to-Case."
|
||||
},
|
||||
{
|
||||
"url":"#email-template",
|
||||
"label":"Email Templates",
|
||||
"description":"Templates for outbound emails."
|
||||
}
|
||||
]
|
||||
},
|
||||
"data":{
|
||||
"label":"Data",
|
||||
"items":[
|
||||
{
|
||||
"url":"#admin/import",
|
||||
"label":"Import",
|
||||
"description":"Import data from CSV file."
|
||||
}
|
||||
]
|
||||
},
|
||||
"customization":{
|
||||
"label":"Customization",
|
||||
"items":[
|
||||
{
|
||||
"url":"#admin/layouts",
|
||||
"label":"Layout Manager",
|
||||
"description":"Customize layouts (list, detail, edit, search, mass update)."
|
||||
},
|
||||
{
|
||||
"url":"#admin/fields",
|
||||
"label":"Field Manager",
|
||||
"description":"Create new fields or customize existing ones."
|
||||
},
|
||||
{
|
||||
"url":"#admin/user-interface",
|
||||
"label":"User Interface",
|
||||
"description":"Configure UI."
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
Executable
+35
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"type":"entity",
|
||||
"manyToOne":{
|
||||
"reporter":{
|
||||
"inversedBy":"reportedBugs",
|
||||
"targetEntity":"Espo\\Entities\\User"
|
||||
},
|
||||
"engineer":{
|
||||
"inversedBy":"assignedBugs",
|
||||
"targetEntity":"Espo\\Entities\\User"
|
||||
}
|
||||
},
|
||||
"fields":{
|
||||
"status":{
|
||||
"type":"string"
|
||||
},
|
||||
"description":{
|
||||
"type":"text"
|
||||
},
|
||||
"created":{
|
||||
"type":"datetime"
|
||||
}
|
||||
},
|
||||
"repositoryClass":"BugRepository",
|
||||
"table":"bugs",
|
||||
"id":{
|
||||
"id":{
|
||||
"type":"string",
|
||||
"generator":{
|
||||
"strategy":"UUID"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Executable
+26
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"table":"users",
|
||||
"type":"entity",
|
||||
"id":{
|
||||
"id":{
|
||||
"type":"string",
|
||||
"generator":{
|
||||
"strategy":"UUID"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fields":{
|
||||
"username":{
|
||||
"type":"string(30)"
|
||||
},
|
||||
"password":{
|
||||
"type":"string(255)"
|
||||
},
|
||||
"isAdmin":{
|
||||
"type":"boolean",
|
||||
"options":{
|
||||
"default":0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": {
|
||||
"type": "varchar",
|
||||
"required": true
|
||||
},
|
||||
"type": {
|
||||
"type": "varchar",
|
||||
"maxLength": 36
|
||||
},
|
||||
"size": {
|
||||
"type": "int",
|
||||
"min": 0
|
||||
},
|
||||
"extension": {
|
||||
"type": "varchar",
|
||||
"maxLength": 10
|
||||
},
|
||||
"parent": {
|
||||
"type": "linkParent"
|
||||
},
|
||||
"createdAt": {
|
||||
"type": "datetime",
|
||||
"readOnly": true
|
||||
},
|
||||
"modifiedAt": {
|
||||
"type": "datetime",
|
||||
"readOnly": true
|
||||
},
|
||||
"createdBy": {
|
||||
"type": "link",
|
||||
"readOnly": true
|
||||
},
|
||||
"modifiedBy": {
|
||||
"type": "link",
|
||||
"readOnly": true
|
||||
}
|
||||
},
|
||||
"links": {
|
||||
"createdBy": {
|
||||
"type": "belongsTo",
|
||||
"entity": "User"
|
||||
},
|
||||
"modifiedBy": {
|
||||
"type": "belongsTo",
|
||||
"entity": "User"
|
||||
},
|
||||
"parent": {
|
||||
"type": "belongsToParent",
|
||||
"foreign": "attachments"
|
||||
}
|
||||
},
|
||||
"collection": {
|
||||
"sortBy": "createdAt",
|
||||
"asc": false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"fields": {
|
||||
"message": {
|
||||
"type": "text"
|
||||
},
|
||||
"parent": {
|
||||
"type": "linkParent"
|
||||
},
|
||||
"attachments": {
|
||||
"type": "linkMultiple"
|
||||
},
|
||||
"createdAt": {
|
||||
"type": "datetime",
|
||||
"readOnly": true
|
||||
},
|
||||
"modifiedAt": {
|
||||
"type": "datetime",
|
||||
"readOnly": true
|
||||
},
|
||||
"createdBy": {
|
||||
"type": "link",
|
||||
"readOnly": true
|
||||
},
|
||||
"modifiedBy": {
|
||||
"type": "link",
|
||||
"readOnly": true
|
||||
}
|
||||
},
|
||||
"links": {
|
||||
"createdBy": {
|
||||
"type": "belongsTo",
|
||||
"entity": "User"
|
||||
},
|
||||
"modifiedBy": {
|
||||
"type": "belongsTo",
|
||||
"entity": "User"
|
||||
},
|
||||
"attachments": {
|
||||
"type": "hasChildren",
|
||||
"entity": "Attachment",
|
||||
"foreign": "parent"
|
||||
},
|
||||
"parent": {
|
||||
"type": "belongsToParent",
|
||||
"foreign": "attachments"
|
||||
}
|
||||
},
|
||||
"collection": {
|
||||
"sortBy": "createdAt",
|
||||
"asc": false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": {
|
||||
"type": "varchar",
|
||||
"required": true
|
||||
},
|
||||
"subject": {
|
||||
"type": "varchar",
|
||||
"required": true
|
||||
},
|
||||
"body": {
|
||||
"type": "text"
|
||||
},
|
||||
"isHtml": {
|
||||
"type": "bool",
|
||||
"default": true
|
||||
},
|
||||
"attachments": {
|
||||
"type": "linkMultiple"
|
||||
},
|
||||
"assignedUser": {
|
||||
"type": "link",
|
||||
"required": true,
|
||||
"default": "javascript: return {assignedUserId: this.getUser().id, assignedUserName: this.getUser().get(\"name\")};"
|
||||
},
|
||||
"teams": {
|
||||
"type": "linkMultiple"
|
||||
},
|
||||
"createdAt": {
|
||||
"type": "datetime",
|
||||
"readOnly": true
|
||||
},
|
||||
"modifiedAt": {
|
||||
"type": "datetime",
|
||||
"readOnly": true
|
||||
},
|
||||
"createdBy": {
|
||||
"type": "link",
|
||||
"readOnly": true
|
||||
},
|
||||
"modifiedBy": {
|
||||
"type": "link",
|
||||
"readOnly": true
|
||||
}
|
||||
},
|
||||
"links": {
|
||||
"attachments": {
|
||||
"type": "hasMany",
|
||||
"entity": "Attachment"
|
||||
},
|
||||
"teams": {
|
||||
"type": "hasMany",
|
||||
"entity": "Team"
|
||||
},
|
||||
"assignedUser": {
|
||||
"type": "belongsTo",
|
||||
"entity": "User"
|
||||
},
|
||||
"createdBy": {
|
||||
"type": "belongsTo",
|
||||
"entity": "User"
|
||||
},
|
||||
"modifiedBy": {
|
||||
"type": "belongsTo",
|
||||
"entity": "User"
|
||||
}
|
||||
},
|
||||
"collection": {
|
||||
"sortBy": "name",
|
||||
"asc": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"fields": {
|
||||
"timeZone": {
|
||||
"type": "enum"
|
||||
},
|
||||
"dateFormat": {
|
||||
"type": "enum",
|
||||
"options": ["MM/DD/YYYY", "YYYY-MM-DD", "DD.MM.YYYY"],
|
||||
"default": "MM/DD/YYYY"
|
||||
},
|
||||
"timeFormat": {
|
||||
"type": "enum",
|
||||
"options": ["HH:mm", "hh:mm A", "hh:mm a"],
|
||||
"default": "HH:mm"
|
||||
},
|
||||
"weekStart": {
|
||||
"type": "enum",
|
||||
"options": ["0", "1"],
|
||||
"default": 0
|
||||
},
|
||||
"thousandSeparator": {
|
||||
"type": "varchar",
|
||||
"default": ","
|
||||
},
|
||||
"decimalMark": {
|
||||
"type": "varchar",
|
||||
"default": ".",
|
||||
"required": true
|
||||
},
|
||||
"defaultCurrency": {
|
||||
"type": "enum",
|
||||
"default": "USD"
|
||||
}
|
||||
},
|
||||
"links": {
|
||||
"user": {
|
||||
"type": "belongsTo",
|
||||
"entity": "User"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": {
|
||||
"maxLength": 150,
|
||||
"required": true
|
||||
}
|
||||
},
|
||||
"links": {
|
||||
"users": {
|
||||
"type": "hasMany",
|
||||
"entity": "User"
|
||||
},
|
||||
"teams": {
|
||||
"type": "hasMany",
|
||||
"entity": "Team"
|
||||
}
|
||||
},
|
||||
"collection": {
|
||||
"sortBy": "name",
|
||||
"asc": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
{
|
||||
"fields": {
|
||||
"useCache": {
|
||||
"type": "bool",
|
||||
"default": true
|
||||
},
|
||||
"recordsPerPage": {
|
||||
"type": "int",
|
||||
"minValue": 1,
|
||||
"maxValue": 1000,
|
||||
"default": 20,
|
||||
"required": true
|
||||
},
|
||||
"recordsPerPageSmall": {
|
||||
"type": "int",
|
||||
"minValue": 1,
|
||||
"maxValue": 100,
|
||||
"default": 10,
|
||||
"required": true
|
||||
},
|
||||
"timeZone": {
|
||||
"type": "enum"
|
||||
},
|
||||
"dateFormat": {
|
||||
"type": "enum",
|
||||
"options": ["MM/DD/YYYY", "YYYY-MM-DD", "DD.MM.YYYY"],
|
||||
"default": "MM/DD/YYYY"
|
||||
},
|
||||
"timeFormat": {
|
||||
"type": "enum",
|
||||
"options": ["HH:mm", "hh:mm A", "hh:mm a"],
|
||||
"default": "HH:mm"
|
||||
},
|
||||
"weekStart": {
|
||||
"type": "enum",
|
||||
"options": ["0", "1"],
|
||||
"default": "1"
|
||||
},
|
||||
"thousandSeparator": {
|
||||
"type": "varchar",
|
||||
"default": ","
|
||||
},
|
||||
"decimalMark": {
|
||||
"type": "varchar",
|
||||
"default": ".",
|
||||
"required": true
|
||||
},
|
||||
"currencyList": {
|
||||
"type": "array",
|
||||
"default": ["USD", "EUR"],
|
||||
"required": true
|
||||
},
|
||||
"defaultCurrency": {
|
||||
"type": "enum",
|
||||
"default": "USD",
|
||||
"required": true
|
||||
},
|
||||
"outboundEmailIsShared": {
|
||||
"type": "bool",
|
||||
"default": false
|
||||
},
|
||||
"outboundEmailFromName": {
|
||||
"type": "varchar",
|
||||
"default": "EspoCRM",
|
||||
"required": true
|
||||
},
|
||||
"outboundEmailFromAddress": {
|
||||
"type": "varchar",
|
||||
"default": "crm@example.com",
|
||||
"required": true
|
||||
},
|
||||
"smtpServer": {
|
||||
"type": "varchar",
|
||||
"required": true
|
||||
},
|
||||
"smtpPort": {
|
||||
"type": "int",
|
||||
"required": true,
|
||||
"min": 0,
|
||||
"max": 9999,
|
||||
"default": 25
|
||||
},
|
||||
"smtpAuth": {
|
||||
"type": "bool",
|
||||
"default": true
|
||||
},
|
||||
"smtpSecurity": {
|
||||
"type": "enum",
|
||||
"options": ["", "SSL", "TLS"]
|
||||
},
|
||||
"smtpUsername": {
|
||||
"type": "varchar",
|
||||
"required": true
|
||||
},
|
||||
"smtpPassword": {
|
||||
"type": "password"
|
||||
},
|
||||
"tabList": {
|
||||
"type": "array",
|
||||
"default": ["Account", "Contact", "Lead", "Opportunity", "Calendar", "Meeting", "Call", "Task", "Case", "Prospect"]
|
||||
},
|
||||
"quickCreateList": {
|
||||
"type": "array",
|
||||
"default": ["Account", "Contact", "Lead", "Opportunity", "Meeting", "Call", "Task", "Case", "Prospect"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"fields": {
|
||||
"name": {
|
||||
"type": "varchar",
|
||||
"maxLength": 100
|
||||
},
|
||||
"roles": {
|
||||
"type": "linkMultiple"
|
||||
}
|
||||
},
|
||||
"links": {
|
||||
"users": {
|
||||
"type": "hasMany",
|
||||
"entity": "User"
|
||||
},
|
||||
"roles": {
|
||||
"type": "hasMany",
|
||||
"entity": "Role"
|
||||
}
|
||||
},
|
||||
"collection": {
|
||||
"sortBy": "name",
|
||||
"asc": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
{
|
||||
"fields": {
|
||||
"isAdmin": {
|
||||
"type": "bool"
|
||||
},
|
||||
"userName": {
|
||||
"type": "varchar",
|
||||
"maxLength": 50,
|
||||
"required": true
|
||||
},
|
||||
"name": {
|
||||
"type": "personName"
|
||||
},
|
||||
"salutationName": {
|
||||
"type": "enum",
|
||||
"options": ["", "Mr.", "Mrs.", "Dr.", "Drs."]
|
||||
},
|
||||
"firstName": {
|
||||
"type": "varchar",
|
||||
"maxLength": 100
|
||||
},
|
||||
"lastName": {
|
||||
"type": "varchar",
|
||||
"maxLength": 100,
|
||||
"required": true
|
||||
},
|
||||
"title": {
|
||||
"type": "varchar",
|
||||
"maxLength": 100
|
||||
},
|
||||
"email": {
|
||||
"type": "email",
|
||||
"required": true
|
||||
},
|
||||
"phone": {
|
||||
"type": "phone",
|
||||
"maxLength": 50
|
||||
},
|
||||
"defaultTeam": {
|
||||
"type": "link"
|
||||
},
|
||||
"teams": {
|
||||
"type": "linkMultiple"
|
||||
},
|
||||
"roles": {
|
||||
"type": "linkMultiple"
|
||||
}
|
||||
},
|
||||
"links": {
|
||||
"defaultTeam": {
|
||||
"type": "belongsTo",
|
||||
"entity": "Team"
|
||||
},
|
||||
"teams": {
|
||||
"type": "hasMany",
|
||||
"entity": "Team"
|
||||
},
|
||||
"roles": {
|
||||
"type": "hasMany",
|
||||
"entity": "Role"
|
||||
},
|
||||
"preferences": {
|
||||
"type": "hasOne",
|
||||
"entity": "Preferences"
|
||||
}
|
||||
},
|
||||
"collection": {
|
||||
"sortBy": "name",
|
||||
"asc": true
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"actualFields":[
|
||||
"street",
|
||||
"city",
|
||||
"state",
|
||||
"country",
|
||||
"postalCode"
|
||||
],
|
||||
"fields":{
|
||||
"street":{
|
||||
"type":"varchar"
|
||||
},
|
||||
"city":{
|
||||
"type":"varchar"
|
||||
},
|
||||
"state":{
|
||||
"type":"varchar"
|
||||
},
|
||||
"country":{
|
||||
"type":"varchar"
|
||||
},
|
||||
"postalCode":{
|
||||
"type":"varchar"
|
||||
}
|
||||
},
|
||||
"mergable":false,
|
||||
"search":{
|
||||
"basic":false,
|
||||
"advanced":true
|
||||
}
|
||||
}
|
||||
Executable
+21
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"params":[
|
||||
{
|
||||
"name":"required",
|
||||
"type":"bool",
|
||||
"default":false
|
||||
},
|
||||
{
|
||||
"name":"options",
|
||||
"type":"array"
|
||||
},
|
||||
{
|
||||
"name":"translation",
|
||||
"type":"varchar"
|
||||
}
|
||||
],
|
||||
"search":{
|
||||
"basic":false,
|
||||
"advanced":false
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"params":[
|
||||
],
|
||||
"search":{
|
||||
"basic":false,
|
||||
"advanced":true
|
||||
}
|
||||
}
|
||||
Executable
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"search":{
|
||||
"basic":false,
|
||||
"advanced":false
|
||||
}
|
||||
}
|
||||
Executable
+12
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"params":[
|
||||
{
|
||||
"name":"default",
|
||||
"type":"bool"
|
||||
}
|
||||
],
|
||||
"search":{
|
||||
"basic":false,
|
||||
"advanced":true
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"params":[
|
||||
{
|
||||
"name":"required",
|
||||
"type":"bool",
|
||||
"default":false
|
||||
},
|
||||
{
|
||||
"name":"min",
|
||||
"type":"float"
|
||||
},
|
||||
{
|
||||
"name":"max",
|
||||
"type":"float"
|
||||
}
|
||||
],
|
||||
"actualFields":[
|
||||
"currency",
|
||||
""
|
||||
],
|
||||
"search":{
|
||||
"basic":false,
|
||||
"advanced":true
|
||||
}
|
||||
}
|
||||
Executable
+21
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"params":[
|
||||
{
|
||||
"name":"required",
|
||||
"type":"bool",
|
||||
"default":false
|
||||
},
|
||||
{
|
||||
"name":"default",
|
||||
"type":"varchar"
|
||||
},
|
||||
{
|
||||
"name":"after",
|
||||
"type":"varchar"
|
||||
}
|
||||
],
|
||||
"search":{
|
||||
"basic":false,
|
||||
"advanced":true
|
||||
}
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"params":[
|
||||
{
|
||||
"name":"required",
|
||||
"type":"bool",
|
||||
"default":false
|
||||
},
|
||||
{
|
||||
"name":"default",
|
||||
"type":"varchar"
|
||||
},
|
||||
{
|
||||
"name":"after",
|
||||
"type":"varchar"
|
||||
}
|
||||
],
|
||||
"search":{
|
||||
"basic":false,
|
||||
"advanced":false
|
||||
}
|
||||
}
|
||||
Executable
+17
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"params":[
|
||||
{
|
||||
"name":"required",
|
||||
"type":"bool",
|
||||
"default":false
|
||||
},
|
||||
{
|
||||
"name":"maxLength",
|
||||
"type":"int"
|
||||
}
|
||||
],
|
||||
"search":{
|
||||
"basic":true,
|
||||
"advanced":true
|
||||
}
|
||||
}
|
||||
Executable
+25
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"params":[
|
||||
{
|
||||
"name":"required",
|
||||
"type":"bool",
|
||||
"default":false
|
||||
},
|
||||
{
|
||||
"name":"options",
|
||||
"type":"array"
|
||||
},
|
||||
{
|
||||
"name":"default",
|
||||
"type":"varchar"
|
||||
},
|
||||
{
|
||||
"name":"translation",
|
||||
"type":"varchar"
|
||||
}
|
||||
],
|
||||
"search":{
|
||||
"basic":false,
|
||||
"advanced":true
|
||||
}
|
||||
}
|
||||
Executable
+25
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"params":[
|
||||
{
|
||||
"name":"required",
|
||||
"type":"bool",
|
||||
"default":false
|
||||
},
|
||||
{
|
||||
"name":"default",
|
||||
"type":"float"
|
||||
},
|
||||
{
|
||||
"name":"min",
|
||||
"type":"float"
|
||||
},
|
||||
{
|
||||
"name":"max",
|
||||
"type":"float"
|
||||
}
|
||||
],
|
||||
"search":{
|
||||
"basic":false,
|
||||
"advanced":true
|
||||
}
|
||||
}
|
||||
Executable
+25
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"params":[
|
||||
{
|
||||
"name":"required",
|
||||
"type":"bool",
|
||||
"default":false
|
||||
},
|
||||
{
|
||||
"name":"default",
|
||||
"type":"int"
|
||||
},
|
||||
{
|
||||
"name":"min",
|
||||
"type":"int"
|
||||
},
|
||||
{
|
||||
"name":"max",
|
||||
"type":"int"
|
||||
}
|
||||
],
|
||||
"search":{
|
||||
"basic":false,
|
||||
"advanced":true
|
||||
}
|
||||
}
|
||||
Executable
+19
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"params":[
|
||||
{
|
||||
"name":"required",
|
||||
"type":"bool",
|
||||
"default":false
|
||||
}
|
||||
],
|
||||
"actualFields":[
|
||||
"id"
|
||||
],
|
||||
"notActualFields":[
|
||||
"name"
|
||||
],
|
||||
"search":{
|
||||
"basic":false,
|
||||
"advanced":true
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"params":[
|
||||
{
|
||||
"name":"required",
|
||||
"type":"bool",
|
||||
"default":false
|
||||
}
|
||||
],
|
||||
"actualFields":[
|
||||
"ids"
|
||||
],
|
||||
"notActualFields":[
|
||||
"names"
|
||||
],
|
||||
"search":{
|
||||
"basic":false,
|
||||
"advanced":true
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"params":[
|
||||
{
|
||||
"name":"required",
|
||||
"type":"bool",
|
||||
"default":false
|
||||
}
|
||||
],
|
||||
"actualFields":[
|
||||
"id",
|
||||
"type"
|
||||
],
|
||||
"notActualFields":[
|
||||
"name"
|
||||
],
|
||||
"search":{
|
||||
"basic":false,
|
||||
"advanced":true
|
||||
}
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"params":[
|
||||
{
|
||||
"name":"required",
|
||||
"type":"bool",
|
||||
"default":false
|
||||
},
|
||||
{
|
||||
"name":"options",
|
||||
"type":"array"
|
||||
},
|
||||
{
|
||||
"name":"translation",
|
||||
"type":"varchar"
|
||||
}
|
||||
],
|
||||
"search":{
|
||||
"basic":false,
|
||||
"advanced":false
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"params":[
|
||||
{
|
||||
"name":"required",
|
||||
"type":"bool",
|
||||
"default":false
|
||||
}
|
||||
],
|
||||
"search":{
|
||||
"basic":false,
|
||||
"advanced":false
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"actualFields":[
|
||||
"salutation",
|
||||
"first",
|
||||
"last"
|
||||
],
|
||||
"fields":{
|
||||
"salutation":{
|
||||
"type":"varchar"
|
||||
},
|
||||
"first":{
|
||||
"type":"enum"
|
||||
},
|
||||
"last":{
|
||||
"type":"varchar"
|
||||
}
|
||||
},
|
||||
"naming":"prefix",
|
||||
"mergable":false,
|
||||
"search":{
|
||||
"basic":true,
|
||||
"advanced":true
|
||||
}
|
||||
}
|
||||
Executable
+22
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"params":[
|
||||
{
|
||||
"name":"required",
|
||||
"type":"bool",
|
||||
"default":false
|
||||
},
|
||||
{
|
||||
"name":"default",
|
||||
"type":"varchar"
|
||||
},
|
||||
{
|
||||
"name":"maxLength",
|
||||
"type":"int",
|
||||
"defalut":50
|
||||
}
|
||||
],
|
||||
"search":{
|
||||
"basic":true,
|
||||
"advanced":true
|
||||
}
|
||||
}
|
||||
Executable
+17
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"params":[
|
||||
{
|
||||
"name":"required",
|
||||
"type":"bool",
|
||||
"default":false
|
||||
},
|
||||
{
|
||||
"name":"default",
|
||||
"type":"text"
|
||||
}
|
||||
],
|
||||
"search":{
|
||||
"basic":true,
|
||||
"advanced":true
|
||||
}
|
||||
}
|
||||
Executable
+21
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"params":[
|
||||
{
|
||||
"name":"required",
|
||||
"type":"bool",
|
||||
"default":false
|
||||
},
|
||||
{
|
||||
"name":"default",
|
||||
"type":"varchar"
|
||||
},
|
||||
{
|
||||
"name":"maxLength",
|
||||
"type":"int"
|
||||
}
|
||||
],
|
||||
"search":{
|
||||
"basic":true,
|
||||
"advanced":true
|
||||
}
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"params":[
|
||||
{
|
||||
"name":"required",
|
||||
"type":"bool",
|
||||
"default":false
|
||||
},
|
||||
{
|
||||
"name":"default",
|
||||
"type":"varchar"
|
||||
},
|
||||
{
|
||||
"name":"maxLength",
|
||||
"type":"int"
|
||||
}
|
||||
],
|
||||
"search":{
|
||||
"basic":true,
|
||||
"advanced":true
|
||||
}
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"entity":true,"layouts":false,"tab":false,"acl":false,"customizable":false}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"entity":true,"layouts":false,"tab":false,"acl":false,"customizable":false}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"entity": true,
|
||||
"layouts": false,
|
||||
"tab": false,
|
||||
"acl": true,
|
||||
"customizable":false
|
||||
}
|
||||
Executable
+1
@@ -0,0 +1 @@
|
||||
{"entity":true,"layouts":false,"tab":false,"acl":false,"customizable":false}
|
||||
Executable
+1
@@ -0,0 +1 @@
|
||||
{"entity":true,"layouts":false,"tab":false,"acl":false,"customizable":false}
|
||||
Executable
+1
@@ -0,0 +1 @@
|
||||
{"entity":true,"layouts":true,"tab":false,"acl":false,"customizable":true}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"menu":{
|
||||
"list":{
|
||||
"buttons":[
|
||||
{
|
||||
"label":"Create Email Template",
|
||||
"link":"#email-template/create",
|
||||
"style":"primary",
|
||||
"acl":"edit"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+27
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"recordViewMaps":{
|
||||
"detail":"Role.Record.Detail",
|
||||
"edit":"Role.Record.Edit",
|
||||
"editQuick":"Role.Record.Edit"
|
||||
},
|
||||
"relationshipPanels":{
|
||||
"users":{
|
||||
"create":false
|
||||
},
|
||||
"teams":{
|
||||
"create":false
|
||||
}
|
||||
},
|
||||
"menu":{
|
||||
"list":{
|
||||
"buttons":[
|
||||
{
|
||||
"label":"Create Role",
|
||||
"link":"#role/create",
|
||||
"style":"primary",
|
||||
"acl":"edit"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+7
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"relationshipPanels":{
|
||||
"users":{
|
||||
"create":false
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+19
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"recordViewMaps":{
|
||||
"detail":"User.Record.Detail",
|
||||
"edit":"User.Record.Edit",
|
||||
"editQuick":"User.Record.Edit"
|
||||
},
|
||||
"menu":{
|
||||
"list":{
|
||||
"buttons":[
|
||||
{
|
||||
"label":"Create User",
|
||||
"link":"#user/create",
|
||||
"style":"primary",
|
||||
"acl":"edit"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+66
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace Espo\Utils\Api;
|
||||
|
||||
use \Slim\Slim,
|
||||
\Espo\Entities as Entities;
|
||||
|
||||
class Auth extends \Slim\Middleware
|
||||
{
|
||||
protected $noAuthRoutes = array();
|
||||
|
||||
function __construct($noAuthRoutes = array())
|
||||
{
|
||||
$this->noAuthRoutes = $noAuthRoutes;
|
||||
|
||||
}
|
||||
|
||||
function call()
|
||||
{
|
||||
$req = $this->app->request();
|
||||
$res = $this->app->response();
|
||||
|
||||
$uri = $req->getResourceUri();
|
||||
$httpMethod = $req->getMethod();
|
||||
|
||||
/**
|
||||
* Check if user credentials are required for current route
|
||||
*/
|
||||
$routes= $this->app->router()->getMatchedRoutes($httpMethod, $uri);
|
||||
|
||||
if (!empty($routes[0])) {
|
||||
$routeConditions = $routes[0]->getConditions();
|
||||
if (isset($routeConditions['auth']) && $routeConditions['auth']===false) {
|
||||
$this->next->call();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$authKey = $req->headers('PHP_AUTH_USER');
|
||||
$authSec = $req->headers('PHP_AUTH_PW');
|
||||
|
||||
if ($authKey && $authSec) {
|
||||
|
||||
$User= new Entities\User();
|
||||
$app= $User->login($authKey, $authSec);
|
||||
|
||||
if($app){
|
||||
//set the current user
|
||||
global $base;
|
||||
$base->currentUser= $base->em->getRepository('\Espo\Entities\User')->findOneBy(array('username' => $authKey));
|
||||
//END: set the current user
|
||||
|
||||
$this->next->call();
|
||||
}else{
|
||||
$res->header('WWW-Authenticate', sprintf('Basic realm="%s"', $this->realm));
|
||||
$res->status(401);
|
||||
}
|
||||
} else {
|
||||
$res->header('WWW-Authenticate', sprintf('Basic realm="%s"', $this->realm));
|
||||
$res->status(401);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
Executable
+78
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
namespace Espo\Utils\Api;
|
||||
|
||||
use \Slim\Slim,
|
||||
\Espo\Utils as Utils;
|
||||
|
||||
|
||||
class Helper
|
||||
{
|
||||
|
||||
/**
|
||||
* Output the result
|
||||
*
|
||||
* @param mixed $data - JSON
|
||||
* @param string $error - error message
|
||||
* @param int $errorCode - error status code
|
||||
*
|
||||
* @return void - Only echo the result
|
||||
*/
|
||||
function output($data=null, $error='Error', $errorCode=500)
|
||||
{
|
||||
$app= Slim::getInstance();
|
||||
|
||||
//check if result is false
|
||||
if ($data === false) {
|
||||
global $base;
|
||||
$logMess= empty($error) ? 'result is not expected' : $error;
|
||||
$base->log->add('ERROR', 'API:'.$app->router()->getCurrentRoute()->getPattern().', Method: '.$app->router()->getCurrentRoute()->getCallable().', InputData: '.$app->request()->getBody().' - '.$logMess);
|
||||
|
||||
Utils\Api\Helper::displayError($error, $errorCode);
|
||||
}
|
||||
//END: check if result is false
|
||||
|
||||
//$json= new Utils\JSON();
|
||||
//$data= $json->isJSON($data) ? $data : $json->encode($data);
|
||||
|
||||
//Can be optimized to the manual selection of input data type
|
||||
/*if ($jsonEncode) {
|
||||
$data= Utils\JSON::encode($data);
|
||||
}*/
|
||||
|
||||
ob_clean();
|
||||
echo $data;
|
||||
$app->stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Output the error and stop app execution
|
||||
*
|
||||
* @static
|
||||
* @param string $text
|
||||
* @param int $statusCode
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function displayError($text, $statusCode=500)
|
||||
{
|
||||
$log= new Utils\Log();
|
||||
$log->add('INFO', 'Display Error: '.$text.', Code: '.$statusCode.' URL: '.$_SERVER['REQUEST_URI']);
|
||||
|
||||
if (class_exists('Slim\Slim', false)) {
|
||||
$app = Slim::getInstance();
|
||||
|
||||
$app->response()->status($statusCode);
|
||||
$app->response()->header('X-Status-Reason', $text);
|
||||
//$app->response()->header('X-Status-Reason', 'Fatal Error/Exception. Please check error log file for details.');
|
||||
$app->stop();
|
||||
}
|
||||
else {
|
||||
$log->add('INFO', 'Could not get Slim instance. It looks like a direct call (bypass API). URL: '.$_SERVER['REQUEST_URI']);
|
||||
die($text);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
Executable
+401
@@ -0,0 +1,401 @@
|
||||
<?php
|
||||
|
||||
namespace Espo\Utils\Api;
|
||||
|
||||
use \Slim\Slim,
|
||||
\Espo\Utils as Utils;
|
||||
|
||||
class Rest extends BaseUtils
|
||||
{
|
||||
|
||||
/**
|
||||
* @var string Layout folder path
|
||||
*/
|
||||
static $layoutPath= 'application/layouts';
|
||||
static $metadataPath= 'application/metadata';
|
||||
static $cachePath= 'data/cache';
|
||||
|
||||
static $exModules= array(
|
||||
'lead',
|
||||
);
|
||||
static $defaultResponce= array(
|
||||
'status' => 'OK',
|
||||
'responce' => 'default response',
|
||||
);
|
||||
|
||||
//DIRECTORY_SEPARATOR
|
||||
|
||||
|
||||
function main()
|
||||
{
|
||||
$template = <<<EOT
|
||||
<h1>Main Page of REST API!!!</h1>
|
||||
EOT;
|
||||
self::output($template);
|
||||
}
|
||||
|
||||
function appAction($action)
|
||||
{
|
||||
$returns= array('action' => $action);
|
||||
self::output(json_encode($returns));
|
||||
}
|
||||
|
||||
function getControllerList($controller)
|
||||
{
|
||||
$sugarRest= self::sugarConnect(true, $controller);
|
||||
|
||||
if (in_array($controller, self::$exModules)) {
|
||||
self::output(json_encode(self::$defaultResponce));
|
||||
}
|
||||
|
||||
$soap_params= array(
|
||||
'module_name'=>$controller,
|
||||
'fields'=>array(),
|
||||
);
|
||||
$fields= $sugarRest->call('get_module_fields', $soap_params);
|
||||
|
||||
$filter_fields= array_keys($fields['module_fields']);
|
||||
$controller_result= $sugarRest->getList($controller, $filter_fields, '', '0', '10');
|
||||
|
||||
self::output(json_encode($controller_result));
|
||||
}
|
||||
|
||||
function getController($controller, $id, $echo=1)
|
||||
{
|
||||
$sugarRest= self::sugarConnect(true, $controller);
|
||||
|
||||
if (in_array($controller, self::$exModules)) {
|
||||
self::output(json_encode(self::$defaultResponce));
|
||||
}
|
||||
|
||||
$where= " ".strtolower($controller).".id = '".$id."'";
|
||||
$soap_params= array(
|
||||
'module_name'=>$controller,
|
||||
'fields'=>array(),
|
||||
);
|
||||
$fields= $sugarRest->call('get_module_fields', $soap_params);
|
||||
|
||||
$filter_fields= array_keys($fields['module_fields']);
|
||||
$controller_result= $sugarRest->getList($controller, $filter_fields, $where, '0', '10');
|
||||
|
||||
if (!$echo) {
|
||||
return $controller_result;
|
||||
}
|
||||
|
||||
self::output(json_encode($controller_result));
|
||||
}
|
||||
|
||||
function getLayout($controller, $type, $echo=1)
|
||||
{
|
||||
if (!$data = self::getFromFile(self::$layoutPath, $controller, $type)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$echo) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
self::output($data);
|
||||
}
|
||||
|
||||
function putLayout($controller, $type)
|
||||
{
|
||||
$app= Slim::getInstance();
|
||||
$data = $app->request()->getBody();
|
||||
|
||||
if (self::saveToFile($data, self::$layoutPath, $controller, $type)) {
|
||||
self::output($data);
|
||||
}
|
||||
else {
|
||||
self::error('Layout Problem');
|
||||
}
|
||||
}
|
||||
|
||||
function patchLayout($controller, $type)
|
||||
{
|
||||
if (!$savedData = self::getFromFile(self::$layoutPath, $controller, $type)) {
|
||||
return false;
|
||||
}
|
||||
if (empty($savedData)) {
|
||||
$savedData= '{}';
|
||||
}
|
||||
$savedDataArray= json_decode($savedData, true);
|
||||
|
||||
$app= Slim::getInstance();
|
||||
$newData = $app->request()->getBody();
|
||||
|
||||
$newDataArray= json_decode($newData, true);
|
||||
|
||||
$data= json_encode(array_merge($savedDataArray, $newDataArray));
|
||||
|
||||
if (self::saveToFile($data, self::$layoutPath, $controller, $type)) {
|
||||
self::output($data);
|
||||
}
|
||||
else {
|
||||
self::error('Layout Problem');
|
||||
}
|
||||
}
|
||||
|
||||
//new
|
||||
function putMetadata($type, $scope)
|
||||
{
|
||||
$app= Slim::getInstance();
|
||||
$data = $app->request()->getBody();
|
||||
|
||||
//die('Here');
|
||||
|
||||
if (self::saveToFile($data, self::$metadataPath, $type, $scope)) {
|
||||
self::output($data);
|
||||
}
|
||||
else {
|
||||
self::error('Save Metadata Problem');
|
||||
}
|
||||
}
|
||||
|
||||
//new
|
||||
function getMetadata($type, $scope)
|
||||
{
|
||||
if (!$data = self::getFromFile(self::$metadataPath, $type, $scope)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
self::output($data);
|
||||
}
|
||||
|
||||
function getMetadataByType($type)
|
||||
{
|
||||
//$folderPath= implode('/', array(self::$metadataPath, $type));
|
||||
$folderPath= self::$metadataPath.'/'.$type;
|
||||
|
||||
require_once('include/FileManager/FileManager.php');
|
||||
$Files= new FileManager();
|
||||
|
||||
//check if cache metadata file exists
|
||||
$cacheFile= self::$cachePath .$Files->getSeparator(). $folderPath . $Files->getFileExt();
|
||||
if (file_exists($cacheFile)) {
|
||||
$data= $Files->getContent($cacheFile);
|
||||
self::output($data);
|
||||
}
|
||||
//END: check if cache metadata file exists
|
||||
|
||||
//merge matadata files
|
||||
$fileList= $Files->getFileList($folderPath, false);
|
||||
|
||||
$content= array();
|
||||
foreach($fileList as $fileName) {
|
||||
$fileContent= $Files->getContent($folderPath, $fileName);
|
||||
if ($fileContent) {
|
||||
$content[]= json_decode($fileContent);
|
||||
}
|
||||
}
|
||||
$data= json_encode($content);
|
||||
//END: merge matadata files
|
||||
|
||||
//save medatada to cache file
|
||||
$Files->setContent($data, $cacheFile);
|
||||
//END: save medatada to cache file
|
||||
|
||||
self::output($data);
|
||||
}
|
||||
|
||||
|
||||
function getUserPreferences()
|
||||
{
|
||||
$module= 'Users';
|
||||
$id= '1';
|
||||
|
||||
$user= self::getController($module, $id, false);
|
||||
|
||||
$userJson= json_encode($user['entry_list'][$id]);
|
||||
self::output('{"user":'.$userJson.',"preferences":{}}');
|
||||
}
|
||||
|
||||
function getSettings()
|
||||
{
|
||||
if (!$data = self::getFromFile(self::$layoutPath, 'app', 'settings')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
self::output($data);
|
||||
|
||||
/*$returns= array(
|
||||
'theme' => 'default',
|
||||
'language' => 'en',
|
||||
);
|
||||
|
||||
self::output(json_encode($returns));*/
|
||||
}
|
||||
|
||||
function putSettings()
|
||||
{
|
||||
$app= Slim::getInstance();
|
||||
$data = $app->request()->getBody();
|
||||
|
||||
if (self::saveToFile($data, self::$layoutPath, 'app', 'settings')) {
|
||||
self::output($data);
|
||||
}
|
||||
else {
|
||||
self::error('Saving Problem');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function sugarConnect($check=false, $controller='')
|
||||
{
|
||||
require_once('api/sugar.REST.php');
|
||||
$sugarRest= new sugarRest();
|
||||
|
||||
if ($check) {
|
||||
$modules= $sugarRest->modules();
|
||||
$modules= array_merge($modules, self::$exModules);
|
||||
|
||||
if (!in_array($controller, $modules)) {
|
||||
|
||||
$app= Slim::getInstance();
|
||||
$app->halt(404);
|
||||
|
||||
//echo json_encode(array('error'=>'---Module does not exist'));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return $sugarRest;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Save layout from the PUT request
|
||||
*
|
||||
* @param string $data JSON string
|
||||
* @param string $controller Ex. Accounts, Leads
|
||||
* @param string $type Layout type, ex. list, detail, edit
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
/*function saveLayoutToFile($data, $controller, $type)
|
||||
{
|
||||
$folderPath= self::$layoutPath.'/'.$controller;
|
||||
|
||||
if (!file_exists($folderPath)) {
|
||||
if (!mkdir($folderPath, 0775)) {
|
||||
self::error('Permission denied: unable to generate a folder on the server - '.$folderPath);
|
||||
}
|
||||
}
|
||||
|
||||
$filePath= $folderPath.'/'.$type;
|
||||
return file_put_contents($filePath, $data);
|
||||
}*/
|
||||
|
||||
|
||||
/**
|
||||
* Get layout from the saved file
|
||||
*
|
||||
* @param string $controller Ex. Accounts, Leads
|
||||
* @param string $type Layout type, ex. list, detail, edit
|
||||
*
|
||||
* @return string JSON string
|
||||
*/
|
||||
/*function getLayoutFromFile($controller, $type)
|
||||
{
|
||||
$filePath= self::$layoutPath.'/'.$controller.'/'.$type;
|
||||
|
||||
if (file_exists($filePath)) {
|
||||
return file_get_contents($filePath);
|
||||
}
|
||||
|
||||
$filePath= self::$layoutPath.'/default/'.$type;
|
||||
if (file_exists($filePath)) {
|
||||
return file_get_contents($filePath);
|
||||
}
|
||||
|
||||
return false;
|
||||
} */
|
||||
|
||||
/**
|
||||
* Save content to file from the PUT request
|
||||
*
|
||||
* @param string $data JSON string
|
||||
* @param string $folderPath - Ex. layouts, metadata
|
||||
* @param string $folderName - Ex. Accounts, Leads, defs
|
||||
* @param string $fileName - Ex. list, detail, edit, contact.json
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function saveToFile($data, $folderPath, $folderName, $fileName)
|
||||
{
|
||||
$currentFolderPath= $folderPath.'/'.$folderName;
|
||||
if (empty($folderName)) {
|
||||
$currentFolderPath= $folderPath;
|
||||
}
|
||||
|
||||
if (!file_exists($currentFolderPath)) {
|
||||
if (!mkdir($currentFolderPath, 0775)) {
|
||||
self::error('Permission denied: unable to generate a folder on the server - '.$currentFolderPath);
|
||||
}
|
||||
}
|
||||
|
||||
$filePath= $currentFolderPath.'/'.$fileName;
|
||||
return file_put_contents($filePath, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get content from the saved file
|
||||
*
|
||||
* @param string $folderPath - Ex. layouts, metadata
|
||||
* @param string $folderName - Ex. Accounts, Leads, defs
|
||||
* @param string $fileName - Ex. list, detail, edit, contact.json
|
||||
*
|
||||
* @return string JSON string
|
||||
*/
|
||||
function getFromFile($folderPath, $folderName, $fileName)
|
||||
{
|
||||
$filePath= $folderPath.'/'.$folderName.'/'.$fileName;
|
||||
if (empty($folderName)) {
|
||||
$filePath= $folderPath.'/'.$fileName;
|
||||
}
|
||||
|
||||
if (file_exists($filePath)) {
|
||||
return file_get_contents($filePath);
|
||||
}
|
||||
|
||||
$filePath= $folderPath.'/default/'.$fileName;
|
||||
if (file_exists($filePath)) {
|
||||
return file_get_contents($filePath);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function output($data, $jsonConvert=false)
|
||||
{
|
||||
ob_clean();
|
||||
if ($jsonConvert) {
|
||||
$data= json_encode($data);
|
||||
}
|
||||
echo $data;
|
||||
|
||||
$app= Slim::getInstance();
|
||||
$app->stop();
|
||||
}
|
||||
|
||||
function error($text)
|
||||
{
|
||||
self::output('{"error":{"text":'.$text.'}}');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
function appAction($action)
|
||||
{
|
||||
try {
|
||||
$returns= array('action' => $action);
|
||||
echo json_encode($returns);
|
||||
} catch(PDOException $e) {
|
||||
echo '{"error":{"text":'. $e->getMessage() .'}}';
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
?>
|
||||
Executable
+187
@@ -0,0 +1,187 @@
|
||||
<?php
|
||||
|
||||
namespace Espo\Utils\Api;
|
||||
|
||||
use \Slim\Slim,
|
||||
\Espo\Utils as Utils,
|
||||
\Espo\Utils\Api as Api;
|
||||
|
||||
|
||||
class Rest
|
||||
{
|
||||
|
||||
/**
|
||||
* Index page of API
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function main()
|
||||
{
|
||||
$template = <<<EOT
|
||||
<h1>Main Page of REST API!!!</h1>
|
||||
EOT;
|
||||
Api\Helper::output($template);
|
||||
}
|
||||
|
||||
public function getAppUser()
|
||||
{
|
||||
$data= '{"user":{"modified_by_name":"Administrator","created_by_name":"","id":"1","user_name":"admin","user_hash":"","system_generated_password":"0","pwd_last_changed":"","authenticate_id":"","sugar_login":"1","first_name":"","last_name":"Administrator","full_name":"Administrator","name":"Administrator","is_admin":"1","external_auth_only":"0","receive_notifications":"1","description":"","date_entered":"2013-06-13 12:18:44","date_modified":"2013-06-13 12:19:48","modified_user_id":"1","created_by":"","title":"Administrator","department":"","phone_home":"","phone_mobile":"","phone_work":"","phone_other":"","phone_fax":"","status":"Active","address_street":"","address_city":"","address_state":"","address_country":"","address_postalcode":"","UserType":"","deleted":"0","portal_only":"0","show_on_employees":"1","employee_status":"Active","messenger_id":"","messenger_type":"","reports_to_id":"","reports_to_name":"","email1":"test@letrium.com","email_link_type":"","is_group":"0","c_accept_status_fields":" ","m_accept_status_fields":" ","accept_status_id":"","accept_status_name":""},"preferences":{}}';
|
||||
return Api\Helper::output($data, 'Cannot login');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whole metadata
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getMetadata()
|
||||
{
|
||||
global $base;
|
||||
$devMode= !$base->config->get('useCache');
|
||||
|
||||
$metadata= new Utils\Metadata();
|
||||
$data= $metadata->getMetadata(true, $devMode);
|
||||
|
||||
return Api\Helper::output($data, 'Cannot reach metadata data');
|
||||
}
|
||||
|
||||
/**
|
||||
* Put the metadata
|
||||
* ex. metadata/menu/Account
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function putMetadata($type, $scope)
|
||||
{
|
||||
$app= Slim::getInstance();
|
||||
$data = $app->request()->getBody();
|
||||
|
||||
$metadata = new Utils\Metadata();
|
||||
$type = $metadata->toCamelCase($type); //convert to camel case view
|
||||
$result = $metadata->setMetadata($data, $type, $scope);
|
||||
|
||||
if ($result===false) {
|
||||
return self::output($result, 'Cannot save metadata data');
|
||||
}
|
||||
|
||||
$data= $metadata->getMetadata(true, true);
|
||||
return Api\Helper::output($data, 'Cannot get the metadata data');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whole settigs
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getSettings()
|
||||
{
|
||||
global $base;
|
||||
$config= new Utils\Configurator();
|
||||
|
||||
$isAdmin= false;
|
||||
if(isset($base->currentUser) && is_object($base->currentUser)) {
|
||||
$isAdmin= $base->currentUser->isAdmin();
|
||||
}
|
||||
|
||||
$data= $config->getJSON($isAdmin);
|
||||
|
||||
return Api\Helper::output($data, 'Cannot get settings');
|
||||
}
|
||||
|
||||
/**
|
||||
* Add or change settigs
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function patchSettings()
|
||||
{
|
||||
global $base;
|
||||
$config= new Utils\Configurator();
|
||||
|
||||
$isAdmin= false;
|
||||
if(isset($base->currentUser) && is_object($base->currentUser)) {
|
||||
$isAdmin= $base->currentUser->isAdmin();
|
||||
}
|
||||
|
||||
$app= Slim::getInstance();
|
||||
$data = $app->request()->getBody();
|
||||
|
||||
$result= $config->setJSON($data, $isAdmin);
|
||||
|
||||
if ($result===false) {
|
||||
return self::output($result, 'Cannot save settings');
|
||||
}
|
||||
|
||||
$data= $config->getJSON($isAdmin);
|
||||
return Api\Helper::output($data, 'Cannot get settings');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get requested layout
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getLayout($controller, $name)
|
||||
{
|
||||
$layout = new Utils\Layout();
|
||||
|
||||
$controller = $layout->toCamelCase($controller);
|
||||
$name = $layout->toCamelCase($name);
|
||||
$data = $layout->getLayout($controller, $name);
|
||||
|
||||
return Api\Helper::output($data, 'Cannot get this layout', 404);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add or change layout
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function patchLayout($controller, $name)
|
||||
{
|
||||
$app= Slim::getInstance();
|
||||
$data = $app->request()->getBody();
|
||||
|
||||
$layout= new Utils\Layout();
|
||||
$controller = $layout->toCamelCase($controller);
|
||||
$name = $layout->toCamelCase($name);
|
||||
$result= $layout->mergeLayout($data, $controller, $name);
|
||||
|
||||
if ($result === false) {
|
||||
Api\Helper::displayError('Saving error', 500);
|
||||
}
|
||||
|
||||
return Api\Helper::output($data, 'Cannot get layout');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add or change layout
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function putLayout($controller, $name)
|
||||
{
|
||||
$app= Slim::getInstance();
|
||||
$data = $app->request()->getBody();
|
||||
|
||||
$layout= new Utils\Layout();
|
||||
$controller = $layout->toCamelCase($controller);
|
||||
$name = $layout->toCamelCase($name);
|
||||
$result= $layout->setLayout($data, $controller, $name);
|
||||
|
||||
if ($result === false) {
|
||||
Api\Helper::displayError('Saving error', 500);
|
||||
}
|
||||
|
||||
return Api\Helper::output($data, 'Cannot get layout');
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
Executable
+193
@@ -0,0 +1,193 @@
|
||||
<?php
|
||||
|
||||
namespace Espo\Utils;
|
||||
|
||||
use Espo\Utils as Utils;
|
||||
|
||||
class BaseUtils
|
||||
{
|
||||
|
||||
function getObject($name)
|
||||
{
|
||||
if (isset($this->$name) && is_object($this->$name)) {
|
||||
return $this->$name;
|
||||
}
|
||||
|
||||
$fullName= 'Espo\\Utils\\'.$name;
|
||||
if (class_exists($fullName)) {
|
||||
$this->$name= new $fullName();
|
||||
return $this->$name;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get module name if it's a custom module or empty string for core entity
|
||||
*
|
||||
* @param string $entityName
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getScopeModuleName($entityName)
|
||||
{
|
||||
$scopeModuleMap= (array) $this->getObject('Configurator')->get('scopeModuleMap');
|
||||
|
||||
$lowerEntityName= strtolower($entityName);
|
||||
foreach($scopeModuleMap as $rowEntityName => $rowModuleName) {
|
||||
if ($lowerEntityName==strtolower($rowEntityName)) {
|
||||
return $rowModuleName;
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert name to Camel Case format
|
||||
* ex. camel-case to camelCase
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function toCamelCase($name, $capitaliseFirstChar=false)
|
||||
{
|
||||
if($capitaliseFirstChar) {
|
||||
$name[0] = strtoupper($name[0]);
|
||||
}
|
||||
$func = create_function('$c', 'return strtoupper($c[1]);');
|
||||
return preg_replace_callback('/-([a-z])/', $func, $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert name from Camel Case format.
|
||||
* ex. camelCase to camel-case
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function fromCamelCase($name)
|
||||
{
|
||||
$name[0] = strtolower($name[0]);
|
||||
$func = create_function('$c', 'return "-" . strtolower($c[1]);');
|
||||
return preg_replace_callback('/([A-Z])/', $func, $name);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Merge arrays (default PHP function is not suitable)
|
||||
*
|
||||
* @param array $array
|
||||
* @param array $mainArray - chief array (priority is same as for array_merge())
|
||||
* @return array
|
||||
*/
|
||||
function merge($array, $mainArray)
|
||||
{
|
||||
if (is_array($array) && !is_array($mainArray)) {
|
||||
return $array;
|
||||
} else if (!is_array($array) && is_array($mainArray)) {
|
||||
return $mainArray;
|
||||
} else if (!is_array($array) && !is_array($mainArray)) {
|
||||
return array();
|
||||
}
|
||||
|
||||
foreach($mainArray as $maKey => $maVal) {
|
||||
$found = false;
|
||||
foreach($array as $aKey => $aVal) {
|
||||
if ((string)$maKey == (string)$aKey){
|
||||
$found = true;
|
||||
if (is_array($maVal) && is_array($aVal)){
|
||||
$array[$maKey] = $this->merge($aVal, $maVal);
|
||||
}
|
||||
else {
|
||||
|
||||
if (is_array($aVal)){
|
||||
$array[$maKey] = $this->merge($aVal, array($maVal));
|
||||
}
|
||||
elseif (is_array($maVal)){
|
||||
$array[$maKey] = $this->merge(array($aVal), $maVal);
|
||||
}
|
||||
else {
|
||||
//merge logic
|
||||
if (!is_numeric($maKey)){
|
||||
$array[$maKey] = $maVal;
|
||||
}
|
||||
elseif (!in_array($maVal, $array)) {
|
||||
$array[] = $maVal;
|
||||
}
|
||||
//END: merge ligic
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
// add an item if key not found
|
||||
if (!$found){
|
||||
$array[$maKey] = $maVal;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return content of PHP file
|
||||
*
|
||||
* @param string $varName - name of variable which contains the content
|
||||
* @param array $content
|
||||
*
|
||||
* @return string | false
|
||||
*/
|
||||
function getPHPFormat($content)
|
||||
{
|
||||
if (empty($content)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return '<?php
|
||||
|
||||
return '.var_export($content, true).';
|
||||
|
||||
?>';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert array to object format recursively
|
||||
*
|
||||
* @param array $array
|
||||
* @return object
|
||||
*/
|
||||
function arrayToObject($array)
|
||||
{
|
||||
if (is_array($array)) {
|
||||
return (object) array_map(array($this, "arrayToObject"), $array);
|
||||
} else {
|
||||
return $array; // Return an object
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert object to array format recursively
|
||||
*
|
||||
* @param object $object
|
||||
* @return array
|
||||
*/
|
||||
function objectToArray($object)
|
||||
{
|
||||
if (is_object($object)) {
|
||||
$object = (array) $object;
|
||||
}
|
||||
|
||||
return is_array($object) ? array_map(array($this, "objectToArray"), $object) : $object;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
Executable
+206
@@ -0,0 +1,206 @@
|
||||
<?php
|
||||
|
||||
namespace Espo\Utils;
|
||||
use Espo\Utils as Utils;
|
||||
|
||||
class Configurator extends BaseUtils
|
||||
{
|
||||
/**
|
||||
* Path of system config file
|
||||
*
|
||||
* @access private
|
||||
* @var string
|
||||
*/
|
||||
private $systemConfigPath = 'application/Espo/Core/systemConfig.php';
|
||||
|
||||
/**
|
||||
* Array of admin items
|
||||
*
|
||||
* @access protected
|
||||
* @var array
|
||||
*/
|
||||
protected $adminItems= array();
|
||||
|
||||
|
||||
/**
|
||||
* Contains content of system config
|
||||
*
|
||||
* @access private
|
||||
* @var string
|
||||
*/
|
||||
private $lastConfigObj;
|
||||
|
||||
|
||||
/**
|
||||
* Get an option from system config
|
||||
*
|
||||
* @param string $name
|
||||
* @return string | array
|
||||
*/
|
||||
public function get($name)
|
||||
{
|
||||
$contentObj = $this->getConfig();
|
||||
|
||||
if (isset($contentObj->$name)) {
|
||||
return $contentObj->$name;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set an option to the system config
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $value
|
||||
* @return bool
|
||||
*/
|
||||
public function set($name, $value='')
|
||||
{
|
||||
if (Utils\JSON::isJSON($value)) {
|
||||
$value= Utils\JSON::decode($value);
|
||||
}
|
||||
|
||||
$content= array($name => $value);
|
||||
$status= $this->getObject('FileManager')->mergeContentPHP($content, $this->get('configPath'), '', true);
|
||||
$this->getConfig(true);
|
||||
|
||||
return $status;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set options from array
|
||||
*
|
||||
* @param array $values
|
||||
* @return bool
|
||||
*/
|
||||
public function setArray($values)
|
||||
{
|
||||
if (Utils\JSON::isJSON($values)) {
|
||||
$values= Utils\JSON::decode($values);
|
||||
}
|
||||
|
||||
if (!is_array($values)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$status= $this->getObject('FileManager')->mergeContentPHP($values, $this->get('configPath'), '', true);
|
||||
$this->getConfig(true);
|
||||
|
||||
return $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an Object of all configs
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
function getConfig($reload=false)
|
||||
{
|
||||
if (!$reload && isset($this->lastConfigObj) && !empty($this->lastConfigObj)) {
|
||||
return $this->lastConfigObj;
|
||||
}
|
||||
|
||||
$fileManager= $this->getObject('FileManager');
|
||||
$systemConfig= $fileManager->getContent($this->systemConfigPath);
|
||||
|
||||
$config= $fileManager->getContent($systemConfig['configPath']);
|
||||
if (empty($config)) {
|
||||
$this->getObject('Log')->add('FATAL', 'Check syntax or permission of your '.$systemConfig['configPath']);
|
||||
}
|
||||
|
||||
$this->lastConfigObj = $this->arrayToObject( $this->merge((array) $systemConfig, (array) $config) );
|
||||
$this->adminItems= $this->getRestrictItems();
|
||||
|
||||
return $this->lastConfigObj;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get JSON config acording to restrictions for a user
|
||||
*
|
||||
* @param $isAdmin
|
||||
* @return object
|
||||
*/
|
||||
public function getJSON($isAdmin=false, $encode=true)
|
||||
{
|
||||
$configObj = $this->getConfig();
|
||||
|
||||
$restrictedConfig= $configObj;
|
||||
foreach($this->getRestrictItems($isAdmin) as $name) {
|
||||
if (isset($restrictedConfig->$name)) {
|
||||
unset($restrictedConfig->$name);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$encode) {
|
||||
return $restrictedConfig;
|
||||
}
|
||||
|
||||
return Utils\JSON::encode( $this->objectToArray($restrictedConfig) );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set JSON data acording to restrictions for a user
|
||||
*
|
||||
* @param $isAdmin
|
||||
* @return bool
|
||||
*/
|
||||
//HERE
|
||||
public function setJSON($json, $isAdmin=false)
|
||||
{
|
||||
$decoded= Utils\JSON::decode($json, true);
|
||||
|
||||
$restrictItems= $this->getRestrictItems($isAdmin);
|
||||
|
||||
$values= array();
|
||||
foreach($decoded as $key => $item) {
|
||||
if (!in_array($key, $restrictItems)) {
|
||||
$values[$key]= $item;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->setArray($values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get admin items
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
function getRestrictItems($onlySystemItems=false)
|
||||
{
|
||||
if ($onlySystemItems) {
|
||||
return ((array) $this->getConfig()->systemItems);
|
||||
}
|
||||
|
||||
if (empty($this->adminItems)) {
|
||||
//$this->adminItems= array_merge( (array) $this->getConfig()->systemItems, (array) $this->getConfig()->adminItems );
|
||||
$this->adminItems= $this->merge( (array) $this->getConfig()->systemItems, (array) $this->getConfig()->adminItems );
|
||||
}
|
||||
|
||||
return $this->adminItems;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if an item is allowed to get and save
|
||||
*
|
||||
* @param $name
|
||||
* @param $isAdmin
|
||||
* @return bool
|
||||
*/
|
||||
protected function isAllowed($name, $isAdmin=false)
|
||||
{
|
||||
if (in_array($name, $this->getRestrictItems($isAdmin))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
Executable
+150
@@ -0,0 +1,150 @@
|
||||
<?php
|
||||
|
||||
namespace Espo\Utils;
|
||||
|
||||
use Espo\Utils as Utils;
|
||||
|
||||
class Datetime
|
||||
{
|
||||
protected $options;
|
||||
|
||||
/**
|
||||
* Get date in defined format
|
||||
*
|
||||
* @param string $format
|
||||
* @return object
|
||||
*/
|
||||
protected function date($format)
|
||||
{
|
||||
return date($format);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get time
|
||||
*
|
||||
* @param string $format
|
||||
* @return object
|
||||
*/
|
||||
public function getTime($format='')
|
||||
{
|
||||
if (empty($format)) {
|
||||
$format= $this->getTimeFormat();
|
||||
}
|
||||
|
||||
return $this->date($format);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get date
|
||||
*
|
||||
* @param string $format
|
||||
* @return object
|
||||
*/
|
||||
public function getDate($format='')
|
||||
{
|
||||
if (empty($format)) {
|
||||
$format= $this->getDateFormat();
|
||||
}
|
||||
|
||||
return $this->date($format);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get date in datetime format
|
||||
*
|
||||
* @param string $format
|
||||
* @return object
|
||||
*/
|
||||
public function getDatetime($format='')
|
||||
{
|
||||
if (empty($format)) {
|
||||
$format= $this->getDatetimeFormat();
|
||||
}
|
||||
|
||||
return $this->date($format);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Date format
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDateFormat()
|
||||
{
|
||||
return $this->getPhpDateFormat( $this->getOptions()->get('dateFormat') );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Time format
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTimeFormat()
|
||||
{
|
||||
return $this->getPhpDateFormat( $this->getOptions()->get('timeFormat') );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Datetime format
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDatetimeFormat()
|
||||
{
|
||||
return $this->getDateFormat().' '.$this->getTimeFormat();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert javascript to php date format
|
||||
* NEED TO CHANGE
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPhpDateFormat($jsFormat)
|
||||
{
|
||||
$rules = array(
|
||||
'YYYY' => 'Y',
|
||||
'MM' => 'm',
|
||||
'DD' => 'd',
|
||||
'HH' => 'H',
|
||||
'mm' => 'i',
|
||||
/*'dd' => 'd',
|
||||
'd' => 'j',
|
||||
'DD' => 'l',
|
||||
'o' => 'z',
|
||||
'MM' => 'F',
|
||||
'M' => 'M',
|
||||
'm' => 'n',
|
||||
'mm' => 'm',
|
||||
'yy' => 'Y',
|
||||
'y' => 'y',*/
|
||||
);
|
||||
|
||||
$pattern = array_keys($rules);
|
||||
$replace = array_values($rules);
|
||||
foreach($pattern as &$p) {
|
||||
$p = '/'.$p.'/';
|
||||
}
|
||||
|
||||
return preg_replace($pattern, $replace, $jsFormat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set options from the system config
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
function getOptions()
|
||||
{
|
||||
if (isset($this->options) && is_object($this->options)) {
|
||||
return $this->options;
|
||||
}
|
||||
|
||||
$this->options = new Utils\Configurator();
|
||||
|
||||
return $this->options;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,679 @@
|
||||
<?php
|
||||
|
||||
namespace Espo\Utils\Doctrine\ORM\Mapping\Driver;
|
||||
|
||||
use Doctrine\Common\Persistence\Mapping\ClassMetadata,
|
||||
Doctrine\Common\Persistence\Mapping\Driver\FileDriver,
|
||||
Doctrine\ORM\Mapping\MappingException;
|
||||
|
||||
|
||||
/**
|
||||
* The JsonDriver reads the mapping metadata from .json schema files.
|
||||
*
|
||||
* @since 2.0
|
||||
* @author Taras Machyshyn
|
||||
* @author YamlDriver (part of code was taken from YamlDriver)
|
||||
*/
|
||||
class EspoPHPDriver extends FileDriver
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
const DEFAULT_FILE_EXTENSION = '.php';
|
||||
|
||||
|
||||
public function __construct($locator, $fileExtension = self::DEFAULT_FILE_EXTENSION)
|
||||
{
|
||||
parent::__construct($locator, $fileExtension);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function loadMetadataForClass($className, ClassMetadata $metadata)
|
||||
{
|
||||
$element = $this->getElement($className);
|
||||
|
||||
if ($element['type'] == 'entity') {
|
||||
if (isset($element['repositoryClass'])) {
|
||||
$metadata->setCustomRepositoryClass($element['repositoryClass']);
|
||||
}
|
||||
if (isset($element['readOnly']) && $element['readOnly'] == true) {
|
||||
$metadata->markReadOnly();
|
||||
}
|
||||
} else if ($element['type'] == 'mappedSuperclass') {
|
||||
$metadata->setCustomRepositoryClass(
|
||||
isset($element['repositoryClass']) ? $element['repositoryClass'] : null
|
||||
);
|
||||
$metadata->isMappedSuperclass = true;
|
||||
} else {
|
||||
throw MappingException::classIsNotAValidEntityOrMappedSuperClass($className);
|
||||
}
|
||||
|
||||
// Evaluate root level properties
|
||||
$table = array();
|
||||
if (isset($element['table'])) {
|
||||
$table['name'] = $element['table'];
|
||||
}
|
||||
$metadata->setPrimaryTable($table);
|
||||
|
||||
// Evaluate named queries
|
||||
if (isset($element['namedQueries'])) {
|
||||
foreach ($element['namedQueries'] as $name => $queryMapping) {
|
||||
if (is_string($queryMapping)) {
|
||||
$queryMapping = array('query' => $queryMapping);
|
||||
}
|
||||
|
||||
if ( ! isset($queryMapping['name'])) {
|
||||
$queryMapping['name'] = $name;
|
||||
}
|
||||
|
||||
$metadata->addNamedQuery($queryMapping);
|
||||
}
|
||||
}
|
||||
|
||||
// Evaluate named native queries
|
||||
if (isset($element['namedNativeQueries'])) {
|
||||
foreach ($element['namedNativeQueries'] as $name => $mappingElement) {
|
||||
if (!isset($mappingElement['name'])) {
|
||||
$mappingElement['name'] = $name;
|
||||
}
|
||||
$metadata->addNamedNativeQuery(array(
|
||||
'name' => $mappingElement['name'],
|
||||
'query' => isset($mappingElement['query']) ? $mappingElement['query'] : null,
|
||||
'resultClass' => isset($mappingElement['resultClass']) ? $mappingElement['resultClass'] : null,
|
||||
'resultSetMapping' => isset($mappingElement['resultSetMapping']) ? $mappingElement['resultSetMapping'] : null,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// Evaluate sql result set mappings
|
||||
if (isset($element['sqlResultSetMappings'])) {
|
||||
foreach ($element['sqlResultSetMappings'] as $name => $resultSetMapping) {
|
||||
if (!isset($resultSetMapping['name'])) {
|
||||
$resultSetMapping['name'] = $name;
|
||||
}
|
||||
|
||||
$entities = array();
|
||||
$columns = array();
|
||||
if (isset($resultSetMapping['entityResult'])) {
|
||||
foreach ($resultSetMapping['entityResult'] as $entityResultElement) {
|
||||
$entityResult = array(
|
||||
'fields' => array(),
|
||||
'entityClass' => isset($entityResultElement['entityClass']) ? $entityResultElement['entityClass'] : null,
|
||||
'discriminatorColumn' => isset($entityResultElement['discriminatorColumn']) ? $entityResultElement['discriminatorColumn'] : null,
|
||||
);
|
||||
|
||||
if (isset($entityResultElement['fieldResult'])) {
|
||||
foreach ($entityResultElement['fieldResult'] as $fieldResultElement) {
|
||||
$entityResult['fields'][] = array(
|
||||
'name' => isset($fieldResultElement['name']) ? $fieldResultElement['name'] : null,
|
||||
'column' => isset($fieldResultElement['column']) ? $fieldResultElement['column'] : null,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$entities[] = $entityResult;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (isset($resultSetMapping['columnResult'])) {
|
||||
foreach ($resultSetMapping['columnResult'] as $columnResultAnnot) {
|
||||
$columns[] = array(
|
||||
'name' => isset($columnResultAnnot['name']) ? $columnResultAnnot['name'] : null,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$metadata->addSqlResultSetMapping(array(
|
||||
'name' => $resultSetMapping['name'],
|
||||
'entities' => $entities,
|
||||
'columns' => $columns
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/* not implemented specially anyway. use table = schema.table
|
||||
if (isset($element['schema'])) {
|
||||
$metadata->table['schema'] = $element['schema'];
|
||||
}*/
|
||||
|
||||
if (isset($element['inheritanceType'])) {
|
||||
$metadata->setInheritanceType(constant('Doctrine\ORM\Mapping\ClassMetadata::INHERITANCE_TYPE_' . strtoupper($element['inheritanceType'])));
|
||||
|
||||
if ($metadata->inheritanceType != \Doctrine\ORM\Mapping\ClassMetadata::INHERITANCE_TYPE_NONE) {
|
||||
// Evaluate discriminatorColumn
|
||||
if (isset($element['discriminatorColumn'])) {
|
||||
$discrColumn = $element['discriminatorColumn'];
|
||||
$metadata->setDiscriminatorColumn(array(
|
||||
'name' => isset($discrColumn['name']) ? (string)$discrColumn['name'] : null,
|
||||
'type' => isset($discrColumn['type']) ? (string)$discrColumn['type'] : null,
|
||||
'length' => isset($discrColumn['length']) ? (string)$discrColumn['length'] : null,
|
||||
'columnDefinition' => isset($discrColumn['columnDefinition']) ? (string)$discrColumn['columnDefinition'] : null
|
||||
));
|
||||
} else {
|
||||
$metadata->setDiscriminatorColumn(array('name' => 'dtype', 'type' => 'string', 'length' => 255));
|
||||
}
|
||||
|
||||
// Evaluate discriminatorMap
|
||||
if (isset($element['discriminatorMap'])) {
|
||||
$metadata->setDiscriminatorMap($element['discriminatorMap']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Evaluate changeTrackingPolicy
|
||||
if (isset($element['changeTrackingPolicy'])) {
|
||||
$metadata->setChangeTrackingPolicy(constant('Doctrine\ORM\Mapping\ClassMetadata::CHANGETRACKING_'
|
||||
. strtoupper($element['changeTrackingPolicy'])));
|
||||
}
|
||||
|
||||
// Evaluate indexes
|
||||
if (isset($element['indexes'])) {
|
||||
foreach ($element['indexes'] as $name => $index) {
|
||||
if ( ! isset($index['name'])) {
|
||||
$index['name'] = $name;
|
||||
}
|
||||
|
||||
if (is_string($index['columns'])) {
|
||||
$columns = explode(',', $index['columns']);
|
||||
$columns = array_map('trim', $columns);
|
||||
} else {
|
||||
$columns = $index['columns'];
|
||||
}
|
||||
|
||||
$metadata->table['indexes'][$index['name']] = array(
|
||||
'columns' => $columns
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Evaluate uniqueConstraints
|
||||
if (isset($element['uniqueConstraints'])) {
|
||||
foreach ($element['uniqueConstraints'] as $name => $unique) {
|
||||
if ( ! isset($unique['name'])) {
|
||||
$unique['name'] = $name;
|
||||
}
|
||||
|
||||
if (is_string($unique['columns'])) {
|
||||
$columns = explode(',', $unique['columns']);
|
||||
$columns = array_map('trim', $columns);
|
||||
} else {
|
||||
$columns = $unique['columns'];
|
||||
}
|
||||
|
||||
$metadata->table['uniqueConstraints'][$unique['name']] = array(
|
||||
'columns' => $columns
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($element['options'])) {
|
||||
$metadata->table['options'] = $element['options'];
|
||||
}
|
||||
|
||||
$associationIds = array();
|
||||
if (isset($element['id'])) {
|
||||
// Evaluate identifier settings
|
||||
foreach ($element['id'] as $name => $idElement) {
|
||||
if (isset($idElement['associationKey']) && $idElement['associationKey'] == true) {
|
||||
$associationIds[$name] = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
$mapping = array(
|
||||
'id' => true,
|
||||
'fieldName' => $name
|
||||
);
|
||||
|
||||
if (isset($idElement['type'])) {
|
||||
$mapping['type'] = $idElement['type'];
|
||||
}
|
||||
|
||||
if (isset($idElement['column'])) {
|
||||
$mapping['columnName'] = $idElement['column'];
|
||||
}
|
||||
|
||||
if (isset($idElement['length'])) {
|
||||
$mapping['length'] = $idElement['length'];
|
||||
}
|
||||
|
||||
if (isset($idElement['columnDefinition'])) {
|
||||
$mapping['columnDefinition'] = $idElement['columnDefinition'];
|
||||
}
|
||||
|
||||
$metadata->mapField($mapping);
|
||||
|
||||
if (isset($idElement['generator'])) {
|
||||
$metadata->setIdGeneratorType(constant('Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_'
|
||||
. strtoupper($idElement['generator']['strategy'])));
|
||||
}
|
||||
// Check for SequenceGenerator/TableGenerator definition
|
||||
if (isset($idElement['sequenceGenerator'])) {
|
||||
$metadata->setSequenceGeneratorDefinition($idElement['sequenceGenerator']);
|
||||
} else if (isset($idElement['customIdGenerator'])) {
|
||||
$customGenerator = $idElement['customIdGenerator'];
|
||||
$metadata->setCustomGeneratorDefinition(array(
|
||||
'class' => (string) $customGenerator['class']
|
||||
));
|
||||
} else if (isset($idElement['tableGenerator'])) {
|
||||
throw MappingException::tableIdGeneratorNotImplemented($className);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Evaluate fields
|
||||
if (isset($element['fields'])) {
|
||||
foreach ($element['fields'] as $name => $fieldMapping) {
|
||||
|
||||
$mapping = $this->columnToArray($name, $fieldMapping);
|
||||
|
||||
if (isset($fieldMapping['id'])) {
|
||||
$mapping['id'] = true;
|
||||
if (isset($fieldMapping['generator']['strategy'])) {
|
||||
$metadata->setIdGeneratorType(constant('Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_'
|
||||
. strtoupper($fieldMapping['generator']['strategy'])));
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($mapping['version'])) {
|
||||
$metadata->setVersionMapping($mapping);
|
||||
unset($mapping['version']);
|
||||
}
|
||||
|
||||
$metadata->mapField($mapping);
|
||||
}
|
||||
}
|
||||
|
||||
// Evaluate oneToOne relationships
|
||||
if (isset($element['oneToOne'])) {
|
||||
foreach ($element['oneToOne'] as $name => $oneToOneElement) {
|
||||
$mapping = array(
|
||||
'fieldName' => $name,
|
||||
'targetEntity' => $oneToOneElement['targetEntity']
|
||||
);
|
||||
|
||||
if (isset($associationIds[$mapping['fieldName']])) {
|
||||
$mapping['id'] = true;
|
||||
}
|
||||
|
||||
if (isset($oneToOneElement['fetch'])) {
|
||||
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $oneToOneElement['fetch']);
|
||||
}
|
||||
|
||||
if (isset($oneToOneElement['mappedBy'])) {
|
||||
$mapping['mappedBy'] = $oneToOneElement['mappedBy'];
|
||||
} else {
|
||||
if (isset($oneToOneElement['inversedBy'])) {
|
||||
$mapping['inversedBy'] = $oneToOneElement['inversedBy'];
|
||||
}
|
||||
|
||||
$joinColumns = array();
|
||||
|
||||
if (isset($oneToOneElement['joinColumn'])) {
|
||||
$joinColumns[] = $this->joinColumnToArray($oneToOneElement['joinColumn']);
|
||||
} else if (isset($oneToOneElement['joinColumns'])) {
|
||||
foreach ($oneToOneElement['joinColumns'] as $joinColumnName => $joinColumnElement) {
|
||||
if ( ! isset($joinColumnElement['name'])) {
|
||||
$joinColumnElement['name'] = $joinColumnName;
|
||||
}
|
||||
|
||||
$joinColumns[] = $this->joinColumnToArray($joinColumnElement);
|
||||
}
|
||||
}
|
||||
|
||||
$mapping['joinColumns'] = $joinColumns;
|
||||
}
|
||||
|
||||
if (isset($oneToOneElement['cascade'])) {
|
||||
$mapping['cascade'] = $oneToOneElement['cascade'];
|
||||
}
|
||||
|
||||
if (isset($oneToOneElement['orphanRemoval'])) {
|
||||
$mapping['orphanRemoval'] = (bool)$oneToOneElement['orphanRemoval'];
|
||||
}
|
||||
|
||||
$metadata->mapOneToOne($mapping);
|
||||
}
|
||||
}
|
||||
|
||||
// Evaluate oneToMany relationships
|
||||
if (isset($element['oneToMany'])) {
|
||||
foreach ($element['oneToMany'] as $name => $oneToManyElement) {
|
||||
$mapping = array(
|
||||
'fieldName' => $name,
|
||||
'targetEntity' => $oneToManyElement['targetEntity'],
|
||||
'mappedBy' => $oneToManyElement['mappedBy']
|
||||
);
|
||||
|
||||
if (isset($oneToManyElement['fetch'])) {
|
||||
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $oneToManyElement['fetch']);
|
||||
}
|
||||
|
||||
if (isset($oneToManyElement['cascade'])) {
|
||||
$mapping['cascade'] = $oneToManyElement['cascade'];
|
||||
}
|
||||
|
||||
if (isset($oneToManyElement['orphanRemoval'])) {
|
||||
$mapping['orphanRemoval'] = (bool)$oneToManyElement['orphanRemoval'];
|
||||
}
|
||||
|
||||
if (isset($oneToManyElement['orderBy'])) {
|
||||
$mapping['orderBy'] = $oneToManyElement['orderBy'];
|
||||
}
|
||||
|
||||
if (isset($oneToManyElement['indexBy'])) {
|
||||
$mapping['indexBy'] = $oneToManyElement['indexBy'];
|
||||
}
|
||||
|
||||
$metadata->mapOneToMany($mapping);
|
||||
}
|
||||
}
|
||||
|
||||
// Evaluate manyToOne relationships
|
||||
if (isset($element['manyToOne'])) {
|
||||
foreach ($element['manyToOne'] as $name => $manyToOneElement) {
|
||||
$mapping = array(
|
||||
'fieldName' => $name,
|
||||
'targetEntity' => $manyToOneElement['targetEntity']
|
||||
);
|
||||
|
||||
if (isset($associationIds[$mapping['fieldName']])) {
|
||||
$mapping['id'] = true;
|
||||
}
|
||||
|
||||
if (isset($manyToOneElement['fetch'])) {
|
||||
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $manyToOneElement['fetch']);
|
||||
}
|
||||
|
||||
if (isset($manyToOneElement['inversedBy'])) {
|
||||
$mapping['inversedBy'] = $manyToOneElement['inversedBy'];
|
||||
}
|
||||
|
||||
$joinColumns = array();
|
||||
|
||||
if (isset($manyToOneElement['joinColumn'])) {
|
||||
$joinColumns[] = $this->joinColumnToArray($manyToOneElement['joinColumn']);
|
||||
} else if (isset($manyToOneElement['joinColumns'])) {
|
||||
foreach ($manyToOneElement['joinColumns'] as $joinColumnName => $joinColumnElement) {
|
||||
if ( ! isset($joinColumnElement['name'])) {
|
||||
$joinColumnElement['name'] = $joinColumnName;
|
||||
}
|
||||
|
||||
$joinColumns[] = $this->joinColumnToArray($joinColumnElement);
|
||||
}
|
||||
}
|
||||
|
||||
$mapping['joinColumns'] = $joinColumns;
|
||||
|
||||
if (isset($manyToOneElement['cascade'])) {
|
||||
$mapping['cascade'] = $manyToOneElement['cascade'];
|
||||
}
|
||||
|
||||
$metadata->mapManyToOne($mapping);
|
||||
}
|
||||
}
|
||||
|
||||
// Evaluate manyToMany relationships
|
||||
if (isset($element['manyToMany'])) {
|
||||
foreach ($element['manyToMany'] as $name => $manyToManyElement) {
|
||||
$mapping = array(
|
||||
'fieldName' => $name,
|
||||
'targetEntity' => $manyToManyElement['targetEntity']
|
||||
);
|
||||
|
||||
if (isset($manyToManyElement['fetch'])) {
|
||||
$mapping['fetch'] = constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $manyToManyElement['fetch']);
|
||||
}
|
||||
|
||||
if (isset($manyToManyElement['mappedBy'])) {
|
||||
$mapping['mappedBy'] = $manyToManyElement['mappedBy'];
|
||||
} else if (isset($manyToManyElement['joinTable'])) {
|
||||
|
||||
$joinTableElement = $manyToManyElement['joinTable'];
|
||||
$joinTable = array(
|
||||
'name' => $joinTableElement['name']
|
||||
);
|
||||
|
||||
if (isset($joinTableElement['schema'])) {
|
||||
$joinTable['schema'] = $joinTableElement['schema'];
|
||||
}
|
||||
|
||||
foreach ($joinTableElement['joinColumns'] as $joinColumnName => $joinColumnElement) {
|
||||
if ( ! isset($joinColumnElement['name'])) {
|
||||
$joinColumnElement['name'] = $joinColumnName;
|
||||
}
|
||||
|
||||
$joinTable['joinColumns'][] = $this->joinColumnToArray($joinColumnElement);
|
||||
}
|
||||
|
||||
foreach ($joinTableElement['inverseJoinColumns'] as $joinColumnName => $joinColumnElement) {
|
||||
if ( ! isset($joinColumnElement['name'])) {
|
||||
$joinColumnElement['name'] = $joinColumnName;
|
||||
}
|
||||
|
||||
$joinTable['inverseJoinColumns'][] = $this->joinColumnToArray($joinColumnElement);
|
||||
}
|
||||
|
||||
$mapping['joinTable'] = $joinTable;
|
||||
}
|
||||
|
||||
if (isset($manyToManyElement['inversedBy'])) {
|
||||
$mapping['inversedBy'] = $manyToManyElement['inversedBy'];
|
||||
}
|
||||
|
||||
if (isset($manyToManyElement['cascade'])) {
|
||||
$mapping['cascade'] = $manyToManyElement['cascade'];
|
||||
}
|
||||
|
||||
if (isset($manyToManyElement['orderBy'])) {
|
||||
$mapping['orderBy'] = $manyToManyElement['orderBy'];
|
||||
}
|
||||
|
||||
if (isset($manyToManyElement['indexBy'])) {
|
||||
$mapping['indexBy'] = $manyToManyElement['indexBy'];
|
||||
}
|
||||
|
||||
if (isset($manyToManyElement['orphanRemoval'])) {
|
||||
$mapping['orphanRemoval'] = (bool)$manyToManyElement['orphanRemoval'];
|
||||
}
|
||||
|
||||
$metadata->mapManyToMany($mapping);
|
||||
}
|
||||
}
|
||||
|
||||
// Evaluate associationOverride
|
||||
if (isset($element['associationOverride']) && is_array($element['associationOverride'])) {
|
||||
|
||||
foreach ($element['associationOverride'] as $fieldName => $associationOverrideElement) {
|
||||
$override = array();
|
||||
|
||||
// Check for joinColumn
|
||||
if (isset($associationOverrideElement['joinColumn'])) {
|
||||
$joinColumns = array();
|
||||
foreach ($associationOverrideElement['joinColumn'] as $name => $joinColumnElement) {
|
||||
if ( ! isset($joinColumnElement['name'])) {
|
||||
$joinColumnElement['name'] = $name;
|
||||
}
|
||||
$joinColumns[] = $this->joinColumnToArray($joinColumnElement);
|
||||
}
|
||||
$override['joinColumns'] = $joinColumns;
|
||||
}
|
||||
|
||||
// Check for joinTable
|
||||
if (isset($associationOverrideElement['joinTable'])) {
|
||||
|
||||
$joinTableElement = $associationOverrideElement['joinTable'];
|
||||
$joinTable = array(
|
||||
'name' => $joinTableElement['name']
|
||||
);
|
||||
|
||||
if (isset($joinTableElement['schema'])) {
|
||||
$joinTable['schema'] = $joinTableElement['schema'];
|
||||
}
|
||||
|
||||
foreach ($joinTableElement['joinColumns'] as $name => $joinColumnElement) {
|
||||
if ( ! isset($joinColumnElement['name'])) {
|
||||
$joinColumnElement['name'] = $name;
|
||||
}
|
||||
|
||||
$joinTable['joinColumns'][] = $this->joinColumnToArray($joinColumnElement);
|
||||
}
|
||||
|
||||
foreach ($joinTableElement['inverseJoinColumns'] as $name => $joinColumnElement) {
|
||||
if ( ! isset($joinColumnElement['name'])) {
|
||||
$joinColumnElement['name'] = $name;
|
||||
}
|
||||
|
||||
$joinTable['inverseJoinColumns'][] = $this->joinColumnToArray($joinColumnElement);
|
||||
}
|
||||
|
||||
$override['joinTable'] = $joinTable;
|
||||
}
|
||||
|
||||
$metadata->setAssociationOverride($fieldName, $override);
|
||||
}
|
||||
}
|
||||
|
||||
// Evaluate associationOverride
|
||||
if (isset($element['attributeOverride']) && is_array($element['attributeOverride'])) {
|
||||
|
||||
foreach ($element['attributeOverride'] as $fieldName => $attributeOverrideElement) {
|
||||
$mapping = $this->columnToArray($fieldName, $attributeOverrideElement);
|
||||
$metadata->setAttributeOverride($fieldName, $mapping);
|
||||
}
|
||||
}
|
||||
|
||||
// Evaluate lifeCycleCallbacks
|
||||
if (isset($element['lifecycleCallbacks'])) {
|
||||
foreach ($element['lifecycleCallbacks'] as $type => $methods) {
|
||||
foreach ($methods as $method) {
|
||||
$metadata->addLifecycleCallback($method, constant('Doctrine\ORM\Events::' . $type));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// populate ClassMetadataInfo instance from $data
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a joinColumn mapping array based on the information
|
||||
* found in the given join column element.
|
||||
*
|
||||
* @param array $joinColumnElement The array join column element
|
||||
* @return array The mapping array.
|
||||
*/
|
||||
private function joinColumnToArray($joinColumnElement)
|
||||
{
|
||||
$joinColumn = array();
|
||||
if (isset($joinColumnElement['referencedColumnName'])) {
|
||||
$joinColumn['referencedColumnName'] = (string) $joinColumnElement['referencedColumnName'];
|
||||
}
|
||||
|
||||
if (isset($joinColumnElement['name'])) {
|
||||
$joinColumn['name'] = (string) $joinColumnElement['name'];
|
||||
}
|
||||
|
||||
if (isset($joinColumnElement['fieldName'])) {
|
||||
$joinColumn['fieldName'] = (string) $joinColumnElement['fieldName'];
|
||||
}
|
||||
|
||||
if (isset($joinColumnElement['unique'])) {
|
||||
$joinColumn['unique'] = (bool) $joinColumnElement['unique'];
|
||||
}
|
||||
|
||||
if (isset($joinColumnElement['nullable'])) {
|
||||
$joinColumn['nullable'] = (bool) $joinColumnElement['nullable'];
|
||||
}
|
||||
|
||||
if (isset($joinColumnElement['onDelete'])) {
|
||||
$joinColumn['onDelete'] = $joinColumnElement['onDelete'];
|
||||
}
|
||||
|
||||
if (isset($joinColumnElement['columnDefinition'])) {
|
||||
$joinColumn['columnDefinition'] = $joinColumnElement['columnDefinition'];
|
||||
}
|
||||
|
||||
return $joinColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the given column as array
|
||||
*
|
||||
* @param string $fieldName
|
||||
* @param array $column
|
||||
* @return array
|
||||
*/
|
||||
private function columnToArray($fieldName, $column)
|
||||
{
|
||||
$mapping = array(
|
||||
'fieldName' => $fieldName
|
||||
);
|
||||
|
||||
if (isset($column['type'])) {
|
||||
$params = explode('(', $column['type']);
|
||||
$column['type'] = $params[0];
|
||||
$mapping['type'] = $column['type'];
|
||||
|
||||
if (isset($params[1])) {
|
||||
$column['length'] = (integer) substr($params[1], 0, strlen($params[1]) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($column['column'])) {
|
||||
$mapping['columnName'] = $column['column'];
|
||||
}
|
||||
|
||||
if (isset($column['length'])) {
|
||||
$mapping['length'] = $column['length'];
|
||||
}
|
||||
|
||||
if (isset($column['precision'])) {
|
||||
$mapping['precision'] = $column['precision'];
|
||||
}
|
||||
|
||||
if (isset($column['scale'])) {
|
||||
$mapping['scale'] = $column['scale'];
|
||||
}
|
||||
|
||||
if (isset($column['unique'])) {
|
||||
$mapping['unique'] = (bool)$column['unique'];
|
||||
}
|
||||
|
||||
if (isset($column['options'])) {
|
||||
$mapping['options'] = $column['options'];
|
||||
}
|
||||
|
||||
if (isset($column['nullable'])) {
|
||||
$mapping['nullable'] = $column['nullable'];
|
||||
}
|
||||
|
||||
if (isset($column['version']) && $column['version']) {
|
||||
$mapping['version'] = $column['version'];
|
||||
}
|
||||
|
||||
if (isset($column['columnDefinition'])) {
|
||||
$mapping['columnDefinition'] = $column['columnDefinition'];
|
||||
}
|
||||
|
||||
return $mapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function loadMappingFile($file)
|
||||
{
|
||||
if (strpos($file, "\n") === false && is_file($file)) {
|
||||
if (false === is_readable($file)) {
|
||||
throw new MappingException(sprintf('File "%s" is not readable.', $file));
|
||||
}
|
||||
|
||||
return include($file);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Executable
+38
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace Espo\Utils;
|
||||
use Espo\Utils as Utils;
|
||||
|
||||
class DoctrineConverter extends BaseUtils
|
||||
{
|
||||
/**
|
||||
* Metadata conversion from Espo format into Doctrine
|
||||
*
|
||||
* @param string $name
|
||||
* @param array $data
|
||||
* @param bool $withName - different return array. If $withName=false, then return is "array()"; $withName=true, then array('name'=>$entityName, 'meta'=>$doctrineMeta);
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
//NEED TO CHANGE
|
||||
function convert($name, $data, $withName=false)
|
||||
{
|
||||
//HERE SHOULD BE CONVERSION FUNCTIONALITY
|
||||
$metadata= $this->getObject('Metadata');
|
||||
|
||||
$entityFullName= $metadata->getEntityPath($name, '\\');
|
||||
|
||||
$doctrineMeta= array(
|
||||
$entityFullName => $data
|
||||
);
|
||||
|
||||
if ($withName) {
|
||||
return array('name'=>$entityFullName, 'meta'=>$doctrineMeta);
|
||||
}
|
||||
return $doctrineMeta;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
Executable
+952
@@ -0,0 +1,952 @@
|
||||
<?php
|
||||
|
||||
namespace Espo\Utils;
|
||||
|
||||
use Espo\Utils as Utils;
|
||||
|
||||
class FileManager extends BaseUtils
|
||||
{
|
||||
/**
|
||||
* @var string - default directory separator
|
||||
*/
|
||||
protected $separator= DIRECTORY_SEPARATOR;
|
||||
|
||||
/**
|
||||
* @var object - default permission settings
|
||||
*/
|
||||
protected $defaultPermissions;
|
||||
|
||||
/**
|
||||
* @var object - default permission settings
|
||||
*/
|
||||
protected $appCache= 'application';
|
||||
|
||||
|
||||
/**
|
||||
* Get a folder separator
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getSeparator()
|
||||
{
|
||||
return $this->separator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of files in specified directory
|
||||
*
|
||||
* @param string $path string - Folder path, Ex. myfolder
|
||||
* @param bool $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.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function getFileList($path, $recursively=false, $filter='', $fileType='all')
|
||||
{
|
||||
$result = array();
|
||||
|
||||
$cdir = scandir($path);
|
||||
foreach ($cdir as $key => $value)
|
||||
{
|
||||
if (!in_array($value,array(".","..")))
|
||||
{
|
||||
$add= false;
|
||||
if (is_dir($path . $this->getSeparator() . $value)) {
|
||||
if ($recursively) {
|
||||
$result[$value] = $this->getFileList($path.$this->getSeparator().$value, $recursively, $filter, $fileType);
|
||||
}
|
||||
else if (in_array($fileType, array('all', 'dir'))){
|
||||
$add= true;
|
||||
}
|
||||
}
|
||||
else if (in_array($fileType, array('all', 'file'))) {
|
||||
$add= true;
|
||||
}
|
||||
|
||||
if ($add) {
|
||||
if (!empty($filter)) {
|
||||
if (preg_match('/'.$filter.'/i', $value)) {
|
||||
$result[] = $value;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$result[] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get content from file
|
||||
*
|
||||
* @param string $folderPath string - Folder path, Ex. myfolder
|
||||
* @param bool $filePath - File path, Ex. file.json
|
||||
*
|
||||
* @return string | bool
|
||||
*/
|
||||
function getContent($folderPath, $filePath='')
|
||||
{
|
||||
$fullPath= $this->concatPath($folderPath, $filePath);
|
||||
|
||||
return $this->fileGetContents($fullPath);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Save content to file
|
||||
*
|
||||
* @param string $data
|
||||
* @param string $folderPath string - Folder path, Ex. myfolder
|
||||
* @param bool $filePath - File path, Ex. file.json
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function setContent($content, $folderPath, $filePath='')
|
||||
{
|
||||
$fullPath= $this->concatPath($folderPath, $filePath);
|
||||
|
||||
return $this->filePutContents($fullPath, $content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save PHP content to file
|
||||
*
|
||||
* @param string $data
|
||||
* @param string $folderPath string - Folder path, Ex. myfolder
|
||||
* @param bool $filePath - File path, Ex. file.json
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function setContentPHP($content, $folderPath, $filePath='')
|
||||
{
|
||||
return $this->setContent($this->getPHPFormat($content), $folderPath, $filePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save JSON content to file
|
||||
*
|
||||
* @param string $data
|
||||
* @param string $folderPath string - Folder path, Ex. myfolder
|
||||
* @param bool $filePath - File path, Ex. file.json
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function setContentJSON($content, $folderPath, $filePath='')
|
||||
{
|
||||
$json = new Utils\JSON();
|
||||
|
||||
if (!$json->isJSON($content)) {
|
||||
$content= $json->encode($data);
|
||||
}
|
||||
return $this->setContent($content, $folderPath, $filePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge file content and save it to a file
|
||||
*
|
||||
* @param string $data JSON string
|
||||
* @param string $folderPath string - Folder path, Ex. myfolder
|
||||
* @param bool $filePath - File path, Ex. file.json
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function mergeContent($content, $folderPath, $filePath = '', $isJSON = false)
|
||||
{
|
||||
$fileContent= $this->getContent($folderPath, $filePath);
|
||||
|
||||
$savedDataArray= $this->getArrayData($fileContent);
|
||||
$newDataArray= $this->getArrayData($content);
|
||||
|
||||
$data= $this->merge($savedDataArray, $newDataArray);
|
||||
if ($isJSON) {
|
||||
$json = new Utils\JSON();
|
||||
$data= $json->encode($data);
|
||||
}
|
||||
|
||||
return $this->setContent($data, $folderPath, $filePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge PHP content and save it to a file
|
||||
*
|
||||
* @param string $data
|
||||
* @param string $folderPath string - Folder path, Ex. myfolder
|
||||
* @param bool $filePath - File path, Ex. file.json
|
||||
* @param bool $onlyFirstLevel - Merge only first level. Ex. current: array('test'=>array('item1', 'item2')). $content= array('test'=>array('item1'),). Result will be array('test'=>array('item1')).
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function mergeContentPHP($content, $folderPath, $filePath='', $onlyFirstLevel= false)
|
||||
{
|
||||
$fileContent= $this->getContent($folderPath, $filePath);
|
||||
|
||||
$savedDataArray= $this->getArrayData($fileContent);
|
||||
$newDataArray= $this->getArrayData($content);
|
||||
|
||||
if ($onlyFirstLevel) {
|
||||
foreach($newDataArray as $key => $val) {
|
||||
$setVal= is_array($val) ? array() : '';
|
||||
$savedDataArray[$key]= $setVal;
|
||||
}
|
||||
}
|
||||
|
||||
$data= $this->merge($savedDataArray, $newDataArray);
|
||||
|
||||
return $this->setContentPHP($data, $folderPath, $filePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Append the content to the end of the file
|
||||
*
|
||||
* @param string $content
|
||||
* @param string $folderPath string - Folder path, Ex. myfolder
|
||||
* @param bool $filePath - File path, Ex. file.json
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function appendContent($content, $folderPath, $filePath='')
|
||||
{
|
||||
$fullPath= $this->concatPath($folderPath, $filePath);
|
||||
|
||||
return $this->filePutContents($fullPath, $content, FILE_APPEND | LOCK_EX);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Unite file content to the file
|
||||
*
|
||||
* @param string $configParams - ["name", "cachePath", "corePath", "customPath"]
|
||||
* @param bool $recursively - Note: only for first level of sub directory, other levels of sub directories will be ignored
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function uniteFiles($configParams, $recursively=false)
|
||||
{
|
||||
//EXAMPLE OF IMPLEMENTATION IN METADATA CLASS
|
||||
/*if (empty($configParams) || empty($configParams->name) || empty($configParams->cachePath) || empty($configParams->corePath)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//merge matadata files
|
||||
$content= $this->uniteFilesSingle($configParams->corePath, $configParams->name, $recursively);
|
||||
|
||||
if (!empty($configParams->customPath)) {
|
||||
$customDir= strstr($configParams->customPath, '{*}', true);
|
||||
$dirList= $this->getFileList($customDir, false, '', 'dir');
|
||||
|
||||
foreach($dirList as $dirName) {
|
||||
$curPath= str_replace('{*}', $dirName, $configParams->customPath);
|
||||
//$content= array_merge($content, $this->uniteFilesSingle($curPath, $recursively));
|
||||
$content= $this->merge($content, $this->uniteFilesSingle($curPath, $configParams->name, $recursively));
|
||||
}
|
||||
}
|
||||
//END: merge matadata files
|
||||
|
||||
//save medatada to cache files
|
||||
$jsonData= $this->getObject('JSON')->encode($content);
|
||||
|
||||
$cacheFile= $this->concatPath($configParams->cachePath, $configParams->name);
|
||||
$result= $this->setContent($jsonData, $cacheFile.'.json');
|
||||
$result&= $this->setContent($this->getPHPFormat($content), $cacheFile.'.php');
|
||||
//END: save medatada to cache files
|
||||
|
||||
return $result; */
|
||||
}
|
||||
|
||||
/**
|
||||
* Unite file content to the file for one directory [NOW ONLY FOR METADATA, NEED TO CHECK FOR LAYOUTS AND OTHERS]
|
||||
*
|
||||
* @param string $dirPath
|
||||
* @param string $type - name of type ["metadata", "layouts"], ex. metadataConfig->name
|
||||
* @param bool $recursively - Note: only for first level of sub directory, other levels of sub directories will be ignored
|
||||
* @param string $moduleName - name of module if exists
|
||||
*
|
||||
* @return string - content of the files
|
||||
*/
|
||||
public function uniteFilesSingle($dirPath, $type, $recursively=false, $moduleName= '')
|
||||
{
|
||||
if (empty($dirPath) || !file_exists($dirPath)) {
|
||||
return false;
|
||||
}
|
||||
$unsetFileName = $this->getObject('Configurator')->get('unsetFileName');
|
||||
$scopeModuleMap = $this->getObject('Configurator')->get('scopeModuleMap');
|
||||
|
||||
//get matadata files
|
||||
$fileList = $this->getFileList($dirPath, $recursively, '\.json$');
|
||||
|
||||
//print_r($fileList);
|
||||
//echo '<hr />';
|
||||
|
||||
$defaultValues = $this->loadDefaultValues($this->getDirName($dirPath), $type);
|
||||
|
||||
$content= array();
|
||||
$unsets= array();
|
||||
foreach($fileList as $dirName => $fileName) {
|
||||
|
||||
if (is_array($fileName)) { /*get content from files in a sub directory*/
|
||||
$content[$dirName]= $this->uniteFilesSingle($this->concatPath($dirPath,$dirName), $type, false, $moduleName); //only first level of a sub directory
|
||||
|
||||
} else { /*get content from a single file*/
|
||||
if ($fileName == $unsetFileName) {
|
||||
$fileContent = $this->getContent($dirPath, $fileName);
|
||||
$unsets = $this->getArrayData($fileContent);
|
||||
continue;
|
||||
} /*END: Save data from unset.json*/
|
||||
|
||||
$mergedValues = $this->uniteFilesGetContent($dirPath, $fileName, $defaultValues);
|
||||
|
||||
if (!empty($mergedValues)) {
|
||||
$name = $this->getFileName($fileName, '.json');
|
||||
|
||||
//check if current module is a custom and if defined into scopeModuleMap
|
||||
/*if (empty($moduleName) || (isset($scopeModuleMap->$name) && $scopeModuleMap->$name == $moduleName) ) {
|
||||
$content[$name] = $mergedValues;
|
||||
} */
|
||||
$content[$name] = $mergedValues;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//unset content
|
||||
$content= $this->uniteFilesUnset($content, $unsets);
|
||||
//END: unset content
|
||||
|
||||
/*print_r($content);
|
||||
print_r($unsets);
|
||||
echo '<hr />'; */
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helpful method for get content from files for unite Files
|
||||
*
|
||||
* @param string $folderPath string - Folder path, Ex. myfolder
|
||||
* @param bool $filePath - File path, Ex. file.json
|
||||
* @param string | array() $defaults - It can be a string like ["metadata","layouts"] OR an array with default values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function uniteFilesGetContent($folderPath, $fileName, $defaults)
|
||||
{
|
||||
$fileContent= $this->getContent($folderPath, $fileName);
|
||||
$decoded= $this->getArrayData($fileContent);
|
||||
|
||||
if (empty($decoded)) {
|
||||
$this->getObject('Log')->add('FATAL EXCEPTION', 'Syntax error or empty file - '.$this->concatPath($folderPath, $fileName));
|
||||
}
|
||||
else {
|
||||
//Default values
|
||||
if (is_string($defaults) && !empty($defaults)) {
|
||||
$defType= $defaults;
|
||||
unset($defaults);
|
||||
$name= $this->getFileName($fileName, '.json');
|
||||
|
||||
$defaults= $this->loadDefaultValues($name, $defType);
|
||||
}
|
||||
$mergedValues= $this->merge($defaults, $decoded);
|
||||
//END: Default values
|
||||
|
||||
return $mergedValues;
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unset content items defined in the unset.json
|
||||
*
|
||||
* @param array $content
|
||||
* @param array $unsets
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function uniteFilesUnset($content, $unsets)
|
||||
{
|
||||
foreach($unsets as $rootKey => $unsetItem){
|
||||
if (!empty($unsetItem)){
|
||||
foreach($unsetItem as $unsetSett){
|
||||
if (!empty($unsetSett)){
|
||||
$keyItems = explode('.', $unsetSett);
|
||||
$currVal = "\$content['{$rootKey}']";
|
||||
foreach($keyItems as $keyItem){
|
||||
$currVal .= "['{$keyItem}']";
|
||||
}
|
||||
|
||||
$currVal = "if (isset({$currVal})) unset({$currVal});";
|
||||
eval($currVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load default values for selected type [metadata, layouts]
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $type - [metadata, layouts]
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function loadDefaultValues($name, $type='metadata')
|
||||
{
|
||||
$defaultPath= $this->getObject('Configurator')->get('defaultsPath');
|
||||
|
||||
$defaultValue= $this->getContent( $this->concatPath($defaultPath, $type), $name.'.json');
|
||||
if ($defaultValue!==false) {
|
||||
//return default array
|
||||
return $this->getObject('JSON')->decode($defaultValue, true);
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a string to a file
|
||||
*
|
||||
* @param string $filename
|
||||
* @param mixed $data
|
||||
* @param int $flags
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function filePutContents($filename, $data, $flags = 0)
|
||||
{
|
||||
if ($this->checkCreateFile($filename)===false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (file_put_contents($filename, $data, $flags) !== FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads entire file into a string
|
||||
*
|
||||
* @param string $filename
|
||||
* @param bool $useIncludePath
|
||||
*
|
||||
* @return string | false
|
||||
*/
|
||||
function fileGetContents($filename, $useIncludePath=false)
|
||||
{
|
||||
if (file_exists($filename)) {
|
||||
|
||||
if (strtolower(substr($filename, -4))=='.php') {
|
||||
return include($filename);
|
||||
} else {
|
||||
return file_get_contents($filename, $useIncludePath);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new file if not exists with all folders in the path.
|
||||
*
|
||||
* @param string $filePath
|
||||
* @return string
|
||||
*/
|
||||
public function checkCreateFile($filePath)
|
||||
{
|
||||
if (file_exists($filePath)) {
|
||||
|
||||
if (!in_array($this->getCurrentPermission($filePath), array($this->getDefaultPermissions()->file, $this->getDefaultPermissions()->dir))) {
|
||||
return $this->setDefaultPermissions($filePath, true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
$pathParts= pathinfo($filePath);
|
||||
if (!file_exists($pathParts['dirname'])) {
|
||||
$dirPermission= $this->getDefaultPermissions()->dir;
|
||||
$dirPermission= is_string($dirPermission) ? base_convert($dirPermission,8,10) : $dirPermission;
|
||||
|
||||
if (!mkdir($pathParts['dirname'], $dirPermission, true)) {
|
||||
$this->getObject('Log')->add('FATAL', 'Permission denied: unable to generate a folder on the server - '.$pathParts['dirname']);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (touch($filePath)) {
|
||||
return $this->setDefaultPermissions($filePath, true);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove all files in defined directory
|
||||
*
|
||||
* @param string $dirPath - directory path
|
||||
* @return bool
|
||||
*/
|
||||
public function removeFiles($filePaths, $dirPath='')
|
||||
{
|
||||
if (!is_array($filePaths)) {
|
||||
$filePaths= (array) $filePaths;
|
||||
}
|
||||
|
||||
$result= true;
|
||||
foreach($filePaths as $filePath) {
|
||||
if (!empty($dirPath)) {
|
||||
$filePath= $this->concatPath($dirPath, $filePath);
|
||||
}
|
||||
|
||||
if (file_exists($filePath) && is_file($filePath)) {
|
||||
$result&= unlink($filePath);
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all files in defined directory
|
||||
*
|
||||
* @param string $dirPath - directory path
|
||||
* @return bool
|
||||
*/
|
||||
public function removeFilesInDir($dirPath)
|
||||
{
|
||||
$fileList= $this->getFileList($dirPath, false, '', 'file');
|
||||
if (!empty($fileList)) {
|
||||
return $this->removeFiles($fileList, $dirPath);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a full path of the file
|
||||
*
|
||||
* @param string $folderPath - Folder path, Ex. myfolder
|
||||
* @param string $filePath - File path, Ex. file.json
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function concatPath($folderPath, $filePath='')
|
||||
{
|
||||
if (empty($filePath)) {
|
||||
return $folderPath;
|
||||
}
|
||||
else {
|
||||
if (substr($folderPath, -1)==$this->getSeparator()) {
|
||||
return $folderPath . $filePath;
|
||||
}
|
||||
return $folderPath . $this->getSeparator() . $filePath;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get an array data (if JSON convert to array)
|
||||
*
|
||||
* @param mixed $data - can be JSON, array
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getArrayData($data)
|
||||
{
|
||||
$json = new Utils\JSON();
|
||||
|
||||
if (is_array($data)) {
|
||||
return $data;
|
||||
}
|
||||
else if ($json->isJSON($data)) {
|
||||
return $json->decode($data, true);
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a filename without the file extension
|
||||
*
|
||||
* @param string $filename
|
||||
* @param string $ext - extension, ex. '.json'
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function getFileName($filename, $ext='')
|
||||
{
|
||||
if (empty($ext)) {
|
||||
$realFileName= substr($filename, 0, strrpos($filename, '.', -1));
|
||||
}
|
||||
else {
|
||||
if (substr($ext, 0, 1)!='.') {
|
||||
$ext= '.'.$ext;
|
||||
}
|
||||
|
||||
if (substr($filename, -(strlen($ext)))==$ext) {
|
||||
$realFileName= substr($filename, 0, -(strlen($ext)));
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($realFileName)) {
|
||||
return $realFileName;
|
||||
}
|
||||
|
||||
return $filename;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a directory name from the path
|
||||
*
|
||||
* @param string $path
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function getDirName($path)
|
||||
{
|
||||
$pieces= explode($this->getSeparator(), $path);
|
||||
if (empty($pieces[count($pieces)-1])) {
|
||||
unset($pieces[count($pieces)-1]);
|
||||
}
|
||||
|
||||
if ($this->getFileName($path)!=$path) {
|
||||
return $pieces[count($pieces)-2];
|
||||
}
|
||||
|
||||
return $pieces[count($pieces)-1];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get default settings
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
public function getDefaultPermissions()
|
||||
{
|
||||
if (isset($this->defaultPermissions) && is_object($this->defaultPermissions)) {
|
||||
return $this->defaultPermissions;
|
||||
}
|
||||
|
||||
$this->defaultPermissions = $this->getObject('Configurator')->get('defaultPermissions');
|
||||
|
||||
return $this->defaultPermissions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set default permission
|
||||
*
|
||||
* @param string $path
|
||||
* @param bool $recurse
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function setDefaultPermissions($path, $recurse=false)
|
||||
{
|
||||
if (!file_exists($path)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$permission= $this->getDefaultPermissions();
|
||||
|
||||
$result= $this->chmod($path, array($permission->file, $permission->dir), $recurse);
|
||||
if (!empty($permission->user)) {
|
||||
$result&= $this->chown($path, $permission->user, $recurse);
|
||||
}
|
||||
if (!empty($permission->group)) {
|
||||
$result&= $this->chgrp($path, $permission->group, $recurse);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get current permissions
|
||||
*
|
||||
* @param string $filename
|
||||
* @return string | bool
|
||||
*/
|
||||
function getCurrentPermission($filePath)
|
||||
{
|
||||
if (!file_exists($filePath)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$fileInfo= stat($filePath);
|
||||
|
||||
return substr(base_convert($fileInfo['mode'],10,8), -4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change permissions
|
||||
*
|
||||
* @param string $filename
|
||||
* @param int | array $octal - ex. 0755, array(0644, 0755), array('file'=>0644, 'dir'=>0755)
|
||||
* @param bool $recurse
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function chmod($path, $octal, $recurse=false)
|
||||
{
|
||||
if (!file_exists($path)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//check the input format
|
||||
$permission= array();
|
||||
if (is_array($octal)) {
|
||||
$count= 0;
|
||||
$rule= array('file', 'dir');
|
||||
foreach ($octal as $key => $val) {
|
||||
$pKey= strval($key);
|
||||
if (!in_array($pKey, $rule)) {
|
||||
$pKey= $rule[$count];
|
||||
}
|
||||
|
||||
if (!empty($pKey)) {
|
||||
$permission[$pKey]= $val;
|
||||
}
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
elseif (is_int((int)$octal)) {
|
||||
$permission= array(
|
||||
'file' => $octal,
|
||||
'dir' => $octal,
|
||||
);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
|
||||
//conver to octal value
|
||||
foreach($permission as $key => $val) {
|
||||
if (is_string($val)) {
|
||||
$permission[$key]= base_convert($val,8,10);
|
||||
}
|
||||
}
|
||||
|
||||
//Set permission for non-recursive request
|
||||
if (!$recurse) {
|
||||
if (is_dir($path)) {
|
||||
return $this->chmodReal($path, $permission['dir']);
|
||||
}
|
||||
return $this->chmodReal($path, $permission['file']);
|
||||
}
|
||||
|
||||
//Recursive permission
|
||||
return $this->chmodRecurse($path, $permission['file'], $permission['dir']);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Change permissions recirsive
|
||||
*
|
||||
* @param string $filename
|
||||
* @param int $fileOctal - ex. 0644
|
||||
* @param int $dirOctal - ex. 0755
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function chmodRecurse($path, $fileOctal=0644, $dirOctal=0755)
|
||||
{
|
||||
if (!file_exists($path)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_file($path)) {
|
||||
chmod($path, $fileOctal);
|
||||
}
|
||||
elseif (is_dir($path)) {
|
||||
$allFiles = scandir($path);
|
||||
$items = array_slice($allFiles, 2);
|
||||
|
||||
foreach ($items as $item) {
|
||||
$this->chmodRecurse($path. $this->getSeparator() .$item, $fileOctal, $dirOctal);
|
||||
}
|
||||
|
||||
$this->chmodReal($path, $dirOctal);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Change permissions recirsive
|
||||
*
|
||||
* @param string $filename
|
||||
* @param int $mode - ex. 0644
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function chmodReal($filename, $mode)
|
||||
{
|
||||
$result= chmod($filename, $mode);
|
||||
|
||||
if (!$result) {
|
||||
$this->chown($filename, $this->getDefaultOwner(true));
|
||||
$this->chgrp($filename, $this->getDefaultGroup(true));
|
||||
$result= chmod($filename, $mode);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Change owner permission
|
||||
*
|
||||
* @param string $path
|
||||
* @param int | string $user
|
||||
* @param bool $recurse
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function chown($path, $user='', $recurse=false)
|
||||
{
|
||||
if (!file_exists($path)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (empty($user)) {
|
||||
$user= $this->getDefaultOwner();
|
||||
}
|
||||
|
||||
//Set chown for non-recursive request
|
||||
if (!$recurse) {
|
||||
return chowm($path, $user);
|
||||
}
|
||||
|
||||
//Recursive chown
|
||||
return $this->chownRecurse($path, $user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change owner permission recirsive
|
||||
*
|
||||
* @param string $filename
|
||||
* @param int $fileOctal - ex. 0644
|
||||
* @param int $dirOctal - ex. 0755
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function chownRecurse($path, $user) {
|
||||
|
||||
if (!file_exists($path)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$allFiles = scandir($path);
|
||||
$items = array_slice($allFiles, 2);
|
||||
|
||||
foreach ($items as $item) {
|
||||
$this->chownRecurse($path. $this->getSeparator() .$item, $user);
|
||||
}
|
||||
|
||||
return chowm($path, $user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change group permission
|
||||
*
|
||||
* @param string $path
|
||||
* @param int | string $group
|
||||
* @param bool $recurse
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function chgrp($path, $group='', $recurse=false)
|
||||
{
|
||||
if (!file_exists($path)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (empty($group)) {
|
||||
$group= $this->getDefaultGroup();
|
||||
}
|
||||
|
||||
//Set chgrp for non-recursive request
|
||||
if (!$recurse) {
|
||||
return chgrp($path, $group);
|
||||
}
|
||||
|
||||
//Recursive chown
|
||||
return $this->chgrpRecurse($path, $group);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change group permission recirsive
|
||||
*
|
||||
* @param string $filename
|
||||
* @param int $fileOctal - ex. 0644
|
||||
* @param int $dirOctal - ex. 0755
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function chgrpRecurse($path, $group) {
|
||||
|
||||
if (!file_exists($path)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$allFiles = scandir($path);
|
||||
$items = array_slice($allFiles, 2);
|
||||
|
||||
foreach ($items as $item) {
|
||||
$this->chgrpRecurse($path. $this->getSeparator() .$item, $group);
|
||||
}
|
||||
|
||||
return chgrp($path, $group);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get default owner user
|
||||
*
|
||||
* @return int - owner id
|
||||
*/
|
||||
function getDefaultOwner($usePosix=false)
|
||||
{
|
||||
$owner= $this->getDefaultPermissions()->user;
|
||||
if (empty($owner) && $usePosix) {
|
||||
$owner= posix_getuid();
|
||||
}
|
||||
|
||||
if (empty($owner)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get default group user
|
||||
*
|
||||
* @return int - group id
|
||||
*/
|
||||
function getDefaultGroup($usePosix=false)
|
||||
{
|
||||
$group= $this->getDefaultPermissions()->group;
|
||||
if (empty($group) && $usePosix) {
|
||||
$group= posix_getegid();
|
||||
}
|
||||
|
||||
if (empty($group)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $group;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
Executable
+100
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
namespace Espo\Utils;
|
||||
use Espo\Utils as Utils;
|
||||
|
||||
class JSON extends BaseUtils
|
||||
{
|
||||
/**
|
||||
* JSON encode a string
|
||||
*
|
||||
* @param string $value
|
||||
* @param int $options Default 0
|
||||
* @param int $depth Default 512
|
||||
* @return string
|
||||
*/
|
||||
public static function encode($value, $options = 0, $depth = 512)
|
||||
{
|
||||
if(version_compare(phpversion(), '5.5.0', '>=')) {
|
||||
$json = json_encode($value, $options, $depth);
|
||||
}
|
||||
elseif(version_compare(phpversion(), '5.3.0', '>=')) {
|
||||
/*Check if options are supported for this version of PHP*/
|
||||
if (is_int($options)) {
|
||||
$json = json_encode($value, $options);
|
||||
}
|
||||
else {
|
||||
$json = json_encode($value);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$json = json_encode($value);
|
||||
}
|
||||
|
||||
if ($json===null) {
|
||||
$Log= new Utils\Log();
|
||||
$Log->add('ERROR', 'Value cannot be decoded to JSON - '.print_r($value, true));
|
||||
}
|
||||
|
||||
return $json;
|
||||
|
||||
//JSON_PRETTY_PRINT
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON decode a string (Fixed problem with "\")
|
||||
*
|
||||
* @param string $json
|
||||
* @param bool $assoc Default false
|
||||
* @param int $depth Default 512
|
||||
* @param int $options Default 0
|
||||
* @return object
|
||||
*/
|
||||
public static function decode($json, $assoc = false, $depth = 512, $options = 0)
|
||||
{
|
||||
if (is_array($json)) {
|
||||
$Log= new Utils\Log();
|
||||
$Log->add('WARNING', 'JSON:decode() - JSON cannot be decoded - '.$json);
|
||||
return false;
|
||||
}
|
||||
|
||||
/*if (strstr($json, '\\') && !strstr($json, '(\\')) {
|
||||
$json = preg_replace('/([^\\\])(\\\)([^\/\\\])/', '$1\\\\\\\$3', $json);
|
||||
} */
|
||||
|
||||
if(version_compare(phpversion(), '5.4.0', '>=')) {
|
||||
$json = json_decode($json, $assoc, $depth, $options);
|
||||
}
|
||||
elseif(version_compare(phpversion(), '5.3.0', '>=')) {
|
||||
$json = json_decode($json, $assoc, $depth);
|
||||
}
|
||||
else {
|
||||
$json = json_decode($json, $assoc);
|
||||
}
|
||||
|
||||
/*if ($json===null) {
|
||||
$Log= new Utils\Log();
|
||||
$Log->add('WARNING', 'JSON:decode() - JSON string cannot be decoded - '.$json);
|
||||
}*/
|
||||
|
||||
return $json;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if the string is JSON
|
||||
*
|
||||
* @param string $json
|
||||
* @return bool
|
||||
*/
|
||||
public static function isJSON($json){
|
||||
if ($json=='[]') {
|
||||
return true;
|
||||
}
|
||||
|
||||
return self::decode($json) != null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
Executable
+130
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
namespace Espo\Utils;
|
||||
|
||||
use Espo\Utils as Utils,
|
||||
Espo\Core,
|
||||
Doctrine\ORM\Tools;
|
||||
|
||||
class Layout extends FileManager
|
||||
{
|
||||
|
||||
protected $layoutConfig;
|
||||
|
||||
/**
|
||||
* Get Layout context
|
||||
*
|
||||
* @param $controller
|
||||
* @param $name
|
||||
*
|
||||
* @return json
|
||||
*/
|
||||
function getLayout($controller, $name)
|
||||
{
|
||||
$fileFullPath = $this->concatPath($this->getLayoutPath($controller), $name.'.json');
|
||||
|
||||
if (!file_exists($fileFullPath)) {
|
||||
|
||||
//load defaults
|
||||
$defaultPath = $this->getObject('Configurator')->get('defaultsPath');
|
||||
$fileFullPath = $this->concatPath( $this->concatPath($defaultPath, $this->getConfig()->name), $name.'.json' );
|
||||
//END: load defaults
|
||||
|
||||
if (!file_exists($fileFullPath)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->getContent($fileFullPath);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Merge layout data
|
||||
* Ex. $controller= Account, $name= detail then will be created a file layoutFolder/Account/detail.json
|
||||
*
|
||||
* @param JSON string $data
|
||||
* @param string $controller - ex. Account
|
||||
* @param string $name - detail
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function mergeLayout($data, $controller, $name)
|
||||
{
|
||||
$layoutPath = $this->getLayoutPath($controller);
|
||||
|
||||
/*//merge data with defaults values
|
||||
$defaults = $this->loadDefaultValues($name, $this->getConfig()->name);
|
||||
|
||||
$decoded = $this->getArrayData($data);
|
||||
$mergedValues= $this->merge($defaults, $decoded);
|
||||
$data= $this->getObject('JSON')->encode($mergedValues);
|
||||
//END: merge data with defaults values */
|
||||
|
||||
return $this->mergeContent($data, $layoutPath, $name.'.json', true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set Layout data
|
||||
* Ex. $controller= Account, $name= detail then will be created a file layoutFolder/Account/detail.json
|
||||
*
|
||||
* @param JSON string $data
|
||||
* @param string $controller - ex. Account
|
||||
* @param string $name - detail
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function setLayout($data, $controller, $name)
|
||||
{
|
||||
$layoutPath = $this->getLayoutPath($controller);
|
||||
|
||||
return $this->setContent($data, $layoutPath, $name.'.json');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Layout path, ex. application/Modules/Crm/Layouts/Account
|
||||
*
|
||||
* @param string $entityName
|
||||
* @param bool $delim - delimiter
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getLayoutPath($entityName, $delim= '/')
|
||||
{
|
||||
$moduleName= $this->getScopeModuleName($entityName);
|
||||
|
||||
$path= $this->getConfig()->corePath;
|
||||
if (!empty($moduleName)) {
|
||||
$path= str_replace('{*}', $moduleName, $this->getConfig()->customPath);
|
||||
}
|
||||
$path= $this->concatPath($path, $entityName);
|
||||
|
||||
if ($delim!='/') {
|
||||
$path = str_replace('/', $delim, $path);
|
||||
}
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get settings for Layout
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
function getConfig()
|
||||
{
|
||||
if (isset($this->layoutConfig) && is_object($this->layoutConfig)) {
|
||||
return $this->layoutConfig;
|
||||
}
|
||||
|
||||
$this->layoutConfig = $this->getObject('Configurator')->get('layoutConfig');
|
||||
|
||||
return $this->layoutConfig;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
Executable
+242
@@ -0,0 +1,242 @@
|
||||
<?php
|
||||
|
||||
namespace Espo\Utils;
|
||||
|
||||
use Espo\Utils as Utils,
|
||||
Espo\Utils\Api;
|
||||
|
||||
class Log extends BaseUtils
|
||||
{
|
||||
|
||||
/**
|
||||
* @var object $options - contains options defined in config.php
|
||||
*/
|
||||
protected $options;
|
||||
|
||||
/**
|
||||
* @var string $defaultLevel - default level, uses only if level is not defined by user
|
||||
*/
|
||||
public $defaultLevel = 'INFO';
|
||||
|
||||
/**
|
||||
* @var array $errorLevels
|
||||
* @link http://www.php.net/manual/en/errorfunc.constants.php
|
||||
*/
|
||||
protected $errorLevels = array (
|
||||
'FATAL EXCEPTION' => -1,
|
||||
'EXCEPTION' => 0,
|
||||
'FATAL' => 1,
|
||||
'WARNING' => 2,
|
||||
'NOTICE' => 8,
|
||||
'ERROR' => 32767,
|
||||
'INFO' => 50000,
|
||||
'DEBUG' => 55000,
|
||||
);
|
||||
|
||||
/**
|
||||
* @var array $phpErrorTypes
|
||||
*/
|
||||
protected $phpErrorTypes = array (
|
||||
-1 => 'FATAL EXCEPTION',
|
||||
0 => 'EXCEPTION',
|
||||
E_ERROR => 'FATAL',
|
||||
E_WARNING => 'WARNING',
|
||||
E_PARSE => 'PARSE',
|
||||
E_NOTICE => 'NOTICE',
|
||||
E_CORE_ERROR => 'CORE_ERROR',
|
||||
E_CORE_WARNING => 'CORE_WARNING',
|
||||
E_COMPILE_ERROR => 'COMPILE_ERROR',
|
||||
E_COMPILE_WARNING => 'COMPILE_WARNING',
|
||||
E_STRICT => 'STRICT',
|
||||
E_RECOVERABLE_ERROR => 'RECOVERABLE',
|
||||
E_DEPRECATED => 'DEPRECATED',
|
||||
E_USER_ERROR => 'USER_ERROR',
|
||||
E_USER_WARNING => 'USER_WARNING',
|
||||
E_USER_NOTICE => 'USER_NOTICE',
|
||||
E_USER_DEPRECATED => 'USER_DEPRECATED',
|
||||
);
|
||||
|
||||
/*
|
||||
* @var array $dieErrors - errors when should stop program execution
|
||||
*/
|
||||
protected $dieErrors = array (
|
||||
'FATAL EXCEPTION',
|
||||
'FATAL',
|
||||
);
|
||||
|
||||
/**
|
||||
* Catch error and save it to the log file
|
||||
*
|
||||
* @param integer $errNo - the level of the error
|
||||
* @param string $errStr - the error message
|
||||
* @param string $errFile - the filename that the error was raised in
|
||||
* @param integer $errLine - the line number the error was raised at
|
||||
* @return bool
|
||||
*/
|
||||
function catchError($errNo, $errStr, $errFile, $errLine)
|
||||
{
|
||||
$errorType= $this->phpErrorTypes[$errNo];
|
||||
if (empty($errorType)) {
|
||||
$errorType= $errNo;
|
||||
}
|
||||
$errorMessage = $errStr." - ".$errFile.":".$errLine;
|
||||
|
||||
return $this->add($errorType, $errorMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Catch exeption and save it to the log file
|
||||
*
|
||||
* @param integer $Exception
|
||||
* @return bool
|
||||
*/
|
||||
public function catchException($Exception, $useResolver=true)
|
||||
{
|
||||
$errNo = $Exception->getCode();
|
||||
$errorMessage = get_class($Exception).' - '.$Exception->getMessage();
|
||||
|
||||
//try to resolve the problem automatically
|
||||
if ($useResolver) {
|
||||
$this->getObject('Resolver')->handle($Exception);
|
||||
}
|
||||
|
||||
$errorType= $this->phpErrorTypes[$errNo];
|
||||
if (empty($errorType)) {
|
||||
$errorType= $errNo;
|
||||
}
|
||||
|
||||
return $this->add($errorType, $errorMessage);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Saved error to the file
|
||||
*
|
||||
* @param string $text
|
||||
* @return bool
|
||||
*/
|
||||
protected function logError($text)
|
||||
{
|
||||
$datetime= $this->getObject('Datetime')->getDatetime();
|
||||
|
||||
$text= $datetime.' '.$text;
|
||||
return $this->getObject('FileManager')->appendContent($text, $this->getOptions()->dir, $this->getOptions()->file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add custom item to the log file
|
||||
*
|
||||
* @param string $errorType
|
||||
* @param string $text
|
||||
* @return bool
|
||||
*/
|
||||
public function add($errorType, $text='')
|
||||
{
|
||||
if (empty($text)) {
|
||||
$text = $errorType;
|
||||
$errorType = '';
|
||||
}
|
||||
if (!empty($errorType)){
|
||||
$errorType = mb_strtoupper($errorType);
|
||||
}
|
||||
|
||||
$text = "[".$errorType."]: ".$text."\n";
|
||||
|
||||
//CHECK Levels here
|
||||
$status = true;
|
||||
if ($this->isSave($errorType)) {
|
||||
$status = $this->logError($text);
|
||||
}
|
||||
|
||||
if (in_array($errorType, $this->dieErrors)) {
|
||||
Utils\Api\Helper::displayError($text, 500);
|
||||
}
|
||||
|
||||
return $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if save the error to log file according to error level
|
||||
*
|
||||
* @param string $errorType
|
||||
* @return bool
|
||||
*/
|
||||
protected function isSave($errorType)
|
||||
{
|
||||
$configLevel= $this->getLevelValue($this->getOptions()->level);
|
||||
$errorLevel= $this->getLevelValue($errorType);
|
||||
|
||||
if ($configLevel >= $errorLevel) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get Level value (int) from the name
|
||||
*
|
||||
* @param string $errorName
|
||||
* @return int
|
||||
*/
|
||||
function getLevelValue($name)
|
||||
{
|
||||
if (empty($name)) {
|
||||
return $this->errorLevels[$this->defaultLevel];
|
||||
}
|
||||
|
||||
if (is_int($name)) {
|
||||
return $name;
|
||||
}
|
||||
|
||||
$name= mb_strtoupper($name);
|
||||
$levelValue= $this->errorLevels[$this->defaultLevel];
|
||||
|
||||
//check into errorLevels
|
||||
if (array_key_exists($name, $this->errorLevels)) {
|
||||
return $this->errorLevels[$name];
|
||||
}
|
||||
|
||||
//check into phpErrorTypes
|
||||
if (in_array($name, $this->phpErrorTypes)) {
|
||||
foreach($this->phpErrorTypes as $key => $val) {
|
||||
if ($name==$val) {
|
||||
return $key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->errorLevels[$this->defaultLevel];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Level name from the int value
|
||||
*
|
||||
* @param int $intValue
|
||||
* @return string
|
||||
*/
|
||||
function getLevelName($intValue)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get options from the system config
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
function getOptions()
|
||||
{
|
||||
if (isset($this->options) && is_object($this->options)) {
|
||||
return $this->options;
|
||||
}
|
||||
|
||||
$this->options = $this->getObject('Configurator')->get('logger');
|
||||
|
||||
return $this->options;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
Executable
+272
@@ -0,0 +1,272 @@
|
||||
<?php
|
||||
|
||||
namespace Espo\Utils;
|
||||
|
||||
use Espo\Utils as Utils,
|
||||
Espo\Core,
|
||||
Doctrine\ORM\Tools;
|
||||
|
||||
class Metadata extends FileManager
|
||||
{
|
||||
|
||||
protected $metadataConfig;
|
||||
protected $doctrineMetadataName= 'defs'; //Metadata "defs" uses for creating the metadata of Doctri
|
||||
|
||||
|
||||
/**
|
||||
* Get Metadata context
|
||||
*
|
||||
* @param $isJSON
|
||||
* @return json | array
|
||||
*/
|
||||
//HERE --- ADD CREATING DOCTRINE METADATA
|
||||
function getMetadata($isJSON=true, $reload=false)
|
||||
{
|
||||
$config= $this->getConfig();
|
||||
|
||||
if (!file_exists($config->cacheFile) || $reload) {
|
||||
$result= $this->uniteFiles($config, true);
|
||||
|
||||
if ($result===false) {
|
||||
$this->getObject('Log')->add('FATAL', 'Metadata:getMetadata() - metadata unite file cannot be created');
|
||||
}
|
||||
|
||||
$this->getObject('Log')->add('Debug', 'Metadata:getMetadata() - converting to doctrine metadata');
|
||||
if ($this->convertToDoctrine($this->getContent($config->cacheFile))) {
|
||||
$this->getObject('Log')->add('Debug', 'Metadata:getMetadata() - database rebuild');
|
||||
|
||||
try{
|
||||
$this->rebuildDatabase();
|
||||
} catch (\Exception $e) {
|
||||
$this->getObject('Log')->add('EXCEPTION', 'Try to rebuildDatabase'.'. Details: '.$e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (file_exists($config->cacheFile)) {
|
||||
$data= $this->getContent($config->cacheFile);
|
||||
if ($isJSON) {
|
||||
$data= $this->getObject('JSON')->encode($data);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set Metadata data
|
||||
* Ex. $type= menu, $scope= Account then will be created a file metadataFolder/menu/Account.json
|
||||
*
|
||||
* @param JSON string $data
|
||||
* @param string $type - ex. menu
|
||||
* @param string $scope - Account
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function setMetadata($data, $type, $scope)
|
||||
{
|
||||
$fullPath= $this->getConfig()->corePath;
|
||||
$moduleName= $this->getScopeModuleName($scope);
|
||||
if (!empty($moduleName)) {
|
||||
$fullPath= str_replace('{*}', $moduleName, $this->getConfig()->customPath);
|
||||
}
|
||||
$fullPath= $this->concatPath($fullPath, $type);
|
||||
|
||||
//merge data with defaults values
|
||||
$defaults= $this->loadDefaultValues($type, 'metadata');
|
||||
|
||||
$decoded= $this->getArrayData($data);
|
||||
$mergedValues= $this->merge($defaults, $decoded);
|
||||
$data= $this->getObject('JSON')->encode($mergedValues);
|
||||
//END: merge data with defaults values
|
||||
|
||||
$result= $this->setContent($data, $fullPath, $scope.'.json');
|
||||
|
||||
//create classes only for "defs" metadata
|
||||
if ($type==$this->doctrineMetadataName) {
|
||||
try{
|
||||
$this->generateEntities( array($this->getEntityPath($scope)) );
|
||||
} catch (\Exception $e) {
|
||||
$this->getObject('Log')->add('EXCEPTION', 'Try to generate Entities for '.$this->getEntityPath($scope).'. Details: '.$e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Metadata conversion from Espo format into Doctrine
|
||||
*
|
||||
* @param object $metadata
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function convertToDoctrine($metadata)
|
||||
{
|
||||
$cacheDir= $this->getConfig()->doctrineCache;
|
||||
|
||||
//remove all existing files
|
||||
$this->removeFilesInDir($cacheDir);
|
||||
|
||||
//create files named like "Espo.Entities.User.php"
|
||||
$result= true;
|
||||
foreach($metadata[$this->doctrineMetadataName] as $entityName => $meta) {
|
||||
$doctrineMetaWithName= $this->getObject('DoctrineConverter')->convert($entityName, $meta, true);
|
||||
|
||||
if (empty($doctrineMetaWithName)) {
|
||||
$this->getObject('Log')->add('FATAL', 'Metadata:convertToDoctrine(), Entity:'.$entityName.' - metadata cannot be converted into Doctrine format');
|
||||
return false;
|
||||
}
|
||||
|
||||
//create a doctrine metadata file
|
||||
$fileName= str_replace('\\', '.', $doctrineMetaWithName['name']).'.php';
|
||||
$result&= $this->setContent($this->getPHPFormat($doctrineMetaWithName['meta']), $cacheDir, $fileName);
|
||||
//END: create a doctrine metadata file
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rebuild a database accordinly to metadata
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function rebuildDatabase()
|
||||
{
|
||||
global $base;
|
||||
if (!is_object($base)) {
|
||||
$base= \Espo\Core\Base::start();
|
||||
}
|
||||
|
||||
$tool = new \Doctrine\ORM\Tools\SchemaTool($base->em);
|
||||
|
||||
$cmf = new \Doctrine\ORM\Tools\DisconnectedClassMetadataFactory();
|
||||
$cmf->setEntityManager($base->em); // $em is EntityManager instance
|
||||
$classes = $cmf->getAllMetadata();
|
||||
|
||||
$tool->updateSchema($classes);
|
||||
|
||||
return true; //always true, because updateSchema just returns the VOID
|
||||
}
|
||||
|
||||
/**
|
||||
* Rebuild a database accordinly to metadata
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function generateEntities($classNames)
|
||||
{
|
||||
if (!is_array($classNames)) {
|
||||
$classNames= (array) $classNames;
|
||||
}
|
||||
|
||||
global $base;
|
||||
if (!is_object($base)) {
|
||||
$base= \Espo\Core\Base::start();
|
||||
}
|
||||
|
||||
$cmf = new \Doctrine\ORM\Tools\DisconnectedClassMetadataFactory();
|
||||
$cmf->setEntityManager($base->em); // $em is EntityManager instance
|
||||
|
||||
$metadata= array();
|
||||
foreach($classNames as $className) {
|
||||
$metadata[]= $cmf->getMetadataFor($className);
|
||||
}
|
||||
|
||||
if (!empty($metadata)) {
|
||||
$generator = new \Doctrine\ORM\Tools\EntityGenerator();
|
||||
$generator->setGenerateAnnotations(false);
|
||||
$generator->setGenerateStubMethods(true);
|
||||
$generator->setRegenerateEntityIfExists(false);
|
||||
$generator->setUpdateEntityIfExists(false);
|
||||
$generator->generate($metadata, 'application');
|
||||
|
||||
return true; //always true, because generate just returns the VOID
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unite file content to the file
|
||||
*
|
||||
* @param string $configParams - ["name", "cachePath", "corePath", "customPath"]
|
||||
* @param bool $recursively - Note: only for first level of sub directory, other levels of sub directories will be ignored
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function uniteFiles($configParams, $recursively=false)
|
||||
{
|
||||
if (empty($configParams) || empty($configParams->name) || empty($configParams->cachePath) || empty($configParams->corePath)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//merge matadata files
|
||||
$content= $this->uniteFilesSingle($configParams->corePath, $configParams->name, $recursively);
|
||||
|
||||
if (!empty($configParams->customPath)) {
|
||||
$customDir= strstr($configParams->customPath, '{*}', true);
|
||||
$dirList= $this->getFileList($customDir, false, '', 'dir');
|
||||
|
||||
foreach($dirList as $dirName) {
|
||||
$curPath= str_replace('{*}', $dirName, $configParams->customPath);
|
||||
$content= $this->merge($content, $this->uniteFilesSingle($curPath, $configParams->name, $recursively, $dirName));
|
||||
|
||||
//print_r($content );
|
||||
}
|
||||
}
|
||||
|
||||
//END: merge matadata files
|
||||
|
||||
//save medatada to cache files
|
||||
return $this->setContentPHP($content, $this->getConfig()->cacheFile);
|
||||
//END: save medatada to cache files
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Entity path, ex. Espo.Entities.Account or Modules\Crm\Entities\MyModule
|
||||
*
|
||||
* @param string $entityName
|
||||
* @param bool $delim - delimiter
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getEntityPath($entityName, $delim= '\\')
|
||||
{
|
||||
$moduleName= $this->getScopeModuleName($entityName);
|
||||
|
||||
$path= 'Espo';
|
||||
if (!empty($moduleName)) {
|
||||
$path= 'Modules'.$delim.$moduleName;
|
||||
}
|
||||
|
||||
return implode($delim, array($path, 'Entities', $entityName));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get settings for Metadata
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
function getConfig()
|
||||
{
|
||||
if (isset($this->metadataConfig) && is_object($this->metadataConfig)) {
|
||||
return $this->metadataConfig;
|
||||
}
|
||||
|
||||
$this->metadataConfig = $this->getObject('Configurator')->get('metadataConfig');
|
||||
$this->metadataConfig->cacheFile= $this->concatPath($this->metadataConfig->cachePath, $this->metadataConfig->name).'.php';
|
||||
|
||||
return $this->metadataConfig;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
Executable
+57
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace Espo\Utils;
|
||||
|
||||
use Espo\Utils as Utils;
|
||||
|
||||
class Resolver extends BaseUtils
|
||||
{
|
||||
protected $exceptions = array(
|
||||
'Doctrine\DBAL\DBALException' => 'DBALException',
|
||||
'ReflectionException' => 'ReflectionException',
|
||||
);
|
||||
|
||||
|
||||
public function handle($Exception)
|
||||
{
|
||||
$handler= get_class($Exception);
|
||||
$trace= $Exception->getTrace();
|
||||
$args= array();
|
||||
if (is_array($trace[0]['args'])) {
|
||||
$args= $trace[0]['args'];
|
||||
}
|
||||
|
||||
if (in_array($handler, array_keys($this->exceptions))) {
|
||||
$method= $this->exceptions[$handler];
|
||||
|
||||
$this->getObject('Log')->add('INFO', 'Try to resolve the exception - '.$handler);
|
||||
$result= false;
|
||||
try {
|
||||
$result= $this->$method($args);
|
||||
} catch(\Exception $e) {
|
||||
$this->getObject('Log')->add('INFO', 'Could not resolve the exception - '.$handler.'. Details below:');
|
||||
$this->getObject('Log')->catchException($e, false);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
protected function DBALException($args)
|
||||
{
|
||||
return $this->getObject('Metadata')->rebuildDatabase();
|
||||
}
|
||||
|
||||
protected function ReflectionException($args)
|
||||
{
|
||||
return $this->getObject('Metadata')->generateEntities($args);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
+1
@@ -0,0 +1 @@
|
||||
[{"label":"Overview","rows":[[{"name":"name"},false],[{"name":"website"},{"name":"phone"}],[{"name":"email"},{"name":"fax"}],[{"name":"billingAddress"},{"name":"shippingAddress"}],[{"name":"description"},false]]},{"label":"Details","rows":[[{"name":"type"},{"name":"sicCode"}],[{"name":"industry"},false]]}]
|
||||
@@ -0,0 +1 @@
|
||||
[{"label":"","rows":[[{"name":"name"}],[{"name":"website"}],[{"name":"email"}],[{"name":"phone"}]]}]
|
||||
@@ -0,0 +1 @@
|
||||
["name","website"]
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user