Duplicate custom HTML module - database

I'm trying to duplicate one of the basic open source Prestahop modules (Custom HTML) because I would need to use it several times with different contents.
I was able to make the relative changes for installing the module (which is installed correctly).
But I was unable to change the part about loading data on the correct table (in fact it changes the same table that is used for the original form).
Could any of you tell me what this behavior is due to?
Thank you so much
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* 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 https://devdocs.prestashop.com/ for more information.
*
* #author PrestaShop SA and Contributors <contact#prestashop.com>
* #copyright Since 2007 PrestaShop SA and Contributors
* #license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
*/
if (!defined('_PS_VERSION_')) {
exit;
}
use PrestaShop\PrestaShop\Adapter\ObjectPresenter;
use PrestaShop\PrestaShop\Core\Module\WidgetInterface;
require_once _PS_MODULE_DIR_ . 'ps_customtext/classes/CustomText.php';
class Ps_Customtext2 extends Module implements WidgetInterface
{
// Equivalent module on PrestaShop 1.6, sharing the same data
const MODULE_16 = 'blockcmsinfo';
/**
* #var string Template used by widget
*/
private $templateFile;
public function __construct()
{
$this->name = 'ps_customtext2';
$this->author = 'PrestaShop';
$this->version = '4.2.0';
$this->need_instance = 0;
$this->bootstrap = true;
parent::__construct();
Shop::addTableAssociation('info', ['type' => 'shop']);
$this->displayName = $this->trans('Custom text block 2', [], 'Modules.Customtext.Admin');
$this->description = $this->trans('Give your visitors extra information, display a customized block of content on your homepage.', [], 'Modules.Customtext.Admin');
$this->ps_versions_compliancy = ['min' => '1.7.4.0', 'max' => _PS_VERSION_];
$this->templateFile = 'module:ps_customtext2/ps_customtext2.tpl';
}
/**
* #return bool
*/
public function install()
{
// Remove 1.6 equivalent module to avoid DB issues
if (Module::isInstalled(self::MODULE_16)) {
return $this->installFrom16Version();
}
return $this->runInstallSteps()
&& $this->installFixtures();
}
/**
* #return bool
*/
public function runInstallSteps()
{
return parent::install()
&& $this->installDB()
&& $this->registerHook('displayHome')
&& $this->registerHook('actionShopDataDuplication');
}
/**
* #return bool
*/
public function installFrom16Version()
{
require_once _PS_MODULE_DIR_ . $this->name . '/classes/MigrateData.php';
$migration = new MigrateData();
$migration->retrieveOldData();
$oldModule = Module::getInstanceByName(self::MODULE_16);
if ($oldModule) {
$oldModule->uninstall();
}
return $this->uninstallDB()
&& $this->runInstallSteps()
&& $migration->insertData();
}
/**
* #return bool
*/
public function uninstall()
{
return parent::uninstall() && $this->uninstallDB();
}
/**
* #return bool
*/
public function installDB()
{
$return = Db::getInstance()->execute('
CREATE TABLE IF NOT EXISTS `' . _DB_PREFIX_ . 'info2` (
`id_info2` INT UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id_info2`)
) ENGINE=' . _MYSQL_ENGINE_ . ' DEFAULT CHARSET=utf8 ;'
);
$return = $return && Db::getInstance()->execute('
CREATE TABLE IF NOT EXISTS `' . _DB_PREFIX_ . 'info_shop2` (
`id_info2` INT(10) UNSIGNED NOT NULL,
`id_shop` INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (`id_info2`, `id_shop`)
) ENGINE=' . _MYSQL_ENGINE_ . ' DEFAULT CHARSET=utf8 ;'
);
$return = $return && Db::getInstance()->execute('
CREATE TABLE IF NOT EXISTS `' . _DB_PREFIX_ . 'info_lang2` (
`id_info2` INT UNSIGNED NOT NULL,
`id_shop` INT(10) UNSIGNED NOT NULL,
`id_lang` INT(10) UNSIGNED NOT NULL ,
`text` text NOT NULL,
PRIMARY KEY (`id_info2`, `id_lang`, `id_shop`)
) ENGINE=' . _MYSQL_ENGINE_ . ' DEFAULT CHARSET=utf8 ;'
);
return $return;
}
/**
* #param bool $drop_table
*
* #return bool
*/
public function uninstallDB($drop_table = true)
{
if (!$drop_table) {
return true;
}
return Db::getInstance()->execute('DROP TABLE IF EXISTS `' . _DB_PREFIX_ . 'info2`, `' . _DB_PREFIX_ . 'info_shop2`, `' . _DB_PREFIX_ . 'info_lang2`');
}
/**
* #return string
*/
public function getContent()
{
$output = '';
if (Tools::isSubmit('saveps_customtext')) {
if (!Tools::getValue('text_' . (int) Configuration::get('PS_LANG_DEFAULT'), false)) {
$output = $this->displayError($this->trans('Please fill out all fields.', [], 'Admin.Notifications.Error'));
} else {
$update = $this->processSaveCustomText();
if (!$update) {
$output = '<div class="alert alert-danger conf error">'
. $this->trans('An error occurred on saving.', [], 'Admin.Notifications.Error')
. '</div>';
}
$this->_clearCache($this->templateFile);
if ($update) {
Tools::redirectAdmin($this->context->link->getAdminLink('AdminModules') . '&configure=' . $this->name . '&conf=4');
}
}
}
return $output . $this->renderForm();
}
/**
* #return bool
*/
public function processSaveCustomText()
{
$shops = Tools::getValue('checkBoxShopAsso_configuration', [$this->context->shop->id]);
$text = [];
$languages = Language::getLanguages(false);
foreach ($languages as $lang) {
$text[$lang['id_lang']] = (string) Tools::getValue('text_' . $lang['id_lang']);
}
$saved = true;
foreach ($shops as $shop) {
Shop::setContext(Shop::CONTEXT_SHOP, $shop);
$info = new CustomText(Tools::getValue('id_info2', 2));
$info->text = $text;
$saved = $saved && $info->save();
}
return $saved;
}
/**
* #return string
*/
protected function renderForm()
{
$default_lang = (int) Configuration::get('PS_LANG_DEFAULT');
$fields_form = [
'tinymce' => true,
'legend' => [
'title' => $this->trans('Custom text block', [], 'Modules.Customtext.Admin'),
],
'input' => [
'id_info2' => [
'type' => 'hidden',
'name' => 'id_info2',
],
'content' => [
'type' => 'textarea',
'label' => $this->trans('Text block 2', [], 'Modules.Customtext.Admin'),
'lang' => true,
'name' => 'text',
'cols' => 40,
'rows' => 10,
'class' => 'rte',
'autoload_rte' => true,
],
],
'submit' => [
'title' => $this->trans('Save', [], 'Admin.Actions'),
],
];
if (Shop::isFeatureActive() && Tools::getValue('id_info2') == false) {
$fields_form['input'][] = [
'type' => 'shop',
'label' => $this->trans('Shop association', [], 'Admin.Global'),
'name' => 'checkBoxShopAsso_theme',
];
}
$helper = new HelperForm();
$helper->module = $this;
$helper->name_controller = 'ps_customtext2';
$helper->identifier = $this->identifier;
$helper->token = Tools::getAdminTokenLite('AdminModules');
foreach (Language::getLanguages(false) as $lang) {
$helper->languages[] = [
'id_lang' => $lang['id_lang'],
'iso_code' => $lang['iso_code'],
'name' => $lang['name'],
'is_default' => ($default_lang == $lang['id_lang'] ? 1 : 0),
];
}
$helper->currentIndex = AdminController::$currentIndex . '&configure=' . $this->name;
$helper->default_form_language = $default_lang;
$helper->allow_employee_form_lang = $default_lang;
$helper->toolbar_scroll = true;
$helper->title = $this->displayName;
$helper->submit_action = 'saveps_customtext';
$helper->fields_value = $this->getFormValues();
return $helper->generateForm([['form' => $fields_form]]);
}
/**
* #return array<string, mixed>
*/
public function getFormValues()
{
$fields_value = [];
$idShop = $this->context->shop->id;
$idInfo = CustomText::getCustomTextIdByShop($idShop);
Shop::setContext(Shop::CONTEXT_SHOP, $idShop);
$info = new CustomText((int) $idInfo);
$fields_value['text'] = $info->text;
$fields_value['id_info2'] = $idInfo;
return $fields_value;
}
/**
* #param string|null $hookName
* #param array $configuration
*
* #return string
*/
public function renderWidget($hookName = null, array $configuration = [])
{
if (!$this->isCached($this->templateFile, $this->getCacheId('ps_customtext2'))) {
$this->smarty->assign($this->getWidgetVariables($hookName, $configuration));
}
return $this->fetch($this->templateFile, $this->getCacheId('ps_customtext2'));
}
/**
* #param string|null $hookName
* #param array $configuration
*
* #return array<string, mixed>
*/
public function getWidgetVariables($hookName = null, array $configuration = [])
{
$customText = new CustomText(1, (int) $this->context->language->id, (int) $this->context->shop->id);
$objectPresenter = new ObjectPresenter();
$data = $objectPresenter->present($customText);
$data['id_lang'] = $this->context->language->id;
$data['id_shop'] = $this->context->shop->id;
unset($data['id']);
return ['cms_infos' => $data];
}
/**
* #return bool
*/
public function installFixtures()
{
$return = true;
$tabTexts = [
[
'text' => '<h2>Custom Text Block 2</h2>
<p><strong class="dark">Lorem ipsum dolor sit amet conse ctetu</strong></p>
<p>Sit amet conse ctetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit.</p>',
],
];
$shopsIds = Shop::getShops(true, null, true);
$languages = Language::getLanguages(false);
$text = [];
foreach ($tabTexts as $tab) {
$info = new CustomText();
foreach ($languages as $lang) {
$text[$lang['id_lang']] = $tab['text'];
}
$info->text = $text;
$return = $return && $info->add();
}
if ($return && count($shopsIds) > 1) {
foreach ($shopsIds as $idShop) {
Shop::setContext(Shop::CONTEXT_SHOP, $idShop);
$info->text = $text;
$return = $return && $info->save();
}
}
return $return;
}
/**
* Add CustomText when adding a new Shop
*
* #param array{cookie: Cookie, cart: Cart, altern: int, old_id_shop: int, new_id_shop: int} $params
*/
public function hookActionShopDataDuplication(array $params)
{
if ($infoId = CustomText::getCustomTextIdByShop($params['old_id_shop'])) {
Shop::setContext(Shop::CONTEXT_SHOP, $params['old_id_shop']);
$oldInfo = new CustomText($infoId);
Shop::setContext(Shop::CONTEXT_SHOP, $params['new_id_shop']);
$newInfo = new CustomText($infoId, null, $params['new_id_shop']);
$newInfo->text = $oldInfo->text;
$newInfo->save();
}
}
}

Related

Duplicate rows in the database when refreshing the page laravel

there is a page which is updated every 5-7 seconds, and on it records from the base are updated, but moments these records are duplicated, Do not tell me why this bug can be?
is a ActiveCaller model
namespace App;
use Illuminate\Database\Eloquent\Model;
use Carbon\Carbon;
class ActiveCaller extends Model
{
protected $fillable = ['queue', 'employee_id', 'station', 'state', 'duration',
'client_id', 'last_call'];
public function Employee()
{
return $this->belongsTo(Employee::class);
}
/**
* Convert duration attribute to acceptable format
*
* #param $value
* #return string
*/
public function getDurationAttribute($value)
{
if (empty($value))
return $value;
return $this->sec2hms($value);
}
public function getStateAttribute($value)
{
if (!empty($value))
return trim($value);
return null;
}
/**
* Convert last call attribute to acceptable format
*
* #param $value
* #return string
*/
public function getLastCallAttribute($value)
{
$data = explode("\n", $value);
$result = "";
$i = 0;
$len = count($data) - 1;
foreach ($data as $item) {
$item = str_replace("\r", "", $item);
$delimiter = "</br>";
if ($i == $len)
$delimiter = "";
if (empty($item) || (trim($item) == "No calls yet")) {
$result .= "No calls yet$delimiter";
} else {
$result .= $this->sec2hms($item) . " min. ago $delimiter";
}
$i++;
}
return $result;
}
public function getStationAttribute($value)
{
return str_replace("\r\n", "</br>", $value);
}
private function sec2hms($sec, $padHours = FALSE)
{
$timeStart = Carbon::now();
$timeEnd = Carbon::now()->addSeconds(intval($sec));
return $timeStart->diff($timeEnd)->format('%H:%I:%S');
}
}
is a AmiApiController
class AmiApiController extends Controller
{
public function fetchDashboardData()
{
$this->updateQueueState();
$activeCallers = ActiveCaller::with('Employee')
->where('old', true)
->orderBy('queue')
->orderBy('employee_id')
->orderBy('station', 'asc')
->get();
$waitingList = WaitingList::where('old', false)->get();
$waitingList = $waitingList->unique('client_id');
$charts = Chart::all()->toArray();
$chartFormatData = [
'Total' => [],
'Callers' => [],
'Queues' => [],
];
foreach ($charts as $key => $chart) {
$charts[$key]['data'] = json_decode($chart['data'], 1);
$chartFormatData[$chart['name']]['total'] = 0;
foreach ($charts[$key]['data']['statistic'] as $datum) {
// if ($datum[0] === 'Effort')
// continue;
$chartFormatData[$chart['name']]['label'][] = $datum[0];
$chartFormatData[$chart['name']]['data'][] = $datum[1];
$chartFormatData[$chart['name']]['name'] = $chart['name'];
}
$chartFormatData[$chart['name']]['total'] = array_sum($chartFormatData[$chart['name']]['data']);
// $chartFormatData[$chart['name']]['label'] = array_reverse($chartFormatData[$chart['name']]['label']);
}
return response()->json([
'activeCallers' => $activeCallers,
'charts' => $chartFormatData,
'waitingList' => $waitingList
], 200);
}
this is where we begin to check if we can update the database at this time
/**
* Check whether the database can be updated at this time
*
* - Returns True if no updates are currently being made to the database
* and the latest update was less than 5 seconds later
* -
Returns True if the update already occurs for more than 15 seconds
*
* - Returns False if an update is already in the database
* -
Returns False if the last update was within the last 5 seconds
*
* If the parameter in $ json is passed true (by default)
* the method returns the answer in JSON format
*
* If the parameter is passed false to $ json
* method returns a php-shne Boolean value
*
* #param bool $json
* #return bool|\Illuminate\Http\JsonResponse
*/
public function canWeUpdate($json = true)
{
$result = ['return' => null, 'msg' => null];
$isUpdating = Configuration::where('key', 'is_ami_data_updating')->first();
if (is_null($isUpdating)) {
Configuration::create(['key' => 'is_ami_data_updating', 'value' => 0]);
}
if ($isUpdating->value == true) {
// if an update is currently in progress
$checkingDate = Carbon::now()->addSeconds(-10);
if ($isUpdating->updated_at < $checkingDate) {
// if the update is longer than 15 seconds, we will cancel this update
$isUpdating->update(['value' => false]);
$result['return'] = true;
$result['msg'] = "Old update in database";
} else {
// if the update is less than 15 seconds, we cannot update again
$result['return'] = false;
$result['msg'] = "CURRENTLY UPDATE";
}
} else if ($isUpdating->updated_at > Carbon::now()->addSeconds(-3)) {
// if the last update was less than 5 seconds ago, we cannot update
$result['return'] = false;
$result['msg'] = "TOO EARLY";
} else {
//if the last update was more than 5 seconds ago, we allow the update
$result['return'] = true;
$result['msg'] = "OK";
}
if ($json)
return $this->simpleResponse($result['return'], $result['msg']);
return $result['return'];
}
is a method fot check if new data is in the database
/**
* A method to check if new data is in the database
*
* Returns True if validation time is less than database update time
* Returns False if validation time is longer than database update time
* Returns False if there is no data in the database
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\JsonResponse
*/
public function checkForNewData(Request $request)
{
$date = new Carbon($request->last_call);
$lastRecord = ActiveCaller::latest()->first();
if (is_null($lastRecord))
return $this->simpleResponse(false);
if ($date < $lastRecord->updated_at) {
return $this->simpleResponse(true);
} else
return $this->simpleResponse(false);
}
/**
* Method for loading table data
*
* Agents - information about active numbers in the PBX in all queues
* Waiting - information about numbers in standby mode
*
* #return \Illuminate\Http\JsonResponse
*/
public function renderAgentTable()
{
$agents = ActiveCaller::with('Employee')
->where('old', true)
->orderBy('queue')
->orderBy('station', 'asc')
->get();
$waitingList = WaitingList::all();
$agentsTable = View::make('dashboard.render.agent-table', ['agents' => $agents]);
$waitingTable = View::make('dashboard.render.waiting-list-table', ['waitingList' => $waitingList]);
$result =
[
'agents' => $agentsTable->render(),
'waiting' => $waitingTable->render(),
];
$result = array_merge($result, $this->renderDashboardChart(new Request()));
return response()->json($result);
}
/**
* Method for updating data from AMI
*
* updating data for ActiveCaller
* updating data for WaitingList
*/
public function updateQueueState()
{
if (!$this->canWeUpdate(false)) {
// dd("We can't update (large check)");
return;
}
$lastUpdateTime = ActiveCaller::latest()->first();
if ($lastUpdateTime != null)
if ($lastUpdateTime->created_at > Carbon::now()->addSeconds(-3)) {
// dd("We can't update (small check)");
return;
}
// we notice the launch of the update in the database
$isAmiDataUpdating = Configuration::where('key', 'is_ami_data_updating')->first();
$isAmiDataUpdating->update(['value' => true]);
$this->ClearOldRecords();
$queues = Queue::where('on_dashboard', '=', '1')->get()->toArray();
// we go through all the queues that are available in AMI
foreach ($queues as $queue) {
$command = new AMIQueueMemberState($queue['name']);
// we get a list of numbers and a waiting list of calls
$response = $command->handle();
$agents = $response['agents'];
$callers = $response['callers'];
//convert the waiting list to PeerList
$peerList = PeerInfo::hydrate($agents);
$employees = new Collection();
foreach ($callers as $caller) {
$caller['queue'] = $queue['name'];
WaitingList::create($caller);
}
$peerList->each(function (PeerInfo $peer) use ($employees) {
$record = Record
::where('phone', 'like', '%' . $peer->name . '%')
->where('end_date', null)
->get()->first();
$data = null;
if ($record != null) {
// check if this user already has an entry in active_callers (not old)
$active = ActiveCaller
::where('employee_id', $record['employee_id'])
->where('old', false)
->get()->first();
// if so, add him another number and
// we move on to the next iteration
if ($active != null) {
if ($this->HandleSingleActive($active, $peer->name, $peer->last_call))
return;
}
$peer->station = $record['station_name'];
$peer->employee_id = $record['employee_id'];
$a = collect($peer->toArray());
$data = $a->except(['name', 'pause'])->toArray();
$data['station'] = "$peer->station | $peer->name";
} else {
$peer->station = "- | $peer->name";
$a = collect($peer->toArray());
$data = $a->except(['name', 'pause'])->toArray();
}
ActiveCaller::create($data);
});
}
$this->updateDashboardChart();
$isAmiDataUpdating->update(['value' => false]);
}

Cakephp 3 PHPUnit ingration test fails after the test before

I have the UsersFixture with three records.
The test methods first() and second(), which both are before guest_can_login(), pr's show "Joe", "Joe", as expected. But with test method third(), which comes after guest_can_login(), I get notice error: trying to get property of non-object.
So, for a reason, something in the guest_can_login() breaks the rest of the test methods. I have tried by making a duplicate of guest_can_login() as well.
I think it is strange, as tearDown should "reset" everything after each test. I'm out of ideas. And after reading the Cakephp Testing docs, I haven't been able to solve it.
Any suggestions to help me solve this is much appreciated.
Code below (gist if you prefer: https://gist.github.com/chris-andre/2eb3ad053073caf4f1c81722428a900b):
public $fixtures = [
'app.users',
'app.tenants',
'app.roles',
'app.roles_users',
];
public $Users;
public function setUp()
{
parent::setUp();
$config = TableRegistry::getTableLocator()->exists('Users') ? [] : ['className' => UsersTable::class];
$this->Users = TableRegistry::getTableLocator()->get('Users', $config);
}
/**
* tearDown method
*
* #return void
*/
public function tearDown()
{
unset($this->Users);
TableRegistry::clear();
parent::tearDown();
}
/** #test */
public function guest_can_register()
{
$this->enableCsrfToken();
$this->enableSecurityToken();
$this->configRequest([
'headers' => [
'host' => 'timbas.test'
]
]);
$data = [
'email' => 'chris#andre.com',
'first_name' => 'Christian',
'last_name' => 'Andreassen',
'password' => '123456',
'tenant' => ['name' => 'Test Company AS', 'domain' => 'testcomp', 'active' => true],
'active' => true
];
$this->post('/register', $data);
$this->assertResponseSuccess();
$this->assertRedirect(['controller' => 'Users', 'action' => 'login', '_host' => 'testcomp.timbas.test']);
$user = $this->Users->find()
->contain(['Tenants', 'Roles'])
->where(['Users.email' => 'chris#andre.com'])
->first();
}
/** #test */
public function first()
{
$users = $this->Users->find()->first();
pr($users->first_name);
}
/** #test */
public function second()
{
$users = $this->Users->find()->first();
pr($users->first_name);
}
/** #test */
public function guest_can_login()
{
$this->enableCsrfToken();
$this->enableSecurityToken();
$this->configRequest([
'headers' => [
'host' => 'testcomp.timbas.test'
]
]);
$data = [
'email' => 'chris#andre.com',
'first_name' => 'Christian',
'last_name' => 'Andreassen',
'password' => '123456',
'tenant' => ['name' => 'Test Company AS', 'domain' => 'testcomp', 'active' => true],
'active' => true,
'roles' => ['_ids' => [ADMINISTRATOR_ROLE_ID]]
];
$user = $this->Users->newEntity($data, [
'associated' => ['Tenants', 'Roles']
]);
$this->Users->save($user);
$getNewUser = $this->Users->find()
->contain(['Roles'])
->where(['Users.email' => 'chris#andre.com'])
->first()
->toArray();
// pr($getNewUser->id);
$this->post('/users/login', [
'email' => 'chris#andre.com',
'password' => '123456'
]);
$this->assertSession($getNewUser, 'Auth.User');
}
/** #test */
public function third()
{
$users = $this->Users->find()->first();
pr($users->first_name);
}
EDIT 2018-08-06:
Users::register() is a global context, I cannot be accessed from url with subdomain. E.g. tenant1.domain.com/register will throw a badRequest, while domain.com/register is a valid url. On registration success, user is forwarded to login from right url. Login-url = Tenants.domain + domain + suffix, e.g. tenant1.domain.com. When user is on the tenant scope (url with subdomain), the Tenants.id where Tenants.domain = tenant1, will be added to the where clause in all queries for the models having the behavior attached.
Now, what happens in third() is that the tenant_id from the newly created Tenant in guest_can_login() is added to the query, which means the test "is still on the tenant scope" when third() is run. That is the problem.
The other problem is that setUp() is called on all test methods but third(). testDown() is called on every test methods.
App\Middleware\TenantMiddleware.php:
use InstanceConfigTrait;
/**
* Default config.
* Options:
* - globalScope: tells the middleware what controller and action tenant scope is not being used
* Example
* 'globalScope' => [
* 'Pages' => ['*'], // All actions in PagesController is global
* 'Users' => ['register'] // Register action in UsersController is global
* ]
* #var array
*/
protected $_defaultConfig = [
'globalScope' => [
'Users' => ['register'],
'Landing' => ['*'],
'Pages' => ['*']
],
];
public function __construct($config = [])
{
if (!isset($config['primaryDomain'])) {
$config['primaryDomain'] = Configure::read('Site.domain');
}
$this->setConfig($config);
}
/**
* Invoke method.
*
* #param \Cake\Http\ServerRequest $request The request.
* #param \Psr\Http\Message\ResponseInterface $response The response.
* #param callable $next Callback to invoke the next middleware.
* #return \Psr\Http\Message\ResponseInterface A response
*/
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, $next)
{
// Get subdomains
$subdomains = $request->subdomains();
// If subdomains not empty, the first is always the tenants domain
$subdomain = !empty($subdomains) ? $subdomains[0] : '';
Tenant::setDomain($subdomain);
// Get params of current request
$params = $request->getAttribute('params');
$controller = $params['controller'];
$action = $params['action'];
// Set tenantScope as default
Tenant::setScope('tenant');
$globalScope = $this->getConfig('globalScope');
// If Controller and action is a global scope
if (array_key_exists($controller, $globalScope)) {
if (in_array($action, $globalScope[$controller]) || in_array('*', $globalScope[$controller])) {
Tenant::setScope('global');
}
}
if (
(Tenant::getScope() === 'tenant' && Tenant::tenant() === null)
|| (Tenant::getDomain() === '' && Tenant::getScope() === 'tenant')
|| (Tenant::getDomain() !== '' && Tenant::getScope() === 'global')
) {
throw new NotFoundException('The page you are looking for does not exists.');
}
$primaryDomain = $this->getConfig('primaryDomain');
if (array_key_exists($controller, $globalScope)) {
if (in_array($action, $globalScope[$controller]) && Tenant::getScope() === 'global') {
}
}
return $next($request, $response);
}
App\Model\Behavior\TenantScopeBehavior.php:
protected $_table;
/**
* Default configuration.
*
* #var array
*/
protected $_defaultConfig = [];
public function __construct(Table $table, array $config = [])
{
parent::__construct($table, $config);
}
public function beforeFind(Event $event, Query $query, ArrayObject $options)
{
$model = $this->_table->getAlias();
$foreig_key = 'tenant_id';
if (!isset($options['skipTenantCheck']) || $options['skipTenantCheck'] !== true) {
if (Tenant::getScope() === 'tenant') {
if ($model === 'Tenants') {
$query->where(['Tenants.id' => Tenant::tenant()->id]);
} else {
$query->where([$model . '.' . $foreig_key => Tenant::tenant()->id]);
}
}
}
return $query;
}
public function beforeSave(Event $event, Entity $entity, $options)
{
if (Tenant::getScope() === 'tenant') {
if ($entity->isNew()) {
$entity->tenant_id = Tenant::tenant()->id;
} else {
// Check if current tenant is owner
if ($this->_table->getAlias() === 'Tenants') {
if ($entity->id != Tenant::tenant()->id) {
throw new BadRequestException();
}
} else {
if ($entity->tenant_id != Tenant::tenant()->id) {
throw new BadRequestException();
}
}
}
}
return true;
}
public function beforeDelete(Event $event, Entity $entity, $options)
{
if (Tenant::getScope() === 'tenant') {
if ($entity->tenant_id != Tenant::tenant()->id) { //current tenant is NOT owner
throw new BadRequestException();
}
}
return true;
}
App\Tenant\Tenant.php:
/**
* $_domain will be empty or comtain the domain (subdomain from url)
* #var string can be empty
*/
protected static $_domain;
/**
* $_scope shall be 'global' or 'tenant'.
* #var string
*/
protected static $_scope;
/**
* #var null|object \App\Model\Entity\Tenant
*/
protected static $_tenant;
/**
* Gets domain from $_domain and returns the string
* #return string
*/
public static function getDomain()
{
return self::$_domain;
}
/**
* Set the tenant scope domain. Will be set in the TenantMiddleware, and shall not be set anywhere else
* #param string $domain
* #return string empty or with domain
*/
public static function setDomain($domain)
{
self::$_domain = $domain;
}
/**
* Tenant method
* Return the object \App\Model\Table\Tenants ro null
* #return type
*/
public static function tenant()
{
$tenant = static::_getTenant();
return $tenant;
}
protected static function _getTenant()
{
if (self::$_tenant === null) {
$cachedTenants = Cache::read('tenants');
if($cachedTenants !== false) {
// do something
}
$tenantsTable = TableRegistry::get('Tenants');
$tenant = $tenantsTable->find('all', ['skipTenantCheck' => true])
->where(['Tenants.domain' => self::getDomain()])
->where(['Tenants.active' => true])
->first();
self::$_tenant = $tenant;
}
return self::$_tenant;
}
public static function getScope()
{
return self::$_scope;
}
/**
* Description
* #param type $scope
* #return type
*/
public static function setScope($scope)
{
self::$_scope = $scope;
}

Decoding JSON array laravel

Hello i am having slight trouble with arrays in my application. I have a table in my database called "contacts" inside that table i have a column "info" of datatype 'TEXT' where i store a json encoded array. This is my function:
/**
* Store a newly created resource in storage.
*
* #return Response
*/
public function store(Request $request)
{
$contact = new Contacts;
$contact->type = $request->type;
$contact->name = str_replace(' ', ' ', $request->type == 'person' ? $request->first_name . ' ' . $request->other_name . ' ' . $request->last_name : $request->description);
$contact->email = $request->email;
$contact->info = json_encode($request->info);
if ($contact->save())
{
return [
'success' => 'Data was saved successfully!'
];
}
}
Now this saves perfectly however the issues is when i retrieving the data from the database it returns that column as a "string" and as such i am unable to access that array from my front-end javascript (i use angular).
I have tried decoding the entire returned result but that did not work, still had the same problem:
/**
* Display a listing of the resource.
*
* #return Response
*/
public function index()
{
$type = Input::get('type');
$contacts = "";
if (empty($type))
{
$contacts = Contacts::get();
}
elseif ($type == 'persons')
{
$contacts = Contacts::where('type', 'person')->get();
}
elseif ($type == 'companies')
{
$contacts = Contacts::where('type', 'company')->get();
}
return [
'contacts' => json_decode($contacts)
];
}
Use the $casts property on your model:
class Contacts extends Eloquent
{
protected $casts = ['inof' => 'json'];
}
It'll handle all encoding/decoding for you.
$contact->info = $request->info;

cakephp get query logs when debug is set to 0

How can you get a list of the executed queries when debug is set to 0 ?
I have the following functions in AppController:
// log INSERT, UPDATE, DELETE queries
private function __logQueries(){
$db = &ConnectionManager::getDataSource('default');
$query_logs = $db->getLog();
if( isset($query_logs['log']) && !empty($query_logs['log']) ){
$this->loadModel('SqlLog');
foreach($query_logs['log'] as $log_q){
$query = $log_q['query'];
if( stristr($query, 'INSERT ') || stristr($query, 'UPDATE ') || stristr($query, 'DELETE ') ){
$q_data = array(
'query' => $query,
'page' => $this->Misc->getCurrentPageURL(), // get the current page
'referrer' => trim(env('HTTP_REFERER')) == '' ? '' : env('HTTP_REFERER'),
'ip' => env('REMOTE_ADDR'),
'browser' => env('HTTP_USER_AGENT'),
'user_id' => SessionComponent::check('Auth.User') ? SessionComponent::read('Auth.User.id') : 0,
'username' => SessionComponent::check('Auth.User') ? addslashes(SessionComponent::read('Auth.User.username')) : '',
);
$this->SqlLog->create();
$this->SqlLog->save($q_data);
}
}
} // end if query occured
}
public function beforeRedirect(){
$this->__logQueries();
}
public function afterFilter(){
$this->__logQueries();
}
The insert, update and delete queries get logged when debug is set to 2, but how can I log those queries when debug is set to 0?
Whether queries are being logged depends on the DboSource::$fullDebug property, it's being set in the DboSource constructur, and by default it's true in case debug is > 1.
So all you have to do is overwrite the value of this property with true, this will ensure that as of this point the queries are being logged regardless of the debug setting.
App::uses('ConnectionManager', 'Model');
ConnectionManager::getDataSource('default')->fullDebug = true;
Create your own dbo file in the specified path:
\app\models\datasources\dbo\dbo_mysql_with_log.php
and the content of this file will be
<?php
class DboMysqlBase extends DboSource {
/**
* Description property.
*
* #var string
*/
var $description = "MySQL DBO Base Driver";
/**
* Start quote
*
* #var string
*/
var $startQuote = "`";
/**
* End quote
*
* #var string
*/
var $endQuote = "`";
/**
* use alias for update and delete. Set to true if version >= 4.1
*
* #var boolean
* #access protected
*/
var $_useAlias = true;
/**
* Index of basic SQL commands
*
* #var array
* #access protected
*/
var $_commands = array(
'begin' => 'START TRANSACTION',
'commit' => 'COMMIT',
'rollback' => 'ROLLBACK'
);
/**
* MySQL column definition
*
* #var array
*/
var $columns = array(
'primary_key' => array('name' => 'NOT NULL AUTO_INCREMENT'),
'string' => array('name' => 'varchar', 'limit' => '255'),
'text' => array('name' => 'text'),
'integer' => array('name' => 'int', 'limit' => '11', 'formatter' => 'intval'),
'float' => array('name' => 'float', 'formatter' => 'floatval'),
'datetime' => array('name' => 'datetime', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
'timestamp' => array('name' => 'timestamp', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
'time' => array('name' => 'time', 'format' => 'H:i:s', 'formatter' => 'date'),
'date' => array('name' => 'date', 'format' => 'Y-m-d', 'formatter' => 'date'),
'binary' => array('name' => 'blob'),
'boolean' => array('name' => 'tinyint', 'limit' => '1')
);
/**
* Generates and executes an SQL UPDATE statement for given model, fields, and values.
*
* #param Model $model
* #param array $fields
* #param array $values
* #param mixed $conditions
* #return array
*/
function update(&$model, $fields = array(), $values = null, $conditions = null) {
if (!$this->_useAlias) {
return parent::update($model, $fields, $values, $conditions);
}
if ($values == null) {
$combined = $fields;
} else {
$combined = array_combine($fields, $values);
}
$alias = $joins = false;
$fields = $this->_prepareUpdateFields($model, $combined, empty($conditions), !empty($conditions));
$fields = join(', ', $fields);
$table = $this->fullTableName($model);
if (!empty($conditions)) {
$alias = $this->name($model->alias);
if ($model->name == $model->alias) {
$joins = implode(' ', $this->_getJoins($model));
}
}
$conditions = $this->conditions($this->defaultConditions($model, $conditions, $alias), true, true, $model);
if ($conditions === false) {
return false;
}
if (!$this->execute($this->renderStatement('update', compact('table', 'alias', 'joins', 'fields', 'conditions')))) {
$model->onError();
return false;
}
return true;
}
/**
* Generates and executes an SQL DELETE statement for given id/conditions on given model.
*
* #param Model $model
* #param mixed $conditions
* #return boolean Success
*/
function delete(&$model, $conditions = null) {
if (!$this->_useAlias) {
return parent::delete($model, $conditions);
}
$alias = $this->name($model->alias);
$table = $this->fullTableName($model);
$joins = implode(' ', $this->_getJoins($model));
if (empty($conditions)) {
$alias = $joins = false;
}
$conditions = $this->conditions($this->defaultConditions($model, $conditions, $alias), true, true, $model);
if ($conditions === false) {
return false;
}
if ($this->execute($this->renderStatement('delete', compact('alias', 'table', 'joins', 'conditions'))) === false) {
$model->onError();
return false;
}
return true;
}
/**
* Sets the database encoding
*
* #param string $enc Database encoding
*/
function setEncoding($enc) {
return $this->_execute('SET NAMES ' . $enc) != false;
}
/**
* Returns an array of the indexes in given datasource name.
*
* #param string $model Name of model to inspect
* #return array Fields in table. Keys are column and unique
*/
function index($model) {
$index = array();
$table = $this->fullTableName($model);
if ($table) {
$indexes = $this->query('SHOW INDEX FROM ' . $table);
if (isset($indexes[0]['STATISTICS'])) {
$keys = Set::extract($indexes, '{n}.STATISTICS');
} else {
$keys = Set::extract($indexes, '{n}.0');
}
foreach ($keys as $i => $key) {
if (!isset($index[$key['Key_name']])) {
$col = array();
$index[$key['Key_name']]['column'] = $key['Column_name'];
$index[$key['Key_name']]['unique'] = intval($key['Non_unique'] == 0);
} else {
if (!is_array($index[$key['Key_name']]['column'])) {
$col[] = $index[$key['Key_name']]['column'];
}
$col[] = $key['Column_name'];
$index[$key['Key_name']]['column'] = $col;
}
}
}
return $index;
}
/**
* Generate a MySQL Alter Table syntax for the given Schema comparison
*
* #param array $compare Result of a CakeSchema::compare()
* #return array Array of alter statements to make.
*/
function alterSchema($compare, $table = null) {
if (!is_array($compare)) {
return false;
}
$out = '';
$colList = array();
foreach ($compare as $curTable => $types) {
$indexes = array();
if (!$table || $table == $curTable) {
$out .= 'ALTER TABLE ' . $this->fullTableName($curTable) . " \n";
foreach ($types as $type => $column) {
if (isset($column['indexes'])) {
$indexes[$type] = $column['indexes'];
unset($column['indexes']);
}
switch ($type) {
case 'add':
foreach ($column as $field => $col) {
$col['name'] = $field;
$alter = 'ADD '.$this->buildColumn($col);
if (isset($col['after'])) {
$alter .= ' AFTER '. $this->name($col['after']);
}
$colList[] = $alter;
}
break;
case 'drop':
foreach ($column as $field => $col) {
$col['name'] = $field;
$colList[] = 'DROP '.$this->name($field);
}
break;
case 'change':
foreach ($column as $field => $col) {
if (!isset($col['name'])) {
$col['name'] = $field;
}
$colList[] = 'CHANGE '. $this->name($field).' '.$this->buildColumn($col);
}
break;
}
}
$colList = array_merge($colList, $this->_alterIndexes($curTable, $indexes));
$out .= "\t" . join(",\n\t", $colList) . ";\n\n";
}
}
return $out;
}
/**
* Generate a MySQL "drop table" statement for the given Schema object
*
* #param object $schema An instance of a subclass of CakeSchema
* #param string $table Optional. If specified only the table name given will be generated.
* Otherwise, all tables defined in the schema are generated.
* #return string
*/
function dropSchema($schema, $table = null) {
if (!is_a($schema, 'CakeSchema')) {
trigger_error(__('Invalid schema object', true), E_USER_WARNING);
return null;
}
$out = '';
foreach ($schema->tables as $curTable => $columns) {
if (!$table || $table == $curTable) {
$out .= 'DROP TABLE IF EXISTS ' . $this->fullTableName($curTable) . ";\n";
}
}
return $out;
}
/**
* Generate MySQL index alteration statements for a table.
*
* #param string $table Table to alter indexes for
* #param array $new Indexes to add and drop
* #return array Index alteration statements
*/
function _alterIndexes($table, $indexes) {
$alter = array();
if (isset($indexes['drop'])) {
foreach($indexes['drop'] as $name => $value) {
$out = 'DROP ';
if ($name == 'PRIMARY') {
$out .= 'PRIMARY KEY';
} else {
$out .= 'KEY ' . $name;
}
$alter[] = $out;
}
}
if (isset($indexes['add'])) {
foreach ($indexes['add'] as $name => $value) {
$out = 'ADD ';
if ($name == 'PRIMARY') {
$out .= 'PRIMARY ';
$name = null;
} else {
if (!empty($value['unique'])) {
$out .= 'UNIQUE ';
}
}
if (is_array($value['column'])) {
$out .= 'KEY '. $name .' (' . join(', ', array_map(array(&$this, 'name'), $value['column'])) . ')';
} else {
$out .= 'KEY '. $name .' (' . $this->name($value['column']) . ')';
}
$alter[] = $out;
}
}
return $alter;
}
/**
* Inserts multiple values into a table
*
* #param string $table
* #param string $fields
* #param array $values
*/
function insertMulti($table, $fields, $values) {
$table = $this->fullTableName($table);
if (is_array($fields)) {
$fields = join(', ', array_map(array(&$this, 'name'), $fields));
}
$values = implode(', ', $values);
$this->query("INSERT INTO {$table} ({$fields}) VALUES {$values}");
}
}
class DboMysql extends DboMysqlBase {
/**
* Enter description here...
*
* #var unknown_type
*/
var $description = "MySQL DBO Driver";
/**
* Base configuration settings for MySQL driver
*
* #var array
*/
var $_baseConfig = array(
'persistent' => true,
'host' => 'localhost',
'login' => 'root',
'password' => '',
'database' => 'cake',
'port' => '3306',
'connect' => 'mysql_pconnect'
);
/**
* Connects to the database using options in the given configuration array.
*
* #return boolean True if the database could be connected, else false
*/
function connect() {
$config = $this->config;
$connect = $config['connect'];
$this->connected = false;
if (!$config['persistent']) {
$this->connection = mysql_connect($config['host'] . ':' . $config['port'], $config['login'], $config['password'], true);
} else {
$this->connection = $connect($config['host'] . ':' . $config['port'], $config['login'], $config['password']);
}
if (mysql_select_db($config['database'], $this->connection)) {
$this->connected = true;
}
if (isset($config['encoding']) && !empty($config['encoding'])) {
$this->setEncoding($config['encoding']);
}
$this->_useAlias = (bool)version_compare(mysql_get_server_info($this->connection), "4.1", ">=");
return $this->connected;
}
/**
* Disconnects from database.
*
* #return boolean True if the database could be disconnected, else false
*/
function disconnect() {
if (isset($this->results) && is_resource($this->results)) {
mysql_free_result($this->results);
}
$this->connected = !#mysql_close($this->connection);
return !$this->connected;
}
/**
* Executes given SQL statement.
*
* #param string $sql SQL statement
* #return resource Result resource identifier
* #access protected
*/
function _execute($sql) {
return mysql_query($sql, $this->connection);
}
/**
* Returns an array of sources (tables) in the database.
*
* #return array Array of tablenames in the database
*/
function listSources() {
$cache = parent::listSources();
if ($cache != null) {
return $cache;
}
$result = $this->_execute('SHOW TABLES FROM ' . $this->name($this->config['database']) . ';');
if (!$result) {
return array();
} else {
$tables = array();
while ($line = mysql_fetch_array($result)) {
$tables[] = $line[0];
}
parent::listSources($tables);
return $tables;
}
}
/**
* Returns an array of the fields in given table name.
*
* #param string $tableName Name of database table to inspect
* #return array Fields in table. Keys are name and type
*/
function describe(&$model) {
$cache = parent::describe($model);
if ($cache != null) {
return $cache;
}
$fields = false;
$cols = $this->query('DESCRIBE ' . $this->fullTableName($model));
foreach ($cols as $column) {
$colKey = array_keys($column);
if (isset($column[$colKey[0]]) && !isset($column[0])) {
$column[0] = $column[$colKey[0]];
}
if (isset($column[0])) {
$fields[$column[0]['Field']] = array(
'type' => $this->column($column[0]['Type']),
'null' => ($column[0]['Null'] == 'YES' ? true : false),
'default' => $column[0]['Default'],
'length' => $this->length($column[0]['Type']),
);
if (!empty($column[0]['Key']) && isset($this->index[$column[0]['Key']])) {
$fields[$column[0]['Field']]['key'] = $this->index[$column[0]['Key']];
}
}
}
$this->__cacheDescription($this->fullTableName($model, false), $fields);
return $fields;
}
/**
* Returns a quoted and escaped string of $data for use in an SQL statement.
*
* #param string $data String to be prepared for use in an SQL statement
* #param string $column The column into which this data will be inserted
* #param boolean $safe Whether or not numeric data should be handled automagically if no column data is provided
* #return string Quoted and escaped data
*/
function value($data, $column = null, $safe = false) {
$parent = parent::value($data, $column, $safe);
if ($parent != null) {
return $parent;
}
if ($data === null || (is_array($data) && empty($data))) {
return 'NULL';
}
if ($data === '' && $column !== 'integer' && $column !== 'float' && $column !== 'boolean') {
return "''";
}
if (empty($column)) {
$column = $this->introspectType($data);
}
switch ($column) {
case 'boolean':
return $this->boolean((bool)$data);
break;
case 'integer':
case 'float':
if ($data === '') {
return 'NULL';
}
if ((is_int($data) || is_float($data) || $data === '0') || (
is_numeric($data) && strpos($data, ',') === false &&
$data[0] != '0' && strpos($data, 'e') === false)) {
return $data;
}
default:
$data = "'" . mysql_real_escape_string($data, $this->connection) . "'";
break;
}
return $data;
}
/**
* Returns a formatted error message from previous database operation.
*
* #return string Error message with error number
*/
function lastError() {
if (mysql_errno($this->connection)) {
return mysql_errno($this->connection).': '.mysql_error($this->connection);
}
return null;
}
/**
* Returns number of affected rows in previous database operation. If no previous operation exists,
* this returns false.
*
* #return integer Number of affected rows
*/
function lastAffected() {
if ($this->_result) {
return mysql_affected_rows($this->connection);
}
return null;
}
/**
* Returns number of rows in previous resultset. If no previous resultset exists,
* this returns false.
*
* #return integer Number of rows in resultset
*/
function lastNumRows() {
if ($this->hasResult()) {
return mysql_num_rows($this->_result);
}
return null;
}
/**
* Returns the ID generated from the previous INSERT operation.
*
* #param unknown_type $source
* #return in
*/
function lastInsertId($source = null) {
$id = $this->fetchRow('SELECT LAST_INSERT_ID() AS insertID', false);
if ($id !== false && !empty($id) && !empty($id[0]) && isset($id[0]['insertID'])) {
return $id[0]['insertID'];
}
return null;
}
/**
* Converts database-layer column types to basic types
*
* #param string $real Real database-layer column type (i.e. "varchar(255)")
* #return string Abstract column type (i.e. "string")
*/
function column($real) {
if (is_array($real)) {
$col = $real['name'];
if (isset($real['limit'])) {
$col .= '('.$real['limit'].')';
}
return $col;
}
$col = str_replace(')', '', $real);
$limit = $this->length($real);
if (strpos($col, '(') !== false) {
list($col, $vals) = explode('(', $col);
}
if (in_array($col, array('date', 'time', 'datetime', 'timestamp'))) {
return $col;
}
if (($col == 'tinyint' && $limit == 1) || $col == 'boolean') {
return 'boolean';
}
if (strpos($col, 'int') !== false) {
return 'integer';
}
if (strpos($col, 'char') !== false || $col == 'tinytext') {
return 'string';
}
if (strpos($col, 'text') !== false) {
return 'text';
}
if (strpos($col, 'blob') !== false || $col == 'binary') {
return 'binary';
}
if (strpos($col, 'float') !== false || strpos($col, 'double') !== false || strpos($col, 'decimal') !== false) {
return 'float';
}
if (strpos($col, 'enum') !== false) {
return "enum($vals)";
}
return 'text';
}
/**
* Enter description here...
*
* #param unknown_type $results
*/
function resultSet(&$results) {
if (isset($this->results) && is_resource($this->results) && $this->results != $results) {
mysql_free_result($this->results);
}
$this->results =& $results;
$this->map = array();
$numFields = mysql_num_fields($results);
$index = 0;
$j = 0;
while ($j < $numFields) {
$column = mysql_fetch_field($results,$j);
if (!empty($column->table)) {
$this->map[$index++] = array($column->table, $column->name);
} else {
$this->map[$index++] = array(0, $column->name);
}
$j++;
}
}
/**
* Fetches the next row from the current result set
*
* #return unknown
*/
function fetchResult() {
if ($row = mysql_fetch_row($this->results)) {
$resultRow = array();
$i = 0;
foreach ($row as $index => $field) {
list($table, $column) = $this->map[$index];
$resultRow[$table][$column] = $row[$index];
$i++;
}
return $resultRow;
} else {
return false;
}
}
/**
* Gets the database encoding
*
* #return string The database encoding
*/
function getEncoding() {
return mysql_client_encoding($this->connection);
}
}
class DboMysqlWithLog extends DboMysql {
function _execute($sql) {
//exclude these types of queries from being logged, change if required
if(!preg_match('/^SHOW|SELECT|DESCRIBE|cake_sessions.*/',$sql) && !preg_match('/^SET.*/',$sql)){
//HH_DOCUMENT_ROOT should be defined in one of the core files pointing to the project root directory, if its not there define it
//do not commit changes, if its specific to local machine
//$filename = HH_DOCUMENT_ROOT.DS.'sql.txt';
$filename = 'C:\xampp\htdocs\your_project_dir\app\sql.txt';
$patfile = fopen($filename, 'a+');
$textdata = "$sql\n";
fwrite($patfile, $textdata);
fclose($patfile);
}
return parent::_execute($sql);
}
}
?>
change sql log file path $filename = 'C:\xampp\htdocs\your_project_dir\app\sql.txt';
Step 2: Open /app/config/database.php
and change 'driver' => 'dbo_mysql_with_log',
This will record all your sql scripts in the below path
C:\xampp\htdocs\your_project_dir\app\sql.txt

How to use cakephp export txt file

I'm using cakephp framework.I want to export a database table of a client download in two formats.One is '.csv', the other is a '.txt'.CSV which I have passed 'csvHelper' resolved.Now I want to know how to export '.txt'.Sorry for my poor English, but I think you'll see what I mean, thanks!
Basically you set the header for the filename, like this:
$this->response->type('Content-Type: text/csv');
$this->response->download('myfilename.txt');
Here are some functions I put in my appController, so that any controller can output a CSV file if required:
/**
* Flattens the data that is returned from a find() operation, and puts it into CSV format
* #param $data
* #return string
*/
public function _arrayToCsvFile($data){
$flattenedData = array();
$exportKeyPair = array();
foreach($data as $datumKey => $datumDetails){
$flattenedDatum = Hash::flatten($datumDetails, '.');
$flattenedData[] = $flattenedDatum;
// Find all keys
if($datumKey == 0){
$exportKeys = array_keys($flattenedDatum);
$exportKeyPair = array_combine($exportKeys, $exportKeys);
}
else {
$datumKeys = array_keys($flattenedDatum);
$datumKeyPair = array_combine($datumKeys, $datumKeys);
// Add the datum keys to the exportKeyPair if it's not already there
$exportKeyPair = array_merge($exportKeyPair, $datumKeyPair);
}
}
$exportKeyMap = array();
foreach($exportKeyPair as $exportKey => $exportValue){
$exportKeyMap[$exportKey] = "";
}
$outputCSV = '';
$outputCSV .= $this->_arrayToCsvLine($exportKeyPair);
foreach($flattenedData as $flattenedDatumKey => $flattenedDatumDetails){
// Add any extra keys
$normalisedDatumDetails = array_merge($exportKeyMap, $flattenedDatumDetails);
$outputCSV .= $this->_arrayToCsvLine($normalisedDatumDetails);
}
return $outputCSV;
}
/**
* arrayToCsvLine function - turns an array into a line of CSV data.
*
* #access public
* #param mixed $inputLineArray the input array
* #param string $separator (default: ")
* #param string $quote (default: '"')
* #return string
*/
function _arrayToCsvLine($inputLineArray, $separator = ",", $quote = '"') {
$outputLine = "";
$numOutput = 0;
foreach($inputLineArray as $inputLineKey => $inputLineValue) {
if($numOutput > 0) {
$outputLine .= $separator;
}
$outputLine .= $quote . str_replace(array('"', "\n", "\r"),array('""', "", ""), $inputLineValue) . $quote;
$numOutput++;
}
$outputLine .= "\n";
return $outputLine;
}
/**
* Serves some CSV contents out to the client
* #param $csvContents
* #param array $options
*/
public function _serveCsv($csvContents, $options = array()){
$defaults = array(
'modelClass' => $this->modelClass,
'fileName' => null
);
$settings = array_merge($defaults, $options);
if(empty($settings['fileName'])){
$settings['fileName'] = strtolower( Inflector::pluralize( $settings['modelClass'] ) ) . '_' . date('Y-m-d_H-i') . '.csv';
}
$this->autoRender = false;
$this->response->type('Content-Type: text/csv');
$this->response->download($settings['fileName']);
$this->response->body($csvContents);
}
Now in any controller you can do this (note that you can pass the filename to _serveCsv if required):
/**
* admin_export_csv method
*
* #return void
*/
public function admin_export_csv() {
$this->Order->recursive = 0;
$conditions = array();
$orders = $this->Order->find('all', array('conditions' => $conditions));
$csvContents = $this->_arrayToCsvFile($orders); // Function in AppController
$this->_serveCsv($csvContents, array('filename' => 'export.txt')); // Function in AppController
}
you can use
$this->RequestHandler->respondAs('txt'); to output the correct header.
Please not the header is not set when DEBUG is greater than 2.
And you will still have to build the controller action and set view as ususal.

Resources