I'm trying to track down anything I can to optimize the performance of my Magento site. I've just noticed that a certain SQL command is running UP TO 91 times on a page:
ALTER TABLE `enterprise_sales_order_grid_archive` MODIFY COLUMN `is_edited` smallint NOT NULL default '0' COMMENT ''
Does anyone have an idea what this is or why this is or most importantly., how I can fix it?
I have been getting similar issue and fix which I have applied is as follows :
This module is particularly active on any order events please disable it totally if you can.
if you look at : /app/code/core/Enterprise/SalesArchive/etc/config.xml
there is a cron job that and many event that is the main cause this to happend
please disabled all the event listening in the config.xml of this module.
Please try to comment ( If you have this file )
app/code/community/MDN/AdvancedStock/Block/Adminhtml/Sales/Order/Grid.php
line 69 to 79 in this way
protected function _prepareColumns()
{
parent::_prepareColumns();
$this->addAfterColumn('increment_id', array(
'header'=> Mage::helper('Organizer')->__('Organizer'),
'renderer' => 'MDN_Organizer_Block_Widget_Column_Renderer_Comments',
'align' => 'center',
'entity' => 'order',
'filter' => false,
'sortable' => false
),'real_order_id');
/*$this->addAfterColumn('payment_validated', array(
'header'=> Mage::helper('AdvancedStock')->__('Payment validated'),
'width' => '40px',
'index' => 'payment_validated',
'align' => 'center',
'type' => 'options',
'options' => array(
'1' => Mage::helper('purchase')->__('Yes'),
'0' => Mage::helper('purchase')->__('No'),
),
),'status');*/
//raise event to allow other modules to add columns
Mage::dispatchEvent('salesorder_grid_preparecolumns', array('grid'=>$this));
}
Another option to fix this issue is as follows
Basically we get two flags which might be added to a app/etc/local.xml. Assuming a site is hosted on multiple frontend web servers, update scripts should only be processed on one of them. Setting
<global>
<skip_process_modules_updates>1</skip_process_modules_updates>
</global>
on all but the “master” web server will avoid race conditions between the hosts.
There is a better way to avoid race conditions for processing setup scripts, and that is by not allowing any web servers at all to process setup scripts.
This is how it works. Instead of setting the skip_process_modules_updates flag on all but one server, it should be set to a true value on all hosts. Then the setup process can be triggered by a short shell script.
It works for me. See If that helps to you.
Related
I am building an app using Yii2 and I am working with multi-tenant architecture. So... every client has his own database (identical structure).
What I have done so far:
I declare all the different databases in the config/web.php file
I have a master database that corresponds each user to his database. So, when someone logs in, the app knows what database should use.
What I have done but I am not sure about:
I created a file components/ActiveRecord.php with the following code:
<?php
namespace app\components;
use Yii;
class ActiveRecord extends \yii\db\ActiveRecord {
public static function getDb() {
if (isset($_SESSION['userdb'])) {
$currentDB = $_SESSION['userdb'];
return Yii::$app->get($currentDB);
}
}
}?>
So... on login I save the database on the session and in the aforementioned file which extends the default ActiveRecord I override the getDb function and I choose my own. Subsequently, I changed all models so they extend my ActiveRecord.
I am not sure that this strategy is correct but it almost works.
Where is the problem:
Everything works fine except from... RBAC! For RBAC I use the yii2-rbac extension. The problem is that the user is not getting his role from his database but from the first declared database in the config/web.php file. So, whatever the logged in user, the first db is used.
Question(s):
How can I solve this problem? Do you have any idea on where is the file that gives the role to the logged in user?
Bonus Questions: Do you think this strategy is wrong? If so, what would you suggest?
Thanks a lot in advance for your time and your support.
Question # 1: How can I solve this problem? Do you have any idea on where is the file that gives the role to the logged in user?
I would suggest you use yii2 admin extension for this purpose(https://github.com/mdmsoft/yii2-admin) that will solve your issue and it is the best extension to manage user role. use this link for better understanding (https://github.com/mdmsoft/yii2-admin/blob/master/docs/guide/configuration.md)
Install above by following above URL or just add "mdmsoft/yii2-admin": "~2.0" in your composer.json file and run composer update.
After successfully installed this extension run migration to create RBAC tables, if you already have then skipped it.
yii migrate --migrationPath=#yii/rbac/migrations
You have to do some configuration in your main.php to tell your application about public routes and for all other application route system will implement RBAC on them.
This is what you have to add in your main.php file.
'components' => [],
'as access' => [
'class' => 'mdm\admin\components\AccessControl',
'allowActions' => [
'site/login', // add or remove allowed actions to this list
'site/logout',
'site/error',
'site/index',
]
]
Above settings will tell your application to make the login, logout, error and index function are public under site controller and all other applications routes need to have RBAC assignment to perform the action.
main.php is exist in backend/config/main.php in my case, you can use according to your requirements may be in common/config/main.php
Question # 2: Bonus Questions: Do you think this strategy is wrong? If so, what would you suggest?
I think your approach is not extendable, I suggest you create a master database and use that for your application tenants with their databases.
Setup tenant table in master database with tenant name, database required parameters
Make master database connection in your application, that is used to get all tenant and there store DB connections from the master database.
'db' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=127.0.0.1;dbname=master-db',
'username' => 'root',
'password' => 'root',
'charset' => 'utf8',
]
Now at login page show tenants list to choose their info OR you can also play with the domain name as well if you are using the unique domain for each tenant. if you are using unique domain then you have to store domain name with tenant info in the master database to able to get tenant info based on the domain.
// Set Session Values on success login page OR read user domain and get tenant info from the master database and add into session.
``
$tenant = Tenant::findOne(Yii::$app->request->post('tenant_id'));
Yii::$app->session->set('DB_HOST', $tenant->DB_host);
Yii::$app->session->set('DB_USER', $tenant->DB_username);
Yii::$app->session->set('DB_PASS', $tenant->DB_password);
Yii::$app->session->set('DB_NAME', $tenant->DB_name);
``
Once you have tenant info you can get the tenant from the master database and add their database settings into SESSION.
Create a BaseModel.php class and extend it with all of your application models classes.
In you BaseModel.php add below method to make runtime DB connection based on domain or tenant selection from the login page.
public static function getDb(){
if ( Yii::$app->session->get('DB_HOST') ){
$host = Yii::$app->session->get('DB_HOST');
$dbName = Yii::$app->session->get('DB_NAME');
$dsn = "mysql:host=$host;dbname=$dbName";
Yii::$app->db->dsn = $dsn;
Yii::$app->db->username = Yii::$app->session->get('DB_USER');
Yii::$app->db->password = Yii::$app->session->get('DB_PASS');
return Yii::$app->db;
}
}
By doing this you will have the option to add multiple tenants from backend to master database and that will automatically available in your application.
I believe that this information is helpful for you.
Cheers!!!
Here is the documentation on dbmanager.
If the you want to get rbac info from a different database, this should work.
Inside your config folder, create a file called rbacdb.php. Add the following:
<?php
return [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=<db host or ip>;dbname=<dbname>',
'username' => '<dbuser>',
'password' => '<dbPassword>',
'charset' => 'utf8',
];
Then go to your config file and find the authmanger section. It should look like this:
'authManager' => [
'class' => 'yii\rbac\DbManager',
'db'=> require(__DIR__ . '/rbacdb.php'),
'assignmentTable'=>'<tableName>',
'itemChildTable'=>'<tableName>',
'itemTable'=>'<tableName>',
'ruleTable'=>'<tableName>'
]
EDIT: after rereading your post...each user doesn't need their own rbac table/schema. use the system that Yii has in place.
I need to create about 20-30 Drupal8 sites on different domains. There will be similar content (difference only in details like city name, ajax calls, etc.) but also there will be a specific content like news.
I know all weakness of this idea, but anyway I think that shared tables in one database will be the best solution for this project.
My steps:
installing first default site (sites/default) with prefix for tables default_
creating directory for second site (sites/second), and configuring sites.php (seconddomain.com => sites/second)
installing second site (sites/second) with prefix for tables second_
... then I tried to use solution which is described on many sites:
$databases['default']['default'] = array(
'database-configuration-stuff' => '[...database configuration]'
'prefix' => array(
'default' => 'second_', // default prefix for second site
'users' => 'default_', // shared users...
'sessions' => 'default_',
'role' => 'default_',
'authmap' => 'default_',
),
);
but it doesn't work. I see only users from second site. Cache cleaning doesn't change anything. Any ideas?
Maybe there is possibility to create multi-page solution with one shared database (not only for users but for nodes also) and create content directed to different domains from one admin console?
BTW: If there is any possibility to create sth like this using Drupal7 I can change d8 to d7.
if you'd like to make sth I was looking for you've got three options:
you need to write your own module ;) ,
you need to wait for "Domain Access" module for D8: https://www.drupal.org/project/domain ,
you can also use D7 and module from URL which I provide above.
I chose 3rd option.
I have been struggling for a few days with this problem and finally seek the opinion of the experts and crowd at this website.
I have two tables - one is a template of workflow steps and the other is an instance of these workflow steps called events. The templates table contains information like step name, step type etc - very generic information. The event table contains a reference link back to the workflow step table and an additional column called notes - which stores data that the user logged as they logged a particular workflow step. Both Workflow Steps and Events are linked to a POST on the website
Workflow step templates can exist without events having yet occurred - that is the user may be still on Step 3 or Step 5 and not logged an event for Step 1, 2 , 4 - basically the order of steps is only suggestive but not binding. Workflow Steps have a sequence field that dictate the order in which they should appear on screen.
Events can also occur without a workflow step - in other words, a user can log a note outside the context of workflow steps. These are generic events and directly associated with the POST
I am able to successfully retrieve both of these values for a given POST - they are retrieved as two separate arrays. I am using CakePHP and MySQL
The UI needs to render a screen that shows all the workflow steps in order and corresponding events that have occured in correlation to these steps or outside of these steps. The ordering of the screen will be driven primarily by the sequence of workflow steps and secondarily by created_date for those events that are not associated with a particular workflow step
Problem statement -
1. Do I send two separate arrays (as noted in #4) to the UI and let the UI determine the complex logic of how to interweave the steps and events for display?
2. Do I process the interweaving of steps and events in the controller and then send to the UI a simple array that it can loop through and display?
3. I have tried moving this logic to the database but because of variations explained in #2 and #3 it becomes quite complicated
I am seeking advise on which would be a better option from a design practice as well as from a simplification point of view. I understand that I have given a limited picture here but am hoping that someone on this website may have run into a similar issue elsewhere.
Depending on how you are assigning events to users, I would make a hasOne relation in Event to Workflow. You would need another relationship for you users, hasOne or hasMany.
$hasOne = 'Workflow';
Obviously this would mean that your Event table would have a column called wordflow_id and would be associated with a single row in your workflow. In the controller I would call the Event with by the user.
$this->Event->findAllByUserId($user_id);
This should provide you with an array that might look something like this.
array(
[0] => array(
[Event] => array(
'id' => 1,
'name' => 'blah',
...
),
[User] => array(
'id' => 1,
'name' => 'Charles',
...
),
[Workflow] => array(
[0] => array(
'id' => 1,
'name' => 'more blagblagblag',
...
),
[1] => array(
'id' => 9,
'name' => 'sblagblsagblag',
...
),
[2] => array(
'id' => 42,
'name' => 'mordse d',
...
)
)
)
)
Call all your workflow templates
$this->Workflow->find('all');
Then I would user cake's built in SET:: functionality to print the workflow template in your view and use your Event call to fill in the data.
Please post more detail and your code, models, ect and I'm sure we can get you the exact query/logic you'll need to achieve this.
http://book.cakephp.org/2.0/en/core-utility-libraries/set.html
OK - I have solved this. I ended up moving the functionality to the Model.
I created two SQL queries - one that retrieves all the workflow steps along with any event information that maybe associated with each of them.
Then I created a second SQL that retrieves all those events that are stand-alone and not associated with any particular workflow step
I used UNION ALL to stack them on top of each other
I used a SORT on modified date and squence number so that all the steps and events appear in chronological order and sequence
I then passed this from the Model to the View (via the controller) and let the View iterate and display the elements. This approach actually simplified my View and Controller code immensely and even the Model code is quite simple since all it is a query statement with parameters.
So my app is running in development mode in one place and in production mode on its live server. I've just put some changes live and a field that has been in the production DB (MySQL) for a good week or two is not being found by a call to Model::read(). Here's the code, verbatim:
$this->Order->id = $id;
$created = $this->Order->field('created');
$this->Order->contain(array('User', 'OrderStatusChange', 'Cart' => array('CartItem' => array('conditions' => array('deleted_date' => null, 'created <=' => $created)))));
$this->request->data = $order = $this->Order->read();
Same code in dev environment returns all fields. The new(ish) field is missing in production. I have deleted every file in /app/tmp/cache/models and it has not fixed the problem. The production site has Configure::write('debug', 0), development site is set to 2.
Any ideas?
Thanks
As you already cleared your caches, but problem still exists. So, I will point out one things here:
$this->Order->contain(...) here you're using contain() and for contain(), need to attach Containable behavior to model. Your code doesn't clarify that you attach that or not. If not, then I will suggest you to attach that like:
.....
$this->Order->Behaviors->attach('Containable'); // attach Containable behavior
$this->Order->contain(...);
......
when the user buys some car manuals in application, he can able to use them without network
so I want to cache the manuals he purchased, I want step by step method to cache the database
$memcache = new Memcache();
$memcache->connect('localhost', 11211);
$servers = array(
'host' => 'memcache_host',
'port' => 11211,
'persistent' => true
);
$cacheDriver = new \Doctrine\Common\Cache\MemcacheCache(
array(
'servers' => $servers,
'compression' => false
)
);
$cacheDriver->setMemcache($memcache);
$cacheDriver->save('cache_id', 'my_data');
I just want to know how does the my_data and id works ?
Memcached and all the other cache providers included with Doctrine 2 are server side caching mechanisms. Meaning that regardless of the users context, connectivity is required.
If you want to allow your user to access data from your application while offline, you will need to use something like HTML5 local storage, you can check out nettuts for a quick video intro to using it.