Codeigniter dynamic multiple instances for loading custom library - codeigniter

I wanted to create instances in a loop, which means the number of instances totally depends on the loop. I'm not able to achieve it.
I've come across many posts regarding the same and was successful for,
$this->load->library('stlstats', $param, 'instance1');
$volume1 = $this->instance1->getVolume($unit);
$this->load->library('stlstats', $param, 'instance2');
$volume2 = $this->instance2->getVolume($unit);
//Don't bother about $param and $unit, those are pre-defined.
So, in the above code, I'm able to achieve getting different volumes. But I want it to be created each iteration. If I place the code inside the loop say,
$this->load->library('stlstats', $param, 'instance1');
$volume1 = $this->instance1->getVolume($unit);
And print $volume1, then the output is the same for all the iteration.
Since I have no idea about the number of iterations of the loop, how can I achieve this?
Thank you all :)

You placed this code in a loop:
$this->load->library('stlstats', $param, 'instance1');
$volume1 = $this->instance1->getVolume($unit);
But where is the loop variable?
You are always using the same instance alias 'instance1'.
A simple solution will be for example (COUNT is the number of iterations):
$volume = array(); // Store all volumes in array
for ($i = 1; $i < COUNT; $i++) {
$instance = 'instance' . $i;
$this->load->library('stlstats', $param, $instance);
$volume[$i] = $this->$instance->getVolume($unit); // Add value to array
}

CodeIgniter caches the already loaded libraries, so it will give back the same instance.
By the way you shouldn't create multiple instances, instead you should re-organize your library code (instead of set the params in the constructor you should create a setter method) like this:
// library
class Stlstats {
protected $params = array();
public function __construct() {
}
public function setParam($params) {
$this->params = $params;
}
public function getVolume($unit) {
$this->params = $params;
// example code:
return ($unit * $params['distance']);
}
}
// load once the library
$this->load->library('stlstats');
// test data
$unit = 22;
$all_params = array(
array('distance'=>3),
array('distance'=>5),
array('distance'=>7),
);
// use it in loop
foreach($all_params as $params) {
$this->stlstats->setParam($param);
echo $this->stlstats->getVolume($unit);
}

The answer is very simple. I'm sure many might have come across this situation and I hope this answers.
$this->load->library('stlstats', $param, 'instance1');
$volume1 = $this->instance1->getVolume($unit);
Place the above code into the loop and at the end of the loop include this,
unset($this->instance1);
As simple as that :)
Thank you #Zaragoli your answer made me think in a right way :) Cheers!!

Related

How can I cross join dynamically in Laravel?

I want to create product variations like this image:
I have tried with static data it works.
$collection = collect(["XL", "XXL"]);
return $collection->crossJoin(["1kg", "2kg"], ["Red", "Green"]);
But I want to create this dynamically. I have tried this way.
$collections = [];
foreach ($request->options as $key => $option) {
if($key == 0) continue;
array_push($collections, $option["option_values"]);
}
return $collection->crossJoin($collections);
Its return like this image.That is not exact I want. I figured out problem that is $collections is a new array and option values inside this array. So that it's return like this. But I can not solve this problem.
I have dd my request data.
You were on the right track. The way I see it you need something like:
// all of my options
$options = [];
// Just store all options in the array
// I am going to assume $option["option_values"] is always an array
foreach ($request->options as $key => $option) {
array_push($options, $option["option_values"]);
}
// Get the first element so we can use collections
// and the crossJoin function
$start = array_shift($options);
return collect($start)->crossJoin(...$options);
The (...$options) kind of explodes all elements in the array and sets them as paramenters.
Some people may tell you to use the function call_user_func_array which allows you to call a function with its arguments as an array, like so...
call_user_func_array('some_function', ['argument1', 'argument2']);
Unfortunately I have never used this function. If there is someone with more experience who can implement it, I would like to know how it would be done.

Encrypting url(parameters only)

In one of projects i got recently have all the urls like
www.abc.com/controller/action/1222
I want to encrypt the url parameters only to achieve something like
www.abc.com/controller/action/saddsadad232dsdfo99jjdf
I know I can do it by changing all the urls one by one and sending the encrypted parameters and dealing with them all over the places in the project.
So my question is Is there a way I can encrypt all the urls at once without making changes to every link one by one ?
Just need a direction.I guess I put all the details needed.
thanks !
Here is a solution if you use the site_url helper function and you are sure that all your URLs comply this format www.abc.com/controller/action/1222:
All you need is to override the site_url method of the CI_Config class
class MY_Config extends CI_Config
{
public function site_url($uri = '', $protocol = NULL)
{
$urlPath = ltrim(parse_url($this->_uri_string($uri), PHP_URL_PATH), '/');
$segments = explode('/', $urlPath);
$numOfSegments = count($segments);
$result = [$segments[0], $segments[1]]; // controller and action
// start from the third segment
for($i = 2; $i < $numOfSegments; $i++)
{
// replace md5 with your encoding function
$result[] = md5($segments[$i]);
}
return parent::site_url($result, $protocol);
}
}
Example:
echo site_url('controller/action/1222'); will outputwww.abc.com/controller/action/3a029f04d76d32e79367c4b3255dda4d
I use a Hashids helper. I think this will do what you're after.
You can pass parameters to your functions like this:
base_url('account/profile/' . hashids_encrypt($this->user->id))
You can then decrypt it within the function and use it however you want:
$id = hashids_decrypt($id);

Random unique ids

I'm trying to generate something like 6B6E23518 using randomString() which I'm calling inside my controller
function randomString($chars=10) //generate random string
{
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$randstring = '';
for ($i = 0; $i < $chars; $i++) {
$randstring .= $characters[rand(0, strlen($characters))];
}
return $randstring;
}
public function store(TicketsCreateRequest $request)
{
$ticket = $user->tickets()->create([
'ticket_hash' => $this->randomString(10),
// ....
]);
}
but this keeps on storing 0 into 'ticket_hash' and nothing gets generated??
Looking at your source code, is randomString() a public method of your controller class or is it a global function declared elsewhere outside of the class? I ask because it's entered above without the public visibility qualifier and with slightly different indentation to the method below it.
If this function is not an instanace method of your class, then your call to $this->randomString() is probably not calling the method you're expecting it to call. If your randomString() function is a global function defined elsewhere you should call it directly (eg. 'ticket_hash' => randomString(10),)
For what it's worth, for random strings like this it might be best to use the Laravel framework's Str class, only because it may be more stable and is definitely more widely used.
The Str::random() method achieves the output you're looking for in this case.
column ticket_hash was an integer type ,changed it to varchar and it works now.

codeigniter count_all_results

I'm working with the latest codeIgniter released, and i'm also working with jquery datatables from datatables.net
I've written this function: https://gist.github.com/4478424 which, as is works fine. Except when I filter by using the text box typing something in. The filter itself happens, but my count is completely off.
I tried to add in $res = $this->db->count_all_results() before my get, and it stops the get from working at all. What I need to accomplish, if ($data['sSearch'] != '') then to utilize the entire query without the limit to see how many total rows with the search filter exists.
If you need to see any other code other than whats in my gist, just ask and I will go ahead and post it.
$this->db->count_all_results() replaces $this->db->get() in a database call.
I.E. you can call either count_all_results() or get(), but not both.
You need to do two seperate active record calls. One to assign the results #, and one to get the actual results.
Something like this for the count:
$this->db->select('id');
$this->db->from('table');
$this->db->where($your_conditions);
$num_results = $this->db->count_all_results();
And for the actual query (which you should already have):
$this->db->select($your_columns);
$this->db->from('table');
$this->db->where($your_conditions);
$this->db->limit($limit);
$query = $this->db->get();
Have you read up on https://www.codeigniter.com/userguide2/database/active_record.html#caching ?
I see you are trying to do some pagination where you need the "real" total results and at the same time limiting.
This is my practice in most of my codes I do in CI.
$this->db->start_cache();
// All your conditions without limit
$this->db->from();
$this->db->where(); // and etc...
$this->db->stop_cache();
$total_rows = $this->db->count_all_results(); // This will get the real total rows
// Limit the rows now so to return per page result
$this->db->limit($per_page, $offset);
$result = $this->db->get();
return array(
'total_rows' => $total_rows,
'result' => $result,
); // Return this back to the controller.
I typed the codes above without testing but it should work something like this. I do this in all of my projects.
You dont actually have to have the from either, you can include the table name in the count_all_results like so.
$this->db->count_all_results('table_name');
Count first with no_reset_flag.
$this->db->count_all_results('', FALSE);
$rows = $this->db->get()->result_array();
system/database/DB_query_builder.php
public function count_all_results($table = '', $reset = TRUE) { ... }
The
$this->db->count_all_results();
actually replaces the:
$this->db->get();
So you can't actually have both.
If you want to do have both get and to calculate the num rows at the same query you can easily do this:
$this->db->from(....);
$this->db->where(....);
$db_results = $this->get();
$results = $db_results->result();
$num_rows = $db_results->num_rows();
Try this
/**
* #param $column_name : Use In Choosing Column name
* #param $where : Use In Condition Statement
* #param $table_name : Name of Database Table
* Description : Count all results
*/
function count_all_results($column_name = array(),$where=array(), $table_name = array())
{
$this->db->select($column_name);
// If Where is not NULL
if(!empty($where) && count($where) > 0 )
{
$this->db->where($where);
}
// Return Count Column
return $this->db->count_all_results($table_name[0]);//table_name array sub 0
}
Then Simple Call the Method
Like this
$this->my_model->count_all_results(['column_name'],['where'],['table name']);
If your queries contain a group by, using count_all_results fails. I wrote a simple method to work around this. The key to preventing writing your queries twice is to put them all inside a private method that can be called twice. Here is some sample code:
class Report extends CI_Model {
...
public function get($page=0){
$this->_complex_query();
$this->db->limit($this->results_per_page, $page*$this->results_per_page);
$sales = $this->db->get()->result(); //no table needed in get()
$this->_complex_query();
$num_results = $this->_count_results();
$num_pages = ceil($num_results/$this->results_per_page);
//return data to your controller
}
private function _complex_query(){
$this->db->where('a', $value);
$this->db->join('(subquery) as s', 's.id = table.s_id');
$this->db->group_by('table.column_a');
$this->db->from('table'); //crucial - we specify all tables here
}
private function _count_results(){
$query = $this->db->get_compiled_select();
$count_query = "SELECT count(*) as num_rows FROM (".$query.") count_wrap";
$r = $this->db->query($count_query)->row();
return $r->num_rows;
}
}

Codeigniter, where to run model save code if not in the destructor?

I have a model that works with one user in the database.
It is designed to do a lot of small changes to the user, so instead of querying the database multiple times I decided to get all of the user's information in the constructor of the model, and then work on that information through out the rest of the model (so instead of updating the database, it would be updating the array I got). Then I would just save that array back to the database in the destructor.
This works fine, but I've been reading a bit more, and it turns out you shouldn't run any non-cleanup code in the destructor (which is where I'm running the update query to the database). So I was curious, is there a better way to do this? Am I missing a better solution?
Thanks, Max
EDIT:
Here is an example of what I am doing (Note: This example is a shopping cart class, not a user class though):
<?php
class cartmodel extends CI_Model
{
private $sessionPrefix = 'Cart_';
private $CartCache = array();
function __construct ()
{
if ($this->session->userdata($this->sessionPrefix.'data') === FALSE)
$this->session->set_userdata($this->sessionPrefix.'data', array());
$this->CartCache = $this->session->userdata($this->sessionPrefix.'data');
parent::__construct();
}
function __destruct ()
{
$this->session->set_userdata($this->sessionPrefix.'data', $this->CartCache);
}
function AddItem ($id, $count)
{
if ($count == 0 || $count == '' || !is_numeric($count))
return;
if (!isset($this->CartCache[$id]))
$this->CartCache[$id] = 0; //Initialize it so that += works
$this->CartCache[$id] += (int)$count;
}
?>
You can directly manipulate session data in your AddItem() method. Something like this:
function AddItem ($id, $count)
{
// UPDATE CartCache VARIABLE
$this->CartCache = $this->session->userdata($this->sessionPrefix.'data');
// YOUR CODE BELOW
if ($count == 0 || $count == '' || !is_numeric($count))
return;
if (!isset($this->CartCache[$id]))
$this->CartCache[$id] = 0; //Initialize it so that += works
$this->CartCache[$id] += (int)$count;
// SAVE CartCache IN SESSION AGAIN
$this->session->set_userdata($this->sessionPrefix.'data', $this->CartCache);
}
This way if you want to manipulate the Cart_data session variable in other methods, you can still do it. Just update the CartCache array in every method and save it again to the session variable once you've done manipulating data in it.

Resources