An Extension Module Example¶
Requirements¶
User should be able to add new RSS feed and read the existing feed.
Design¶
Server Side¶
List view of existing RSS feed.
Save action for new RSS feed.
Client Side¶
Enable option to click on the RSS feed and load the items.
Provide option to add new RSS feed - accept the URL and title.
Implementation¶
Getting Started¶
Create the bootstrap vtlib script in root folder of Vtiger to activate the module entry.
<?php
include_once 'vendor/autoload.php';
include_once 'vtlib/Vtiger/Module.php';
$Vtiger_Utils_Log = true;
$MODULENAME = 'MyRss';
$moduleInstance = Vtiger_Module::getInstance($MODULENAME);
if ($moduleInstance || file_exists('modules/'.$MODULENAME)) {
echo "Module already present - choose a different name.";
} else {
$moduleInstance = new Vtiger_Module();
$moduleInstance->name = $MODULENAME;
$moduleInstance->parent= 'Tools';
$moduleInstance->save();
mkdir('modules/'.$MODULENAME);
echo "OK\n";
}
Schema¶
Vtiger_Utils::CreateTable('vtiger_myrss',
'(id integer not null auto_increment, url varchar(255), title varchar(50), primary key (id))');
Directory Structure¶
- vtigercrm/
- modules/
- MyRss/
MyRss.php -
class MyRss
- views/
views/List.php -
class MyRss_List_View
- models/
models/Record.php -
class MyRss_Record_Model
- actions/
actions/Save.php -
class MyRss_Save_Action
- layouts/
- v7/
- modules/
- MyRss/
- resources/
resources/MyRss.js -
jQuery.Class MyRss_List_Js
jquery_rss_min.js
Code¶
schema.xml¶
<?xml version="1.0"?>
<schema>
<tables>
<table>vtiger_myrss</table>
</tables>
</schema>
MyRss.php¶
<?php
class MyRss {
function vtlib_handler($moduleName, $eventType) {
if ($eventType == 'module.postinstall') {
$data = array('url' => 'https://www.vtiger.com/blogs/?feed=rss2',
'title' => 'Vtiger Blogs');
MyRss_Record_Model::create($data);
}
}
}
views/List.php¶
<?php
class MyRss_List_View extends Vtiger_Index_View {
// We are overriding the default SideBar UI to list our feeds.
public function preProcess(Vtiger_Request $request, $display = true) {
$feeds = MyRss_Record_Model::findAll();
$viewer = $this->getViewer($request);
$viewer->assign('FEEDS', $feeds);
return parent::preProcess($request, $display);
}
// Injecting custom javascript resources
public function getHeaderScripts(Vtiger_Request $request) {
$headerScriptInstances = parent::getHeaderScripts($request);
$moduleName = $request->getModule();
$jsFileNames = array(
"modules.$moduleName.resources.jquery_rss_min", // . = delimiter
);
$jsScriptInstances = $this->checkAndConvertJsScripts($jsFileNames);
$headerScriptInstances = array_merge($headerScriptInstances, $jsScriptInstances);
return $headerScriptInstances;
}
}
models/Record.php¶
<?php
class MyRss_Record_Model extends Vtiger_Base_Model {
public function save() {
$db = PearDatabase::getInstance();
$db->pquery('INSERT INTO vtiger_myrss (url, title) VALUES(?,?)', array(
$this->get('url'), $this->get('title')
));
return $db->getLastInsertID();
}
static function create($data) {
$instance = self::findWithUrl($data['url']);
if ($instance) {
throw new Exception('Duplicate Feed');
}
$instance = new self($data);
return $instance->save();
}
static function findWithUrl($url) {
$db = PearDatabase::getInstance();
$rs = $db->pquery('SELECT * FROM vtiger_myrss WHERE url=?', array($url));
return $db->num_rows($rs)? new self($db->fetch_array($rs)) : NULL;
}
static function findAll() {
$db = PearDatabase::getInstance();
$instances = array();
$rs = $db->pquery('SELECT * FROM vtiger_myrss ORDER BY id DESC', array());
if ($db->num_rows($rs)) {
while ($data = $db->fetch_array($rs)) {
$instances[] = new self($data);
}
}
return $instances;
}
}
actions/Save.php¶
<?php
class MyRss_Save_Action extends Vtiger_Action_Controller {
public function checkPermission() {
return true;
}
public function process(Vtiger_Request $request) {
$feedurl = $request->get('url');
if (empty($feedurl)) {
throw new Exception('URL cannot be empty');
}
$data = array('url' => $feedurl, 'title' => $feedurl);
MyRss_Record_Model::create($data);
$response = new Vtiger_Response();
$response->setResult(array('feed' => $data));
return $response;
}
}
Index.tpl¶
<div class="listViewPageDiv">
<div class="listViewTopMenuDiv">
<div class="listViewActionsDiv">
<div id="RssFeedTitle">
Learn more about RSS
<a href="http://en.wikipedia.org/wiki/RSS" target="_blank">here</a>.
</div>
</div>
</div>
<div id="RssFeedContainer" class="listViewEntriesDiv">
← Selected feed content will be displayed here.
</div>
</div>
<div id="RssFeedAddFormTpl" style="display: none;">
<div class="modelContainer">
<form method="GET" action="javascript:;" class="RssFeedAddForm">
<div class="modal-header">
<a class="close" data-dismiss="modal">x</a>
<h3>New RSS Feed</h3>
</div>
<div class="modal-body">
RSS Feed: <input type="text" name="url" class="validate[required]">
</div>
<div class="modal-footer">
<a class="cancelLink cancelLinkContainer pull-right" data-dismiss="modal">
{vtranslate('LBL_CANCEL')}</a>
<button class="btn btn-success" type="submit">Add</button>
</div>
</form>
</div>
</div>
resources/MyRss.js¶
jQuery.Class('MyRss_List_Js', {}, {
registerEvents: function() {
this.registerFeedClick();
this.registerFeedAdd();
},
registerFeedClick: function() {
jQuery('[data-feedurl]').click(function(e){
e.preventDefault();
var feedAnchor = jQuery(this);
var feedurl = feedAnchor.data('feedurl');
jQuery('#RssFeedTitle').text(feedAnchor.html() + ' - ' + feedurl);
var options = {
limit: 50
}
jQuery('#RssFeedContainer').empty().rss(feedurl, options);
});
},
registerFeedAdd: function() {
jQuery('#RssFeedAdd').click(function(e){
var formTplClone = jQuery('#RssFeedAddFormTpl').clone().css({display: 'block'});
app.showModalWindow(formTplClone, function(){
var targetForm = jQuery('.RssFeedAddForm', formTplClone);
targetForm.validationEngine(app.validationEngineOptions);
targetForm.submit(function(){
if (!targetForm.validationEngine('validate')) {
return;
}
var params = 'module=MyRss&action=Save&';
params += jQuery(targetForm).serialize();
AppConnector.request(params).then(function(response){
window.location.reload();
//app.hideModalWindow();
});
});
});
});
}
});
Distribution¶
You can achieve through Package Export API
Deployment¶
Go to Module Manager Import the module.
You can achieve through Package Import API