2018-3-9 14:42:14 星期五
本文分两部分:
第一部分是从index.php入口开始的代码执行的部分流程
第二部分是对官方文档的翻译
第一部分: 流程:
入口文件: index.php
->加载 include/entryPoint.php
entryPoin.php:
->加载配置文件 config.php ($sugar_config 数据库配置, 邮件配置, 语种, 日志配置, 默认module/action等等 ) config_override.php
->加载安全相关类, DB工厂类, autoloader, 本地化, 邮件, 日志
->加载权限认证类, 钩子, SugarApplaction类
->设置session_id, 实例化Localization, 获取管理员信息
->sugarApplication()->execute()
exectute():
-> 获取module名字
-> 加载controller.php 查找顺序:
custom/modules/moduleNameController/controller.php
modules/moduleNameController/controller.php
custom/include/MVC/Controller/SugarController.php::CustomSugarController.php
include/MVC/controller/SugarController.php
-> 检查权限认证信息, 设置主题, -> 设置数据库查询超时, 查询最大连接等资源
->controller->execute()
注意:
action=index时, 默认是listView: SugarController->remap_action
加载模板:
以SugarController.php为例
SugarController->execute()->procesView()->ViewFactory::loadView()
loadview优先级(当action=index时):
1.当URL参数中有target_module时
custom/modules/{$target_module}/views/view.list.php > modules/{$target_module}/views/view.list.php
2.档URL参数中没有target_module时
custom/modules/{$module}/views/view.list.php
modules/{$module}/views/view.list.php
custom/include/MVC/View/views/view.list.php
include/MVC/View/views/view.list.php
loadView():
ViewFactory::_buildFormFile()-> new SugarView() (或者_buildClass()) -> ViewFactory::_loadConfig() -> process()
注意: view.list.php是一个公用的模板文件, 他最终的渲染内容是会根一些配置文件, 数据文件有关的
第二部分: 翻译:
Dashlets:
他就是首页页面上的一个功能模块(一个横条)
自定义模块的相关文件:
custom/modules/xxx/Dashlets/xxx/xxx.meta.php : 定义一个数组变量, 里边有模块的名字,描述, 图标, 归属哪个模块
custom/modules/xxx/Dashlets/xxx/xxx.php : 定义一个类, 里边有显示模块内容的方法display()
custom/modules/xxx/Dashlets/xxx/xxx.en_us.lang.php : xxx.meta.php中的title, description使用(没有就直接使用xxx.meta.php数组中定义的值)
单个dashlets要继承自Dashlet.php,
list dashlets继承自DashletGeneric.php,
图表dashlets继承自DashletGenericChart.php
所有的dashlets信息存放在user_preferences表, 每个dashlets都有一个ID
dashlets种类:
1. 展示modules数据 2. 订阅其他网站的数据 3.图表展示 4. 工具(日历, 记事本, 时钟等) 5. 其他
javascript:
位置: ./include/JavaScript/Dashlets.js
功能: 提交表单(postForm), 请求数据(callMethod: 调用dashlet类的方法, 或者调用外部接口,如谷歌地图)
Databases
支持MySQL和mssql, 高级版本还支持db2和oracle, 没有使用触发器和存储过程, 方便编码和抽象
索引: 放在系统模块或者自定义模块目录下的vardefs.php, 键名叫indices (注意vardef文件, 和metadata文件, 前者是描述数据库表的信息, 后者是描述html样式和布局的配置文件)
主键: sugar用create_guid()方法生成全局的唯一值(GUID)当做所有表的主键, 一共36位的字符串: aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee, 没有使用自增值是为了防止在数据同步时产生主键冲突
Entry Point 入口文件
/cron.php windows/linux 计划任务入口
/index.php 框架入口
/service/{v1版本号}/soap.php
/service/{v1版本号}/rest.php
./include/MVC/Controller/entry_point_registry.php
URL访问方式: http://{sugar url}/index.php?entryPoint={entry point name}
自定义入口: 分 6.3版本之前和之后
6.3之后: 入口文件写在/custom/Extension/application/Ext/EntryPointRegistry/中, 然后通过编译生成到: /custom/application/Ext/EntryPointRegistry/entry_point_registry.ext.php
6.3之前: 要创建/custom/include/MVC/Controller/entry_point_registry.php文件 定义入口(仍然兼容, 但不推荐)
入口信息是一个数组, 每一项是一个入口点, 每一项中包含两个值一个是入口文件的路径, 另一个是bool值,表示是否进行权限验证
File cache 文件缓存
主要缓存模板文件和语言字符串
默认放在/cache目录下边, 如果需要更改位置, 则需要需改 config.php 或者 config_override.php
打开文件缓存: 系统管理 > 系统 > 系统设置 > 高级 > 开发模式
Quick Search
Sugar QuickSearch (SQS)
Suagr Bean
:
增:
$bean = BeanFactory::newBean($module);
$bean->name = 'Example Record';$bean->save();$record_id = $bean->id;改:
$bean = BeanFactory::getBean($module, $id);
$bean->name = 'Updated Name';$bean->save();通过bean的fetched_rows 属性可以确认一条记录是新建的还是已经存在的
Module Framework (module/下的代码结构, 与之对应的是 Application Framework 指application/下的代码结构)
一个module通常包含的文件:
1. Vardefs文件, 定义了数据库的表, 字段, 数据类型和关联关系的信息
2. SugarBean文件, 实现了增删改查的功能, 每个模块都继承自SugarBean, 并添加了适用本模块的方法和变量
3. MetaData文件, 定义页面布局和内容信息: (ListView, DetialView, EditeView, SubPanels(跟其他module的关系), Popups(跟其他记录关联的数据列表))
MVC
主要流程: SugarApplication -> ControllerFactory::getController() -> SugarController() -> SugarController::execute()::process()::processView() -> ViewFactory() -> view -> view::process -> SugarView -> SugarView::display()
Model:
SugarBean 以及其子类, 用来操作数据库, 许多普通的module也会继承自SugarObject
内置的六种SugarObject: Basic, Person, issue, Company, File, Sale
View:
Views, otherwise known as actions are typically used to render views or to process logic
或者叫Action, 他不仅可以输出HTML数据, 也可以输出json数据或其他结构的数据, 有一个内置的/默认的SugarView类, 他实现了很多view所需要的基础功能, 例如处理HTML头部和底部信息,
自定义的view文件, 应该放在 /your_module/views/view.<view_name>.php 而其类名应该是驼峰式命名: <Modulename>View<Viewname>, 首字母大写, 其余字母小写, 自定义视图文件可以继承自SugarView或其他View
view分类:
1. DatilView, 通常从ListView页面进入, 他显示了自身的一些数据以及关联的条目(子面板), 子面板是在详情页显示的与之有关的列表性质的信息
./<module>/metadata/detailviewdefs.php定义了详情页的布局 ./<module>/metadata/subpaneldefs.php定义了详情页显示的子面板
2, EditView, 新添加或者编辑都属于他, ./<module>/metadata/editviewdefs.php 中存放编辑页面的布局
3, ListView, 他包含了搜索表单, 搜索结果, 可以 删除, 导出, 批量更新数据, 也可以点击去查看详情
4, Save,
5, Delete
view 方法:
1, preDidplay() 当一个视图继承了其他视图的时候就可以使用这个函数了,
2, display() 展示数据, 将逻辑都写在这里边
加载视图:
ViewFactory 按照以下顺序去加载vew文件:
./custom/modules/<module>/views/view.<view>.php
./modules/<module>/views/view.<view>.php./custom/include/MVC/View/view.<view>.php./include/MVC/Views/view.<view>.php视图的配置文件:
ViewFactory在渲染页面的时候, 会从下边文件中找到一些配置信息, 去控制视图的显示
./customs/modules/<module>/views/view.<view>.config.php
./modules/<module>/views/view.<view>.config.php./custom/include/MVC/View/views/view.<view>.config.php./include/MVC/View/views/view.<view>.config.phpController
Sugar主要的控制器是 SugarController, 如果想继承他, 就要在自己的模块中创建一个controller.php, 并把类名定义为<ModuleName>Controller, 而类的action的命名方式是 action_functionName
有许多细粒度的控制机制可以被开发者利用, 去重写controller的处理流程, 例如:
如果你想重写Save功能, 你可能要重写三个地方:
1, action_save: 处理保存的逻辑
2, pre_save: 处理来自表单的数据
3, post_save: 这里可以设置跳转链接, 或者保存后的一些处理逻辑, 或者展示一个新的view
自定义controller
自定义的controller要么继承自已经存在于/<module>/controller.php的类, 要么继承自SagurController, 但都要放在 ./custom/modules/<module>/controller.php 为了升级的时候不会被覆盖
包含控制器的文件:
./include/MVC/Controller/SugarController.php
./include/MVC/Controller/ControllerFactory.php./modules/<MyModule>/Controller.php./custom/modules/<MyModule>/controller.phpaction
控制器中的方法可以直接写在控制器类中, 也可以通过 $action_file_map 去找到对应的代码文件去执行, $action_file_map的加载顺序如下, 后边的变量会覆盖前边的同名变量
./include/MVC/Controller
./modules/<module>./custom/modules/<module>./custom/include/MVC/Controller自定义的 $action_file_map 文件需要放在 ./custom/modules/<module>/action_file_map.php 路径中, 确保安全升级
1, 从index.php开始, 加载SugarApplication实例
2, SugarApplication实例化 SugarControllerFactory
3, SugarControllerFactory加载对应的Controller
4, 检查 ./custom/modules/<module>/Controller.php 是否存在
1, 如果不存在, 检查./modules/<module>/Controller.php是否存在
2, 如果还不存在, 就加载SugarController.php
5, 调用对应的action
1, 检查./custom/modules/<module>/<action>.php是否存在, 如果找到了, 并且./custom/modules/<module>/views/view.<action>.php不存在, 那就用这个view ???wtf
2, 如果不存在 ./custom/modules/<module>/<action> 就去查找 modules/<module>/<action>.php, 如果找到了, 并且./modules/<module>/views/view.<action>.php不存在, 就使用modules/<module>/<action>.php
3, 如果不存在 modules/<module>/<action>.php 就在控制器里查找 action_<action> 方法
4, 如果控制器中不存在这个方法, 就去加载 action_file_mapping, 并查找
5, 还是没有找到, 就报错"Action is not defined"
Metadata (用于页面布局的配置信息)
: Metadata定义为数据的信息 , 框架会利用这些文件去表达/抽象系统中页面怎么显示或者业务是怎样的逻辑, Metadata存在于定义性质的php文件中, 并由php进行处理, 这些处理通常包括, 1. Smarty 模板渲染页面, 2. JavaScript库处理(调用)一些影响显示的逻辑,或者对输入进行验证等
: Metadata是一个定义了嵌套数组的php文件, 他描述了视图中的按钮, hidden input标签, 字段布局等等的信息,
Application级别的Metadata
所有可用的应用模块都定义在 /include/moudules.php 其中:
$moduleList 定义了用于在界面顶部显示的tabs的名字, 他是个索引数组, 每一项的值都用复数形式 (so??)
$beanList 定义了可用的beans(modules), 他是一个关联数组, 键是复数形式, 值是单数形式, 值还跟$beanFiles关联
$beanFiles 定义了modules文件位置
$modInvisList 定义了可以在界面上显示的modues
$adminOnlyList 定义了在admin页面可以被admin看到的modules
Module级别的Metadata
路径: modules/[module]/metadata
additionalDetails.php | 定义了当用户鼠标滑过listView的一行时的显示效果 |
editviewdefs.php | 编辑页面如何渲染 |
detailviewdefs.php | 详情页面如何渲染 |
listviewdefs.php | 列表页面如何渲染 |
metafiles.php | 重新定义详情, 编辑, 列表需要的metadata文件的路径 |
popupdefs.php | 渲染搜索表单和列表页面时使用 |
searchdefs.php | 显示modules的基础和高级搜索时使用 |
sidecreateviewdefs.php | 在快捷面板上创建表单时使用 |
subpaneldefs.php | 在详情页面的字面板展示 |
这些metadata文件的路径也可以在metafiles.php中被重新定义
搜索表单(Search Form)的Metadata
文件名是searchdefs.php, 里边是一个多维数组, 定义了某个模块的表单怎么显示
比如Accounts模块的表单( $searchDefs['Accounts']), 这个表单有多少列, 每一个表单项的文字宽度是多少百分比, input框多少百分比, input的name属性的值等等
其中$searchDefs['Accounts'] 中的Accounts是在 include/modules.php::$moduleList 变量中定义的键名
当一个模块的list视图被渲染的时候, 就会引入searchdefs.php文件, 在view.list.php中会检查modules中是否存在SearchForm.html
如果存在, 就会以Classic模式, 用include/SearchForm/SearchForm.php去处理搜索表单, (Classic Mode是指5.x版本之前, 目前是MVC/Metadata模式)
如果不存在, 就会用include/SearchForm/SearchForm2.php去处理搜索表单, 此时 就会在 custom/modules/[module]/metadata/ 和 modules/[module]/metadata 中依次寻找searchdefs.php文件
EditView 和 DetailView 的 Metadata
metadata文件也以通过studio interface(手工拖动?)去自动创建, 这种情况下, metadata会放在 custom/modules/[module]/metadata/目录下
当第一次访问一个view的时候, preDisplay()方法会去尝试加载正确的metadata文件, 通常情况下metadata文件会在/modules/[module]/metadata/目录下
metadata也可能放在其他路径下边, 他们的路径可以在metafiles.php中找到
生成html文件/渲染视图
当按照上边的约定加载完metadata后, preDisplay()方法还会创建一个EditView object(以EditView为例), 检查是否需要根据metadata区构建一个smarty模板, EditView object会做大量的工作:
创建模板, 赋值, 权限等级判断等等,
在view代码中调用完preDisplay()方法后就会去调用display()->EditView object()::process()->EditView object()::display()->将生成的html数据放到buffer中输出
举例
加入有一个详情页的请求: index.php?action=DetailView&module=Opportunities&record=46af9843-ccdf-f489-8833
1. 程序先去是否有一个 modules/Opportunity/DetailView.php 如果有就会去触发 Classic 模式的渲染方式
如果没有这个文件, 程序就会去找modules/Opportunity/views/view.detail.php
如果两个都没有, 程序就会加载include/DetailView/DetailView.php, 此时是 MVC模式, include/MVC/View/views/views.detail.php 会创建一个DetailView的实例 -> 加载smarty -> setup() -> process() -> display();
2. 其中setup()会创建一个 TemplateHandler 实例, 他在创建最终的详情视图时会去检查加载哪个detailviewdefs.php, 如果setup()中传入了metadata参数就用这个参数, 没有的话, 就去做
TemplateHandler 实例 也会去做一些 ajax, javascript验证有关的事情
3. process()方法会根据metadata去计算页面展示时HTML元素之间的距离, 字段个数, 以及每列所占的百分比等等
4. display()方法会把变量赋值到Smarty模板上去, 并返回最终要输出的内容
5. 在输出前, TemplateHandler 实例会去检查缓存目录中有没有对应的文件(cache/modules/Opportunity/DetailView.tpl), 如果没有, 就会调用Sugar_Smarty::fetch()去生成缓存文件, 这一步很耗费资源, 另外, 通过 studio interface 方法生成的模板肯定会刷新缓存
Sugar Fields
sugar 根据metadata文件(例如listviewdefs.php)vardefs.php中定义的字段信息, 可以在include/SugarFields/Fields中找到sugar Fields文件
在 include/SugarFields/Fields/Base 中你会找到渲染 DetailView, EditView, ListView, 和 Search Forms 这些基础视图的模板(例如, DetailView.tpl)
目录结构:
./include/SugarFields/Fields/
./include/SugarFields/Fields/<Type>/DetailView.tpl //Type: 比如Bool, Enum, Text, URL, Readonly... ./modules/MyModule/vardefs.php./modules/MyModule/metadata/defs.php字段类型以及关联信息(比如是枚举类型, 他就会有多个值) 去自动生成HTML标签
: 也有group类型的比如 Address, Datetime, Parent, Relate
大多数的Sugar Field包含了一堆Smarty tpl文件
一些 Sugar Fields 还包含了 SugarFieldBase 的子类, 用来覆盖原有的方法去做一些额外的处理, 子类的名字要这样写: SugarField[Sugar Field Type] 其中后边的英文单词首字母要大写
例如:
enum类型的SugarField(会被渲染成 select 标签)的代码, 放在 ./include/SugarFields/Fields/Enum/SugarFieldEnum.php中,
这个代码中你可以看到, 枚举类型是是怎么使用6个Smarty模板中的一个取决于
1. view是什么(edit, detail or search)
2. enum vardef 的定义中是否有一个 'function' 属性去调用php函数去渲染字段的内容
例子,
Vardefs
他(Variable Definitions) 给Application提供了SugarBean的信息, 如果一个moudles包含了SugarBean, 那么就会有一个vardefs文件,
该文件用来描述表中的每个字段的信息, beans之间的关系, bean的索引信息, 关联表/字段信息