I have a simple extbase extension (typo3) with one controller and one model/view. Now i want to "select *" a MSSQL database and output the results in my view. I have not found any reference on how to realize this.
How can i connect to a foreign database from within my extbase/fluid extension and use the data from this database (MSSQL)? How do i execute a query on the "extDB" and how to i print out the result IN my fluid-view.
This is how i integrate the DB (dbal/adodb):
$TYPO3_CONF_VARS['EXTCONF']['dbal']['handlerCfg'] = array(
'extDB' => array(
'type' => 'adodb',
'config' => array(
'driver' => 'mssql',
'username' => 'DB_username',
'password' => 'DB_password',
'host' => 'DB_host',
'database' => 'DB_used',
)
)
);
$TYPO3_CONF_VARS['EXTCONF']['dbal']['table2handlerKeys'] = array (
'VIEW_TABLE1' => 'extDB',
'VIEW_TABLE2' => 'extDB',
);
Any help is appreciated.
You can try extension Database Abstraction Layer (dbal).
Example use global variable $GLOBALS. This is tested on Typo3 4.x, but with little updates(?) maybe working on Typo 6.2 (eg. remove deprecated t3lib_div, and use GeneralUtility...).
class Abstract {
/**
* Access to database
*
*/
private
$msdbHost = 'localhost',
$msdb = 'database-name',
$msdbUsername = 'xxx',
$msdbPassword = 'xxx';
/**
* Connect to MS database
*
*/
public function connectDatabaseMs() {
$GLOBALS['MS_DB'] = t3lib_div::makeInstance('t3lib_DB');
$GLOBALS['MS_DB']->sql_pconnect($this->msdbHost, $this->msdbUsername, $this->msdbPassword);
if($GLOBALS['MS_DB']->link) {
if($GLOBALS['MS_DB']->sql_select_db($this->msdb)) {
return $GLOBALS['MS_DB'];
} else {
t3lib_div::devLog('[tx_rtgms_lib::connectDatabaseUsers] Can not select database "'.$this->msdb.'".', $this->extKey, 3);
}
} else {
t3lib_div::devLog('[tx_rtgms_lib::connectDatabaseUsers] Can not connect to database "'.$this->msdb.'".', $this->extKey, 3);
}
$GLOBALS['MS_DB'] = FALSE;
return FALSE;
}
/**
* Example
*
*/
public function getData() {
$query = 'SELECT ...';
$res = $GLOBALS['HOSTAFF_DB']->sql_query($query);
...
}
}
Related
I am developing a module, it gets order details when order status is changed to "shipped" by admin, to post them to a third-party application with API.
I am using Prestashop V 1.7.7.0.
The hook i'm using is hookActionOrderStatusPostUpdate
The module is installed successfully in the Backoffice and there's no syntax errors, But it doesn't do anything.
Can't figure out what's wrong in my code.
Need help please. Thanks
<?php
/**
* 2007-2021 PrestaShop
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License (AFL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://opensource.org/licenses/afl-3.0.php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license#prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to http://www.prestashop.com for more information.
*
* #author PrestaShop SA <contact#prestashop.com>
* #copyright 2007-2021 PrestaShop SA
* #license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
if (!defined('_PS_VERSION_')) {
exit;
}
class Cargo extends Module
{
protected $config_form = false;
public function __construct()
{
$this->name = 'cargo';
$this->tab = 'administration';
$this->version = '1.0.0';
$this->author = 'tekwave';
$this->need_instance = 1;
/**
* Set $this->bootstrap to true if your module is compliant with bootstrap (PrestaShop 1.6)
*/
$this->bootstrap = true;
parent::__construct();
$this->displayName = $this->l('cargo');
$this->description = $this->l('Ce module permet la synchronisation entre Prestashop et Cargo');
$this->confirmUninstall = $this->l('');
$this->ps_versions_compliancy = array('min' => '1.6', 'max' => _PS_VERSION_);
}
/**
* Don't forget to create update methods if needed:
* http://doc.prestashop.com/display/PS16/Enabling+the+Auto-Update
*/
public function install()
{
Configuration::updateValue('CARGO_LIVE_MODE', false);
return parent::install() &&
$this->registerHook('header') &&
$this->registerHook('backOfficeHeader') &&
$this->registerHook('actionOrderStatusPostUpdate');
}
public function uninstall()
{
Configuration::deleteByName('CARGO_LIVE_MODE');
return parent::uninstall();
}
/**
* Load the configuration form
*/
public function getContent()
{
/**
* If values have been submitted in the form, process.
*/
if (((bool)Tools::isSubmit('submitCargoModule')) == true) {
$this->postProcess();
}
$this->context->smarty->assign('module_dir', $this->_path);
$output = $this->context->smarty->fetch($this->local_path.'views/templates/admin/configure.tpl');
return $output.$this->renderForm();
}
/**
* Create the form that will be displayed in the configuration of your module.
*/
protected function renderForm()
{
$helper = new HelperForm();
$helper->show_toolbar = false;
$helper->table = $this->table;
$helper->module = $this;
$helper->default_form_language = $this->context->language->id;
$helper->allow_employee_form_lang = Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG', 0);
$helper->identifier = $this->identifier;
$helper->submit_action = 'submitCargoModule';
$helper->currentIndex = $this->context->link->getAdminLink('AdminModules', false)
.'&configure='.$this->name.'&tab_module='.$this->tab.'&module_name='.$this->name;
$helper->token = Tools::getAdminTokenLite('AdminModules');
$helper->tpl_vars = array(
'fields_value' => $this->getConfigFormValues(), /* Add values for your inputs */
'languages' => $this->context->controller->getLanguages(),
'id_language' => $this->context->language->id,
);
return $helper->generateForm(array($this->getConfigForm()));
}
/**
* Create the structure of your form.
*/
protected function getConfigForm()
{
return array(
'form' => array(
'legend' => array(
'title' => $this->l('Settings'),
'icon' => 'icon-cogs',
),
'input' => array(
array(
'type' => 'switch',
'label' => $this->l('Live mode'),
'name' => 'CARGO_LIVE_MODE',
'is_bool' => true,
'desc' => $this->l('Use this module in live mode'),
'values' => array(
array(
'id' => 'active_on',
'value' => true,
'label' => $this->l('Enabled')
),
array(
'id' => 'active_off',
'value' => false,
'label' => $this->l('Disabled')
)
),
),
array(
'col' => 3,
'type' => 'text',
'prefix' => '<i class="icon icon-envelope"></i>',
'desc' => $this->l('Enter a valid email address'),
'name' => 'CARGO_ACCOUNT_EMAIL',
'label' => $this->l('Email'),
),
array(
'type' => 'password',
'name' => 'CARGO_ACCOUNT_PASSWORD',
'label' => $this->l('Password'),
),
),
'submit' => array(
'title' => $this->l('Save'),
),
),
);
}
/**
* Set values for the inputs.
*/
protected function getConfigFormValues()
{
return array(
'CARGO_LIVE_MODE' => Configuration::get('CARGO_LIVE_MODE', true),
'CARGO_ACCOUNT_EMAIL' => Configuration::get('CARGO_ACCOUNT_EMAIL', 'contact#prestashop.com'),
'CARGO_ACCOUNT_PASSWORD' => Configuration::get('CARGO_ACCOUNT_PASSWORD', null),
);
}
/**
* Save form data.
*/
protected function postProcess()
{
$form_values = $this->getConfigFormValues();
foreach (array_keys($form_values) as $key) {
Configuration::updateValue($key, Tools::getValue($key));
}
}
/**
* Add the CSS & JavaScript files you want to be loaded in the BO.
*/
public function hookBackOfficeHeader()
{
if (Tools::getValue('module_name') == $this->name) {
$this->context->controller->addJS($this->_path.'views/js/back.js');
$this->context->controller->addCSS($this->_path.'views/css/back.css');
}
}
/**
* Add the CSS & JavaScript files you want to be added on the FO.
*/
public function hookHeader()
{
$this->context->controller->addJS($this->_path.'/views/js/front.js');
$this->context->controller->addCSS($this->_path.'/views/css/front.css');
}
This is my code under hookActionOrderStatusPostUpdate function :
public function hookActionOrderStatusPostUpdate($params)
{
if ($params['newOrderStatus']->id == 6) {
$order = new Order((int)$params['id_order']);
$address = new Address((int)$order->id_address_delivery);
$country = new Country((int)($address->id_country));
$state = new State((int)($address->id_state));
$message = new Message((int)($order->id_message));
$Products = $order->getProducts();
$tel_cl = $address->phone;
$nom_prenom_cl = $address->lastname . ' ' . $address->firstname;
$ville_cl = $country->name;
$delegation_cl = $state->name;
$adresse_cl = $address->address1 . ' ' . $address->address2;
$tel_2_cl = $address->phone_mobile;
$libelle = '';
$nb_piece = 0;
foreach ($Products as $product) {
$libelle .= $product['product_name'] . '<br/>';
$nb_piece += $product['product_quantity'];
}
$cod = $order->total_paid;
$remarque = $message->message;
$Url_str = 'http://admin.cargotunisie.com/cargo_api/set_colis_cargo_get.php?id=1&tel_cl='.$tel_cl.'&nom_prenom_cl='.$nom_prenom_cl.'&ville_cl='.$ville_cl.'&delegation_cl='.$delegation_cl.'&adresse_cl='.$adresse_cl.'&tel_2_cl='.$tel_2_cl.'&libelle='.$libelle.'&cod='.$cod.'&nb_piece='.$nb_piece.'&remarque='.$remarque;
$json = Tools::file_get_contents($Url_str);
$result = json_decode($json);
}
}
}
It could be due to several things.
First: make sure the hook is hooked.
Go to Design > Positions > Then add new hook
Choose your module's name and check if you can select the hook actionOrderStatusPostUpdate. If you can, then it means it was unhooked.
This happens more than we would like, and sometimes you can get crazy until you found it
If that doesn't work you can try this (only if is not on a production site). If it is, just wrap it by using an if that checks if it's from your IP.
Add Tools::dieObject($params); at the beginning of the function.
Then change the an order and check the results. You should see a user friendly list of the values stored in $params.
Make it sure the $params['newOrderStatus'] exists and $params['newOrderStatus']->id is an object.
Also, it should be pretty obvious, but make sure the order ID which are you doing the tests is 6.
With that you should be able to have a general clue of what may be happening.
I would like to implement a login at TYPO3 v8.7. Here it is so that the data comes from a foreign provider who should log in automatically with his login data of his system at TYPO3. I developed something for that.
What is wrong?
// Authentication Service
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addService(
$_EXTKEY,
'auth',
'TEST\\Tests\\Service\\AuthenticationService',
array(
'title' => 'User authentication service',
'description' => 'Authentication with username',
'subtype' => 'getUserFE, authUserFE',
'available' => true,
'priority' => 90,
'quality' => 90,
'os' => '',
'exec' => '',
'className' => 'TEST\\Tests\\Service\\AuthenticationService',
)
);
This is in ext_localconf.php
class AuthenticationService extends \TYPO3\CMS\Sv\AuthenticationService
{
function init() {
$available = parent::init();
return $available;
}
public function getUser(){
$remoteUser = $this->getRemoteUser();
$user = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
'*',
'fe_users',
'username = '.$GLOBALS['TYPO3_DB']->fullQuoteStr($remoteUser, 'fe_users') . ' AND deleted = 0'
);
return $user;
}
public function authUser($user)
{
$userData = $user[0];
foreach ($user[0] as $item => $key) {
if (is_numeric($key)) {
$result_array[$item] = (int) $key;
} else {
$result_array[$item] = $key;
}
}
$this->login = $loginData = array(
'uname' => $userData["username"],
'uident_text' => $userData['password'],
'status' => 'login'
);
$ok = $this->compareUident($result_array, $loginData);
if($ok == 1) {
return 200;
}
return 100;
}
/**
* Returns the remote user.
*
* #return string
*/
protected function getRemoteUser()
{
[...]
return $user;
}
}
Is that all right, what am I doing?
In the function remoteUser I get the username of the third party provider.
Whenever I enter the GET parameter, the AuthService is triggered. However, I get the following error message:
"updateLoginTimestamp () must be of the type integer, null given"
Unfortunately I do not find the mistake I make. Hence my question if anyone sees where this is?
The getUser() Method should Return an Array of the User reccord
which is equal to a database row of fe_users
i am Guessing there is no existing fe_user for the username you get from getRemoteUser thus its the job of the Authentication service to create/update a record for this user in the table fe_users.
so in a more step by stepp manner your service should follow the following steps
in get user:
1. get Remote Username
2. check if Remote Username exists in fe_users table
3. if not create an new entry for Remote Username in fe_users
4. select the entry of Remote Username from fe_users and return the row.
I am currently developing a module for prestashop but I can not find information regarding the registration of data in database. Do you have any idea how to do this?
I started by creating my form in my controller like this:
/**
* Assign template vars related to page content
* #see FrontController::initContent()
*/
public function initContent()
{
parent::initContent();
$this->setTemplate('upload.tpl');
}
public function renderForm()
{
$fields_form = array(
'form' => array(
'input' => array(
array(
'type' => 'file',
'label' => $this->l('Insert file here.'),
'name' => 'FILE_NAME',
'required' => true
),
),
'submit' => array(
'title' => $this->l('Save'),
)
),
);
$helper = new HelperForm();
$helper->show_toolbar = false;
$helper->table = $this->table;
$lang = new Language((int)Configuration::get('PS_LANG_DEFAULT'));
$helper->default_form_language = 1;
$helper->fields_value['FILE_NAME'] = "";
$this->fields_form = array();
$helper->submit_action = 'btnSubmit';
return $helper->generateForm(array($fields_form));
}
Thank you
Actually you have to handle response from the form yourself.
Short answer is "do something like this in your module PHP main file" :
protected function postProcess()
{
$errors = array();
if (Tools::isSubmit('submitFormName'))
{
if (!Configuration::updateValue('FORM_INPUT_NAME', Tools::getValue('FORM_INPUT_NAME')))
$errors[] = $this->l('Cannot update settings');
}
}
Configuration::updateValue($key, $value) stores simple strings in DB. You can add some features (see Configuration.php class).
The best way to handle it is to check what they did in modules/mailalerts/mailalerts.php to have a better idea how to do it. It's a good example.
Matt Loye gave you an easy way to save data. But if you want to create your own table you have to do it during the install process. If you want more examples you can explore the modules that are already installed by default.
You might want to tell us the version you are using, because the modules are a little bit different between PS 1.6 and PS 1.7.
The example below is a part of a custom module that I wrote for PS 1.7.
Installation
public function install()
{
if (!parent::install() || !$this->createTables()
) {
return false;
}
return true;
}
protected function createTables()
{
$res = (bool)Db::getInstance()->execute('
CREATE TABLE IF NOT EXISTS `'._DB_PREFIX_.'my_table` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`column1` varchar(255) NOT NULL,
`column2` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE='._MYSQL_ENGINE_.' DEFAULT CHARSET=UTF8;
return $res;
}
Deinstallation
public function uninstall()
{
if (!parent::uninstall() || !$this->deleteTables()){
return false;
}
return true;
}
protected function deleteTables()
{
return Db::getInstance()->execute('
DROP TABLE IF EXISTS `'._DB_PREFIX_.'my_table`;
');
}
Registration of data
protected function postProcess()
{
if (Tools::isSubmit('submitFormName'))
{
//INSERT
Db::getInstance()->execute('
INSERT INTO `'._DB_PREFIX_.'my_table'` (`column1`, `column2`)
VALUES('.$column1.', '.$column2.')'
);
//OR DELETE DATA
Db::getInstance()->execute('
DELETE FROM `'._DB_PREFIX_.'my_table' `
WHERE `id` = '.(int)$id
);
}
}
I am doing multiple database connection using the tutorial at http://www.yiiframework.com/wiki/544/multiple-database-connection-select-database-based-on-login-user-id-dynamic/ . The code is working fine in the model. But the problem is I am using an extension where I am using db connection using Yii::app()->db; Here I am getting exception Property "CWebApplication.dbadvert" is not defined. The controller of the extension is extended from CExtController. Please help.
In the example you're referring dbadvert is set up for custom active record class RActiveRecord, not for the web application.
If you want to use it like Yii::app()->dbadvert, you would need to set it up in components section of your config.php like this
'dbadvert' => array(
'class' => 'CDbConnection'
*params here*
),
UPD
You can create a wrapper component for CDbConnection, that will change the connection string any way you want and put in as a webapp component.
<?php
class CMultiuserDatabaseConnection extends CApplicationComponent {
public function __call($name, $params) {
$db = $this->db;
return call_user_func_array(($db, $name), $params);
}
public $dbConnectionClass = 'CDbConnection';
public $connections = null;
public $defaultConfiguration = null;
public function getDatabaseConfiguration($user) {
if (!$this->connections) { return array(); }
return array_key_exists($user, $this->connections) ? $this->connections[$user] : $this->defaultConfiguration;
}
public function getDb() {
$user = Yii::app()->user;
if ($user->isGuest) { return false; }
$username = $user->name;
$config = $this->getDatabaseConfiguration($username);
if (!$config) { return false; }
$dsn = array_key_exists('dsn', $config) ? $config['dsn'] : null;
if (!$dsn) { return false; }
$user = array_key_exists('user', $config) ? $config['user'] : null;
$password = array_key_exists('password', $config) ? $config['password'] : null;
$result = new $this->dbConnectionClass($dsn, $user, $password);
return $result;
}
}
That's a crude example of component, which you can set up as your 'db' component and then you'll get 'connections' option for storing the per-user configuration in that way:
'components' => array(
...
'db' => array(
'class' => "CMultiuserDatabaseConnection",
'connections' => array(
"first-user-name" => array(
// just another db configuration here, for user-one
),
"second-user-name" => array(
// just another db configuration herer, for user two
),
...
),
'defaultConfiguration' => array(
/*
* here goes configuration for all other user, that were not specified
* in connections.
*/
),
),
...
),
I wrote the query for the extension in a model as functions. and in the CExtController created an instance of the model. Then I called those functions and everything is working fine.
I have a custom module I'm writing, part of what I want it to do is create a vote associated with a node, I'm trying to figure out how to call the voting API from my module. I loookd in the documentation but it's a little sparse.
Here is an example from a module I wrote a while ago.
while ($data = db_fetch_object($result)) {
$node = node_load($data->nid);
$node_terms = taxonomy_node_get_terms($node);
$vote['value'] = 0;
$vote['value_type'] = 'points';
foreach ($node_terms as $term) {
$vote['value'] = $vote['value'] + $users_tags[$term->name];
}
$vote['content_id'] = $node->nid;
if (isset($vote['content_id'])) {
votingapi_set_votes($vote);
}
}
Just another example of using this:
function _ept_set_vote($nid, $status, $uid = NULL) {
global $user;
$vote = array(
array(
'entity_type' => 'node',
'value' => 1,
'entity_id' => $nid,
'uid' => (!$uid) ? $user->uid : $uid,
'tag' => $status
)
);
votingapi_set_votes($vote, array());
}
I call it like this:
switch($task_status){
case('start'):
_ept_set_vote($nid, "Start");
break;
case('completed'):
_ept_set_vote($nid, "Completed");
break;
}