Need to change timezone dynamically for existing project - mysql

There is an existing project only for one country. But for now, it should be used for multiple countries. So I need some place to change timezones. I decided to update & insert in only London/Sydney timezone. I need to change the timezone for all select queries. I just tried with middlewares, but I could not achieve it. Please give your suggestions.
Linux server, MySQL, Laravel, Vagrant
namespace App\Http\v2018_06_12\Middleware;
use App;
use App\Order;
use Closure;
class LocaleMiddleware
{
public function handle($request, Closure $next, $guard = null)
{
$locale = ($request->hasHeader('locale')) ? $request->header('locale') : 'uk';
$timezone = env('APP_TIMEZONE');
if ('aus' == $locale) {
$timezone = 'Australia/Sydney';
}
config(['app.timezone' => $timezone]);
date_default_timezone_set($timezone);
print_r(Order::select('delivery_time')->orderBy('id', 'DESC')->first()->toArray());
return $next($request);
}
}

Related

Write database queries in Magento custom module

I created a custom module in my Magento. This is working good. My module's name is mymodule.
Mymodule.php
class Myshop_Mymodule_Block_Mymodule extends Mage_Core_Block_Template
{
public function myfunction()
{
return "Hello User";
}
}
The path of the Mymodule.php file is C:\wamp\www\magento\app\code\local\Myshop\Mymodule\Block.
Now I want to display some data from database. For example I would like to display the admin's email id. How can I display this??
I tried like this.
$read = Mage::getSingleton('core/resource')->getConnection('core_read');
//database write adapter
$write = Mage::getSingleton('core/resource')->getConnection('core_write');
$result = $read->fetchAll("select email from admin_user where user_id= 1");
var_dump($result);
I write these lines in Mymodule.php inside myfunction. But nothing displayed(display only "Hello User").
So my question is how to display or write database queries in magento custom module.
Please someone help me..Any help is really appreciable..
We generally avoid using adapters when magento by default provides models for the basic tables. In your case, you can fetch the admin details using following :
<?php
$userDetails = Mage::getModel('admin/user')->load(1);
//where 1 is your admin user id
echo $userDetails->getEmail();
?>
Hence, your function can be modified as :
<?php
class Myshop_Mymodule_Block_Mymodule extends Mage_Core_Block_Template
{
public function myfunction()
{
$userDetails = Mage::getModel('admin/user')->load(1);
return $userDetails->getEmail();
}
}
You can get data from database in magento as
$collection = Mage::getModel("mumodule/mymodule")->getCollection();
foreach($collection as $data){
..Your Code ..
}

How to use database specific functions in Laravel Eloquent ORM for modular usage

Im developing a project which uses ORM to make project run on every database system as much as we can.
Project uses postgresql right now. Im wondering how to use database specific functions without losing ORM modularity.
For example:
I have to use "extract" function for one query like so;
DELETE FROM tokens AS t WHERE (extract(epoch from t.created_at) + t.expires) < extract(epoch from NOW())
If i want to use model class to achieve this. Soon or late i need to write extract function where clause in raw format
Tokens::whereRaw('(extract(epoch from t.created_at) + t.expires) < extract(epoch from NOW())')->get();
If i use query builder
DB::table('tokens')->whereRaw('(extract(epoch from t.created_at) + t.expires) < extract(epoch from NOW())')->select()->get();
Same things happens
I need something like when i use postgresql ORM need to use EXTRACT() function or when i use mysql ORM need to use UNIX_TIMESTAMP() function
What the ways i can use to achieve this ?
This could go in the respective drivers, but Taylor Otwell's view on driver-specific functions is, that you simply should use raw statements, just like you do.
However in Eloquent you can pretty easily do it yourself:
// BaseModel / trait / builder macro or whatever you like
public function scopeWhereUnix($query, $col, $operator = null, $value = null)
{
if (func_num_args() == 3)
{
list($value, $operator) = array($operator, '=');
}
switch (class_basename($query->getQuery()->getConnection()))
{
case 'MySqlConnection':
$col = DB::raw("unix_timestamp({$col})");
break;
case 'PostgresConnection':
$col = DB::raw("extract(epoch from {$col})");
break;
}
$query->where($col, $operator, $value);
}
Now you can do this:
Tokens::whereUnix('created_at', 'value')->toSql();
// select * from tokens where unix_timestamp(created_at) = 'value'
// or
// select * from tokens where extract(epoch from created_at) = 'value'
You have a bit more complex condition, but you still can achieve that with a little bit of hack:
Tokens::whereUnix(DB::raw('created_at) + (expires', '<', time())->toSql();
// select * from tokens where unix_timestamp(created_at) + (expires) < 12345678
// or
// select * from tokens where extract(epoch from created_at) + (expires) < 12345678
Unfortunately Query\Builder (DB::table(..)) is not that easy to extend - in fact it is not extendable at all, so you would need to swap it with your own Builder class, what is rather cumbersome.
Take this logic out of the models.
Create a repository for Postgres, let's call it PostgresTokenRepository. The constructor of this repository should look like...
<?php
class PostgresTokenRepository implements TokenRepositoryInterface
{
protected $token;
public function __construct(Token $token)
{
$this->token = $token;
}
public function getTokens()
{
return $this->token->whereRaw('(extract(epoch from t.created_at) + t.expires) < extract(epoch from NOW())')->get();
}
}
And you will need an interface... TokenRepositoryInterface
interface TokenRepositoryInterface
{
public function getTokens();
}
Now you should be all set as far as the repository goes. If you need to do a MySQL implementation, just create a MysqlTokenRepository which will look similar except the getTokens() function would use UNIX_TIMESTAMP().
Now you need to tell Laravel that when you are looking for an implementation of TokenRepositoryInterface, it should return PostgresTokenRepository. For that, we will need to create a service provider.
<?php
class UserServiceProvider extends \Illuminate\Support\ServiceProvider
{
public function register()
{
$this->app->bind('TokenRepositoryInterface', 'PostgresTokenRepository');
}
}
And now the only thing left to do is add this Service Provider to the service providers array in config/app.php.
Now whenever you need this repository in your controllers, you can have them automatically injected. Here is an example...
class TokenController extends BaseController
{
protected $token;
public function __construct(TokenRepositoryInterface $token)
{
$this->token = $token;
}
public function index()
{
$tokens = $this->token->getTokens();
return View::make('token.index')->with('tokens', $tokens);
}
}
The purpose for doing it this way is when you want to start using the MySQL implementation, all you have to do is modify the service provider to return MysqlTokenRepository instead of PostgresTokenRepository. Or if you want to write a new implementation all together, it will all be possible without having to change production code. If something doesn't work, simply change that one line back to PostgresTokenRepository.
One other benefit that sold me is this gives you the capability of keeping your models and controllers very light and very testable.
I ended up creating a global scope. Created a trait like ExpiresWithTimestampsTrait that contains the logic for whereExpires scope. The scope does adding where clause that specific to database driver.
public function scopeWhereExpired($query)
{
// Eloquent class is my helper for getting connection type based on the #jarek's answer
$type = Eloquent::getConnectionType($this);
switch ($type) {
case Eloquent::CONNECTION_POSTGRESS:
return $query->whereRaw("(round(extract(epoch from (created_at)) + expires)) < round(extract(epoch from LOCALTIMESTAMP))");
break;
default:
break;
}
}
So i just need to use that trait on the model. I need to add just an "case" clause to whereExpires scope for support mysql with where clause in the future when i start using mysql
Thanks to everybody!

Codeigniter timezone mysql settings

Just realised WHY my site is now showing all datetime variables as -1 hr... I'm using Codeigniter for the first time! (Never had this problem before)
So, I have included the following code in my main index.php file
/*
|---------------------------------------------------------------
| DEFAULT TIMEZONE
|---------------------------------------------------------------
|
| Set the default timezone for date/time functions to use if
| none is set on the server.
|
*/
if( ! ini_get('date.timezone') )
{
date_default_timezone_set('GMT');
}
However, it's still showing as -1 hr, so I'm assuming I need to set some sort of default setting for MySQL...
I have included the following line of code in my model:
function __construct()
{
// Call the Model constructor
parent::__construct();
$this->db->query("SET time_zone='+0:00'");
}
Still no difference... Help!
My code is:
<h3><?=date('D, jS F # g:ia', strtotime($row->datetime))?></h3>
The $row->datetime variable is nothing more than a DATETIME column value from my MySQL database. The echoed variable in view is ALWAYS 1 hour less than the value in my database...
My model code is:
function coming_up()
{
$this->db->query("SET time_zone='+0:00'");
$query = $this->db->query('SELECT * FROM events1 WHERE datetime >= NOW() ORDER BY datetime LIMIT 2');
return $query->result();
}
In config/autoload.php, set a model to load on each page load. then call $this->db->query("SET time_zone='+0:00'"); in that model constructor.
config/autoload.php
$autoload['model'] = array('default_model');// for ex, "say default_model"
In application/models, create a new model file with name of "default_model.php" and add below code.
application/models/default_model.php
class Default_model extends CI_Model {
function __construct()
{
// Call the Model constructor
parent::__construct();
$this->db->query("SET time_zone='+0:00'");
}
}
On each page load, this constructor will be called and mysql timezone will be set to +0:00.
Add these line in your config file and then check, it is working for me
$config['time_reference'] = 'gmt';# Default should be GMT
date_default_timezone_set('UTC');# Add this line after creating timezone to GMT for reflecting
am also face this problem.
i tried this way..
$this->db->query("SET LOCAL time_zone='Asia/Kolkata'");
$query="SELECT * FROM offers where NOW() between offfer_from and offer_to";
$res=$this->db->query($query);
it will work fine in my project and i'm not using anything new default model.. if you want global solution means you can use auto-load some model.
SET default time_zone for MySQL :
Go to : Your_Project/system/core/Model.php And then update this function :
public function __construct() {
$this->db->query("SET time_zone='YOUR_TIME_ZONE'");
}
SET default_time_zone for PHP :
Go to Your_Project/index.php
And then update here :
define('ENVIRONMENT', isset($_SERVER['CI_ENV']) ? $_SERVER['CI_ENV'] : 'development');
date_default_timezone_set('YOUR_TIME_ZONE');
I like the solution proposed by Kumar however, I didn't need to set this globally, only when showing dates stored in UTC time in my db.
In my api model I have the following function.
public function setDBTimeOffset(){
$dt = new DateTime();
$offset = $dt->format("P");
$result = $this->db->query("SET time_zone='$offset';");
return $result;
} # END FUNCTION setDBTimeOffset
From my controller, I call the following first.
$this->api->setDBTimeOffset();
Followed by the call to the function that queries the db. For example, I am fetching some user history.
$data["viewData"]["allHistory"] = $this->api->getUserHistory("ALL", 0, 10000);
When I display the output, the dates are in my timezone. I hope this helps someone, somewhere in time (couldn't resist).
You can set it in the index.php file in your project folder on top and after <?php
<?php
date_default_timezone_set('Asia/Bangkok');

Use existing MySQL database in CodeIgniter

In my PHP websites I’m using SiteTranslator script for a website translated into 30 languages. Each translation is stored in its own table (text_en, text_de...) and each table has 3 columns (textKey, textValue, lastUpdate).
Now I would like to use that database in my CodeIgniter application.
What would be the best way to do it?
You could use multiple databases as suggested, you would still need to setup your app language files
{read more in the user guide}
Based on the first uri segment you could try something like this.
Adding routes
$route['en|fr|gr/test'] = 'test';
First segment checks for en OR fr OR whatever else.
Then the Main Controller catches the first segment before the test controller is initialized and the db(object) && app(language) files are set
www.site.com/en/test => load english language file(application/language/english/mylanguage) and db
www.site.com/fr/test => load french language file(application/language/french/mylanguage) and db ...and so on
Main Controller
class MY_Controller extends CI_Controller{
protected $lang, $db;
public function __construct(){
parent::__construct();
$this->set_language();
}
protected function set_language(){
switch($this->uri->segment(1))
{
case 'en':
$this->lang = $this->lang->load('mylanguage', 'english');
$this->db = $this->load->database('en', TRUE);
break;
case 'fr':
$this->lang = $this->lang->load('mylanguage', 'french');
$this->db = $this->load->database('fr', TRUE);
break;
default:
$this->lang = $this->lang->load('mylanguage', 'english');
$this->db = $this->load->database('en', TRUE);
break;
}
}
}

Calling stored procedure in codeigniter

I am using latest codeigniter and trying to call stored procedure from my model. Also I am using mysqli as database driver. Now I am having an error when I call two stored procedures. Following is the error:
Error Number: 2014
Commands out of sync; you can't run this command now
call uspTest();
Filename: E:\wamp\www\reonomy-dev\system\database\DB_driver.php
Line Number: 330
Note that when I call a single stored procedure it works fine. Here is the code for model.
class Menus_model extends CI_Model {
function __construct()
{
parent::__construct();
}
public function getMenus()
{
$query = $this->db->query("call uspGetMenus()");
return $query->result();
}
public function getSubMenus()
{
$query = $this->db->query("call uspTest()");
return $query->result();
}
}
Here is the code from controller
class MYHQ extends CI_Controller {
public function __construct()
{
parent::__construct();
$this->load->model('menus_model');
}
public function index()
{
$menu = $this->menus_model->getMenus();
$submenu = $this->menus_model->getSubMenus();
}
}
Is there any solution without hacking the core of codeigniter??
I follow the blog of Mr. Tim Brownlaw:
http://ellislab.com/forums/viewthread/73714/#562711
First, modify application/config/config.php, line 55.
$db['default']['dbdriver'] = 'mysqli'; // USE mysqli
Then, add the following into mysqli_result.php that is missing this command for some strange reason (under /system/database/drivers/mysqli/mysqli_result.php).
/**
* Read the next result
*
* #return null
*/
function next_result()
{
if (is_object($this->conn_id))
{
return mysqli_next_result($this->conn_id);
}
}
Then, in your model, add $result->next_result().
Below is my example.
function list_sample($str_where, $str_order, $str_limit)
{
$qry_res = $this->db->query("CALL rt_sample_list('{$str_where}', '{$str_order}', '{$str_limit}');");
$res = $qry_res->result();
$qry_res->next_result(); // Dump the extra resultset.
$qry_res->free_result(); // Does what it says.
return $res;
}
Having the same problem I found another approach which doesn't change the core, but instead uses a small helper.
Edit: The below linked asset is nowhere to be found.
See CoreyLoose post.
https://ellislab.com/forums/viewthread/71141/#663206
I had to make a small adjusment to his helper though. The line
if( get_class($result) == 'mysqli_stmt' )
could possibly produce a warning since the $result sometimes is passed as a boolean. I just put a check prior to this line and now it works perfectly, with no tinkering with the core!
This seems to be a bug in CodeIgniter. How come it's still in there is beyond me.
However, there's a couple of ways to overcome it.
Check here: http://codeigniter.com/forums/viewthread/73714/
Basically, you modify mysqli_result.php to include next_result() function and make sure to call it after every stored proc. call.
Just note that it assumes you're using mysqli as your DB driver... but you can probably do something similar with any other. You can change your driver in /application/config/database.php It's the line that says
$db['default']['dbdriver'] = 'mysql';
by default. Change it to:
$db['default']['dbdriver'] = 'mysqli';
You could also just close/reopen a DB connection between the calls, but I would definitely advise against that approach.
change dbdriver to "mysqli"
put this function to your model and use it to call stored procedure
function call( $procedure )
{
$result = #$this->db->conn_id->query( $procedure );
while ( $this->db->conn_id->next_result() )
{
//free each result.
$not_used_result = $this->db->conn_id->use_result();
if ( $not_used_result instanceof mysqli_result )
{
$not_used_result->free();
}
}
return $result;
}