change instance

This commit is contained in:
Taras Machyshyn
2013-11-01 13:49:54 +02:00
commit 417576fd5e
2373 changed files with 284713 additions and 0 deletions
Executable
+3
View File
@@ -0,0 +1,3 @@
data/logs/*
/test.php
/test2.php
Executable
+10
View File
@@ -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
View File
@@ -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();
?>
+103
View File
@@ -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
View File
@@ -0,0 +1,6 @@
[{
"label":"Overview",
"rows": [
[{"name":"name"}]
]
}]
+6
View File
@@ -0,0 +1,6 @@
[{
"label":"",
"rows": [
[{"name":"name"}]
]
}]
+1
View File
@@ -0,0 +1 @@
["name"]
@@ -0,0 +1 @@
["name"]
+1
View File
@@ -0,0 +1 @@
[{"name":"name","link":true,"width":"30"}]
+1
View File
@@ -0,0 +1 @@
[{"name":"name"},{"name":"email","type":"base","sortable":false,"params":{}},{"name":"city"}]
+1
View File
@@ -0,0 +1 @@
[{"name":"name","link":true,"width":"30"}]
+1
View File
@@ -0,0 +1 @@
["assignedUser", "teams"]
@@ -0,0 +1 @@
[]
+1
View File
@@ -0,0 +1 @@
+7
View File
@@ -0,0 +1,7 @@
{
"name":"TestModuleName",
"var1": {
"subvar1":"subval1",
"subvar2":"subval2"
}
}
+7
View File
@@ -0,0 +1,7 @@
{
"name":"TestModuleName",
"var1": {
"subvar1":"subval1",
"subvar2":"subval2"
}
}
+7
View File
@@ -0,0 +1,7 @@
{
"name":"CustomTestModuleName",
"var1": {
"subvar1":"subval1",
"subvar2":"subval2"
}
}
+67
View File
@@ -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',
),
);
?>
+122
View File
@@ -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";
}
}
+47
View File
@@ -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();
}
}
+84
View File
@@ -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;
}
}
+1
View File
@@ -0,0 +1 @@
{"theme":"default","language":"en"}
+1
View File
@@ -0,0 +1 @@
[{"label":"MyLabel"}]
+1
View File
@@ -0,0 +1 @@
[{"oldlabel":"MyLabeldddd","label":"MyLabel"}]
+1
View File
@@ -0,0 +1 @@
[[{"name":"Opportunities","id":1},{"name":"Leads","id":2},{"name":"OpportunitiesByStatus","id":5}],[{"name":"Calendar","id":3},{"name":"Tasks","id":4}]]
+9
View File
@@ -0,0 +1,9 @@
[{
"label": "Locale",
"rows": [
[{"name": "dateFormat"}, {"name": "timeFormat"}],
[{"name": "timeZone"}, {"name": "weekStart"}],
[{"name": "defaultCurrency"}],
[{"name": "thousandSeparator"}, {"name": "decimalMark"}]
]
}]
+1
View File
@@ -0,0 +1 @@
["users", "teams"]
+18
View File
@@ -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
View File
@@ -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"}]
]
}
]
+9
View File
@@ -0,0 +1,9 @@
[
{
"label": "Configuration",
"rows": [
[{"name": "recordsPerPage"},{"name": "recordsPerPageSmall"}],
[{"name": "tabList"},{"name": "quickCreateList"}]
]
}
]
+1
View File
@@ -0,0 +1 @@
["users"]
+1
View File
@@ -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
View File
@@ -0,0 +1 @@
[{"label":"","rows":[[{"name":"name"}],[{"name":"userName"}],[{"name":"isAdmin"}],[{"name":"email"}]]}]
+1
View File
@@ -0,0 +1 @@
["name","userName","email"]
+1
View File
@@ -0,0 +1 @@
["title"]
+1
View File
@@ -0,0 +1 @@
[{"name":"name","width":30,"link":true},{"name":"userName"},{"name":"email"}]
+1
View File
@@ -0,0 +1 @@
[{"name":"name","width":30,"link":true},{"name":"userName"},{"name":"email"}]
+1
View File
@@ -0,0 +1 @@
["teams","roles"]
+87
View File
@@ -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."
}
]
}
}
+35
View File
@@ -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"
}
}
}
}
+26
View File
@@ -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
View File
@@ -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
}
}
+21
View File
@@ -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
View File
@@ -0,0 +1,8 @@
{
"params":[
],
"search":{
"basic":false,
"advanced":true
}
}
+6
View File
@@ -0,0 +1,6 @@
{
"search":{
"basic":false,
"advanced":false
}
}
+12
View File
@@ -0,0 +1,12 @@
{
"params":[
{
"name":"default",
"type":"bool"
}
],
"search":{
"basic":false,
"advanced":true
}
}
+25
View File
@@ -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
}
}
+21
View File
@@ -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
View File
@@ -0,0 +1,21 @@
{
"params":[
{
"name":"required",
"type":"bool",
"default":false
},
{
"name":"default",
"type":"varchar"
},
{
"name":"after",
"type":"varchar"
}
],
"search":{
"basic":false,
"advanced":false
}
}
+17
View File
@@ -0,0 +1,17 @@
{
"params":[
{
"name":"required",
"type":"bool",
"default":false
},
{
"name":"maxLength",
"type":"int"
}
],
"search":{
"basic":true,
"advanced":true
}
}
+25
View File
@@ -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
}
}
+25
View File
@@ -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
}
}
+25
View File
@@ -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
}
}
+19
View File
@@ -0,0 +1,19 @@
{
"params":[
{
"name":"required",
"type":"bool",
"default":false
}
],
"actualFields":[
"id"
],
"notActualFields":[
"name"
],
"search":{
"basic":false,
"advanced":true
}
}
+19
View File
@@ -0,0 +1,19 @@
{
"params":[
{
"name":"required",
"type":"bool",
"default":false
}
],
"actualFields":[
"ids"
],
"notActualFields":[
"names"
],
"search":{
"basic":false,
"advanced":true
}
}
+20
View File
@@ -0,0 +1,20 @@
{
"params":[
{
"name":"required",
"type":"bool",
"default":false
}
],
"actualFields":[
"id",
"type"
],
"notActualFields":[
"name"
],
"search":{
"basic":false,
"advanced":true
}
}
+21
View File
@@ -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
View File
@@ -0,0 +1,13 @@
{
"params":[
{
"name":"required",
"type":"bool",
"default":false
}
],
"search":{
"basic":false,
"advanced":false
}
}
+24
View File
@@ -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
}
}
+22
View File
@@ -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
}
}
+17
View File
@@ -0,0 +1,17 @@
{
"params":[
{
"name":"required",
"type":"bool",
"default":false
},
{
"name":"default",
"type":"text"
}
],
"search":{
"basic":true,
"advanced":true
}
}
+21
View File
@@ -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
View File
@@ -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
View File
@@ -0,0 +1 @@
{"entity":true,"layouts":false,"tab":false,"acl":false,"customizable":false}
+1
View File
@@ -0,0 +1 @@
{"entity":true,"layouts":false,"tab":false,"acl":false,"customizable":false}
+7
View File
@@ -0,0 +1,7 @@
{
"entity": true,
"layouts": false,
"tab": false,
"acl": true,
"customizable":false
}
+1
View File
@@ -0,0 +1 @@
{"entity":true,"layouts":false,"tab":false,"acl":false,"customizable":false}
+1
View File
@@ -0,0 +1 @@
{"entity":true,"layouts":false,"tab":false,"acl":false,"customizable":false}
+1
View File
@@ -0,0 +1 @@
{"entity":true,"layouts":true,"tab":false,"acl":false,"customizable":true}
+14
View File
@@ -0,0 +1,14 @@
{
"menu":{
"list":{
"buttons":[
{
"label":"Create Email Template",
"link":"#email-template/create",
"style":"primary",
"acl":"edit"
}
]
}
}
}
+27
View File
@@ -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"
}
]
}
}
}
+7
View File
@@ -0,0 +1,7 @@
{
"relationshipPanels":{
"users":{
"create":false
}
}
}
+19
View File
@@ -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"
}
]
}
}
}
+66
View File
@@ -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);
}
}
}
?>
+78
View File
@@ -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);
}
}
}
?>
+401
View File
@@ -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() .'}}';
}
}
*/
?>
+187
View File
@@ -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');
}
}
?>
+193
View File
@@ -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;
}
}
?>
+206
View File
@@ -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;
}
}
?>
+150
View File
@@ -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);
}
}
}
+38
View File
@@ -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;
}
}
?>
+952
View File
@@ -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;
}
}
?>
+100
View File
@@ -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;
}
}
?>
+130
View File
@@ -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;
}
}
?>
+242
View File
@@ -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;
}
}
?>
+272
View File
@@ -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;
}
}
?>
+57
View File
@@ -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
View File
@@ -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]]}]
+1
View File
@@ -0,0 +1 @@
[{"label":"","rows":[[{"name":"name"}],[{"name":"website"}],[{"name":"email"}],[{"name":"phone"}]]}]
+1
View File
@@ -0,0 +1 @@
["name","website"]

Some files were not shown because too many files have changed in this diff Show More