Multilingual databases using Codeigniter - php

I have applied the method Additional Translation Approach in the database design.
With such structure of the tables, the code becomes more complex for per query.
My PHP code in models:
<?php
// SHOW ALL RECORDS
$this->db->select('m.id, m.title, m.content');
$table = 'blog';
if (MULTILINGUAL) {
$this->db->from($table.' AS m');
$this->db->select('t.title, t.content');
$this->db->join($table.'_translation AS t', 'm.id = t.parent_id', 'left');
$this->db->where('t.language_id', LANGUAGE);
$query = $this->db->get();
} else $query = $this->db->get($table.' AS m');
?>
So I want to change it's code...
When MULTILINGUAL is true, and with per query has column fields is title, content,...
$table = 'blog';
$this->db->select('id, title, content');
$query = $this->db->get($table);
it will automatically use the method JOIN with a table have suffix _translation (as my code above).
Otherwise, queries should be run as a normal query.
How can I do modified db class but don't affects core system of Codeigniter?
PHP code (using Codeigniter):
// Query 1:
$this->db->select('id, title, content');
$query = $this->db->get('blog');
// Query 2:
$this->db->select('id, title, content');
$this->db->where('id', 1);
$query = $this->db->get('blog');
Produces $this->db->last_query():
if (MULTILINGUAL) {
// Query 1:
// SELECT t.title, t.content FROM blog AS m LEFT JOIN blog_translation AS t ON m.id = t.parent_id WHERE t.language_id = 1
// Query 2:
// SELECT t.title, t.content FROM blog AS m LEFT JOIN blog_translation AS t ON m.id = t.parent_id WHERE t.language_id = 1 WHERE m.id = 1
else {
// Query 1:
// SELECT title, content FROM blog
// Query 2:
// SELECT title, content FROM blog WHERE id = 1
}
I want it to be completely automatic.
I think that could change the db class to solve this problem, but direct intervention into the core system is unstable (within core update)...
I truly appreciate your help in resolving my problem!

This might help you to work around I don't know how you were using that config file but can achieve that functionality as
function your_function($multilingual = false) {
$table = 'blog';
if ($multilingual === true) {
$this->db->select('t.title, t.content');
$this->db->join($table . '_translation AS t', 'm.id = t.parent_id', 'left');
$this->db->where('t.language_id', LANGUAGE);
$query = $this->db->get($table . ' AS m')->result_array();
} else {
$this->db->select('m.id, m.title, m.content');
$query = $this->db->get($table . ' AS m')->result_array();
}
return $query;
}

You could create a view and just call : $this->db->where('t.language_id', LANGUAGE); , but I don't know really if this is a better solution.

Related

codeigniter join same table multiple values

i need some codeigniter 3 help from you friends. its like 10 years ago when i did some more complex querys and my noobish JOIN-trys just gave me errors and questionmarks for hours.
lets say i have a mysql table covers
id, text, bgcolor_id, color_id
example : 1, "nice headline", 55, 88
and a table colors
id, value, name
example : 55, #FF0000, "red"
example : 88, #000000, "black"
how to "link" based on bgcolor_id, color_id in table covers
cover.bgcolor_id ->
color.value AS bgcolorvalue
color.name AS bgcolorname
cover.color_id ->
color.value AS colorvalue
color.name AS colorname
my codeigniter model
public function list(){
$query = $this->db->query('SELECT * FROM covers ORDER BY id DESC');
return $query->result_array();
}
public function get($id){
$query = $this->db->query('SELECT * FROM covers WHERE id = ' . $id);
return $query->row();
}
Join twice your colors table
select c.*,c1.name bgcolorname,
c1.value bgcolorvalue,
c2.name colorname,
c2.value colorvalue
from covers c
join colors c1 on c.bgcolor_id = c1.id
join colors c2 on c.color_id = c2.id
DEMO
I strongly recommend you to use the query builder Reference
You could to something like.
$cv = 'covers';
$cl1 = 'colors';
$cl2 = 'colors';
$get = array(
$cv.'.id',
$cv.'.text',
$cv.'.bgcolor_id',
$cv.'.color_id',
$cl1.'.value as bgcolorvalue',
$cl1.'.name as bgcolorname',
$cl1.'.value as colorvalue',
$cl1.'.name as colorname'
);
$this->db->select($get);
$this->db->from($cv);
$this->db->where($cv.'.id', 1);
$this->db->join($cl1, $cv.'.bgcolor_id = ' . $cl1.'.id');
$this->db->join($cl2, $cv.'.color_id = ' . $cl2.'.id');
$result = $this->db->get()->result();
let me know if this works
As i have understood your question right then you want to join on colors table twice for bgcolor_id and color_id, so here i am providing solution for your question let me know if it works or something wrong with the solutuion, thanks.
public function list(){
$query = $this->db->select("covers.*, bg.value AS bgcolorvalue bg.name AS
bgcolorname, colors.value AS colorvalue
colors.name AS colorname")
->join("colors", "colors.id = covers.color_id", "left")
->join("colors as bg", "bg.id = covers.bgcolor_id", "left")
->get("covers")->result();
return $query->result_array();
}

How can I achieve a UNION query using Codeigniter's active records? [duplicate]

How to do UNION query with PHP CodeIgniter framework's active record query format?
CodeIgniter's ActiveRecord doesn't support UNION, so you would just write your query and use the ActiveRecord's query method.
$this->db->query('SELECT column_name(s) FROM table_name1 UNION SELECT column_name(s) FROM table_name2');
By doing union using last_query(), it may hamper performance of application. Because for single union it would require to execute 3 queries. i.e for "n" union "n+1" queries. It won't much affect for 1-2 query union. But it will give problem if union of many queries or tables having large data.
This link will help you a lot: active record subqueries
We can combine active record with manual queries.
Example:
// #1 SubQueries no.1 -------------------------------------------
$this->db->select('title, content, date');
$this->db->from('mytable');
$query = $this->db->get();
$subQuery1 = $this->db->_compile_select();
$this->db->_reset_select();
// #2 SubQueries no.2 -------------------------------------------
$this->db->select('title, content, date');
$this->db->from('mytable2');
$query = $this->db->get();
$subQuery2 = $this->db->_compile_select();
$this->db->_reset_select();
// #3 Union with Simple Manual Queries --------------------------
$this->db->query("select * from ($subQuery1 UNION $subQuery2) as unionTable");
// #3 (alternative) Union with another Active Record ------------
$this->db->from("($subQuery1 UNION $subQuery2)");
$this->db->get();
This is a quick and dirty method I once used
// Query #1
$this->db->select('title, content, date');
$this->db->from('mytable1');
$query1 = $this->db->get()->result();
// Query #2
$this->db->select('title, content, date');
$this->db->from('mytable2');
$query2 = $this->db->get()->result();
// Merge both query results
$query = array_merge($query1, $query2);
Not my finest work, but it solved my problem.
note: I didn't need to order the result.
You may use the following method to get the SQL statement in the model:
$this->db->select('DISTINCT(user_id)');
$this->db->from('users_master');
$this->db->where('role_id', '1');
$subquery = $this->db->_compile_select();
$this->db->_reset_select();
This way the SQL statement will be in the $subquery variable, without actually executing it.
You have asked this question a long time ago, so maybe you have already got the answer. if not, this process may do the trick.
by modifying somnath huluks answer, i add these following variable and functions to DB_Active_rec class as follows:
class DB_Active_records extends CI_DB_Driver
{
....
var $unions;
....
public function union_push($table = '')
{
if ($table != '')
{
$this->_track_aliases($table);
$this->from($table);
}
$sql = $this->_compile_select();
array_push($this->unions, $sql);
$this->_reset_select();
}
public function union_flush()
{
$this->unions = array();
}
public function union()
{
$sql = '('.implode(') union (', $this->unions).')';
$result = $this->query($sql);
$this->union_flush();
return $result;
}
public function union_all()
{
$sql = '('.implode(') union all (', $this->unions).')';
$result = $this->query($sql);
$this->union_flush();
return $result;
}
}
therefore you can virtually use unions without dependencies to db_driver.
to use union with this method, you simply make regular active record queries, but calling union_push instead of get.
note: you have to ensure your queries have matching columns like regular unions
example:
$this->db->select('l.tpid, l.lesson, l.lesson_type, l.content, l.file');
$this->db->where(array('l.requirement' => 0));
$this->db->union_push('lessons l');
$this->db->select('l.tpid, l.lesson, l.lesson_type, l.content, l.file');
$this->db->from('lessons l');
$this->db->join('scores s', 'l.requirement = s.lid');
$this->db->union_push();
$query = $this->db->union_all();
return $query->result_array();
would produce:
(SELECT `l`.`tpid`, `l`.`lesson`, `l`.`lesson_type`, `l`.`content`, `l`.`file`
FROM `lessons` l
WHERE `l`.`requirement`=0)
union all
(SELECT `l`.`tpid`, `l`.`lesson`, `l`.`lesson_type`, `l`.`content`, `l`.`file`
FROM `lessons` l
JOIN `scores` s ON `l`.`requirement`=`s`.`lid`)
I found this library, which worked nicely for me to add UNION in an ActiveRecord style:
https://github.com/NTICompass/CodeIgniter-Subqueries
BUT I had to grab the get_compiled_select() method from the dev branch of CodeIgniter first (available here: https://github.com/EllisLab/CodeIgniter/blob/develop/system/database/DB_query_builder.php -- DB_query_builder will be replacing DB_active_rec). Presumably this method will be available in a future production release of CodeIgniter.
Once I added that method to DB_active_rec.php in system/database it worked like a charm. (I didn't want to use the dev version of CodeIgniter as this is a production app.)
try this one
function get_merged_result($ids){
$this->db->select("column");
$this->db->distinct();
$this->db->from("table_name");
$this->db->where_in("id",$model_ids);
$this->db->get();
$query1 = $this->db->last_query();
$this->db->select("column2 as column");
$this->db->distinct();
$this->db->from("table_name");
$this->db->where_in("id",$model_ids);
$this->db->get();
$query2 = $this->db->last_query();
$query = $this->db->query($query1." UNION ".$query2);
return $query->result();
}
This is solution I am using:
$union_queries = array();
$tables = array('table1','table2'); //As much as you need
foreach($tables as $table){
$this->db->select(" {$table}.row1,
{$table}.row2,
{$table}.row3");
$this->db->from($table);
//I have additional join too (removed from this example)
$this->db->where('row4',1);
$union_queries[] = $this->db->get_compiled_select();
}
$union_query = join(' UNION ALL ',$union_queries); // I use UNION ALL
$union_query .= " ORDER BY row1 DESC LIMIT 0,10";
$query = $this->db->query($union_query);
bwisn's answer is better than all and will work but not good in performance because it will execute sub queries first.
get_compiled_select does not run query; it just compiles it for later run so is faster
try this one
$this->db->select('title, content, date');
$this->db->where('condition',value);
$query1= get_compiled_select("table1",FALSE);
$this->db->reset_query();
$this->db->select('title, content, date');
$this->db->where('condition',value);
$query2= get_compiled_select("table2",FALSE);
$this->db->reset_query();
$query = $this->db->query("$query1 UNION $query2");
Here's a solution I created:
$query1 = $this->db->get('Example_Table1');
$join1 = $this->db->last_query();
$query2 = $this->db->get('Example_Table2');
$join2 = $this->db->last_query();
$union_query = $this->db->query($join1.' UNION '.$join2.' ORDER BY column1,column2);

Duplicated Values with GROUP_CONCAT - CI

I have some problem with a table that I want to build.
This table use a mysql database with mutliple tables linked by many-to-many tables.
I use JSON code to insert values in the jQuery Table.
Here is the model used to query the values in database :
function list_all()
{
$login_id = $this->session->userdata('User_id');
$this->db->select('p.project_id, p.Project, p.Description, p.Status, p.Thumbnail, p.StartDate, p.EndDate, t.template_id, t.Template')
->select('GROUP_CONCAT(DISTINCT v.Name SEPARATOR ",") as PeopleList, GROUP_CONCAT(DISTINCT w.asset_id SEPARATOR ",") as AssetsList', FALSE)
->from('projects p')
->join('assigned_projects_ppeople a', 'a.project_id = p.project_id')
->join('assigned_assets_pproject w', 'w.project_id = p.project_id', 'left')
->join('project_templates t', 't.template_id = p.template_id')
->join('people v', 'v.people_id = a.people_id')
->where('a.people_id', $login_id)
->group_by('p.project_id');
$query = $this->db->get();
$rows = $query->result_array();
//Return result to jTable
$jTableResult = array();
$jTableResult['Result'] = "OK";
$jTableResult['Records'] = $rows;
$result = json_encode($jTableResult);
return $result;
}
All values are well listed in the jQuery table, except GROUP_CONCAT values which are duplicated for People Name by the number of assets listed in Assets column...
EDIT : Problem resolved using DISTINCT keyword in GROUP_CONCAT.
But, if there's no entry assets linked to a project, the project doesn't be loaded and doesn't appear in table. EDIT : Resolved using LEFT JOIN on "assigned_assets_pproject" table.
Here is the screenshot of the table with JSON code http://i.stack.imgur.com/jEj4D.png
For information, there's just one user "Michael Bonfill" in each project.
Here is the output of last_query()
SELECT `p`.`project_id`, `p`.`Project`, `p`.`Description`, `p`.`Status`, `p`.`Thumbnail`, `p`.`StartDate`, `p`.`EndDate`, `t`.`template_id`, `t`.`Template`, GROUP_CONCAT(v.Name SEPARATOR ", ") as PeopleList, GROUP_CONCAT(w.asset_id SEPARATOR ", ") as AssetsList
FROM (`projects` p)
JOIN `assigned_projects_ppeople` a ON `a`.`project_id` = `p`.`project_id`
JOIN `assigned_assets_pproject` w ON `w`.`project_id` = `p`.`project_id`
JOIN `project_templates` t ON `t`.`template_id` = `p`.`template_id`
JOIN `people` v ON `v`.`people_id` = `a`.`people_id`
WHERE `a`.`people_id` = '1'
GROUP BY `p`.`project_id`
I can export the SQL of my database for more info if you want.
Thank you !
use DISTINCT keyword like that GROUP_CONCAT(DISTINCT v.Name SEPARATOR ",")

how to get article from the specific category joomla

In joomla 2.5 is there any built in function to fetch all article from the specific category.
I don't want to use custom query to fetch article from the database.
I would use the articles model
JLoader::import('joomla.application.component.model');
JModelLegacy::addIncludePath(JPATH_SITE.'/components/com_content/models', 'ContentModel');
$model = JModelLegacy::getInstance('Articles', 'ContentModel');
$model->getState();
$model->setState('list.limit', 10);
$articles = $model->getItems();
I'm not sure how're you're setting up your slider however to answer your actual question:
$db = JFactory::getDbo();
$query = $db->getQuery(true);
$query->select('*')
->from($db->quoteName('#__content'))
->where($db->quoteName('catid') . ' = 2');
$db->setQuery($query);
$rows = $db->loadObjectList();
foreach ( $rows as $row ) {
echo $row->introtext;
}
There is a built in function to get articles using the route.php I believe which is what the likes of Accordions use and so on, however for the most simple method, use the above.
Note: Don't forget to change the catid value from 2 to whatever suits your needs.
Hope this helps
I create small function to get category and return all articles with custom fields
function getArticlesByCategory($categoryId, $limit = "")
{
if (is_int($limit) && !empty($limit)) {
$limit = "LIMIT $limit";
}
$articles = JFactory::getDBO()->setQuery('
SELECT
C.*,
CONCAT(
"{",
GROUP_CONCAT(CONCAT(\'"\',F.name,\'"\', ":",\'"\',V.value,\'"\')),
"}"
) AS \'additional_fields\'
FROM
#__content AS C
LEFT JOIN #__fields_values AS V
ON
V.item_id = C.id
LEFT JOIN #__fields AS F
ON
F.id = V.field_id
WHERE
C.catid = \'' . $categoryId . '\' AND F.context = "com_content.article"
GROUP BY
C.id ' . $limit
)->loadObjectList();
if($articles){
foreach ($articles as $article) {
$article->additional_fields = json_decode($article->additional_fields);
}
}
return $articles;
}
Usage
$categoryId = 9;
$limit = 4;
getArticlesByCategory(9,2);
Tested on Joomla! 3.8.11
I don't like solutions like this one, but Joomla! made me do it.
Check this out: /modules/mod_articles_category for a full-fledged (and fairly slow) implementation. You might want to make it simpler:
select introtext, params from #__content where catid=%s AND state=1 AND ...
(you might want to add some checks on publish_up fields etc, but if you're happy with managing published/unpublished and don't use publish_up / down you don't need to do this).
Make sure you implement the module correctly to leverage Joomla cache, even if this query is fast it's best to avoid repeating it adlib. Read this for more details on module's cache
If you are creating a module, you may just create a module that has a type Article Category. Then, on the right side, click on the Filtering Options and there, select the category you want to show.

Zend Framework Select Objects And UNION()

I'm pretty sure this is not possible in Zend Framework (I have searched the Web, the documentation and issue tracker) but I just want to make sure so I'm asking here.
$select = $this->select();
$select->union($select1, $select2);
That doesn't work of course. To explain what I need. I need to use UNION() to merge 2 tables in a SELECT query, I know I could just do:
$select = "$select1 UNION $select2";
The problem is that would return a string and I need to get a select object so I can use it with Zend_Paginator.
I have already solved the issue by modifying my database architecture but I'm just curious if there is some workaround for this.
Here's what I've done to make a union:
$select = $this->select();
//common select from both sides of the union goes here
$select1 = clone($select);
//select1 specifics here
$select2 = clone($select);
//select 2 specifics here
$db = $this->getAdapter();
$pageselect = $db->select()->union(array("($select1)", "($select2)"));
Remember Db_Select's __toString will print out the SQL generated by that select, to help you debug.
Zend_Db_Select has a union method so I'd have thought it is possible, if you can build your query using a select object. I haven't used Zend_Db_Select (or the table subclass) with union but I'd imagine you can do something like
$select = $this->select()
->where('blah')
->union($sql);
a complete example:
public function getReservationById($id)
{
if(!$id) return null;
$sql = $this->table->select();
$sql->union(array(
$this->table->select()->where('id=?', $id),
$this->tableFinished->select()->where('id=?', $id),
$this->tableCanceled->select()->where('id=?', $id),
$this->tableTrashed->select()->where('id=?', $id)
));
echo $sql->__toString();
}
and the generated query:
SELECT reservations.* FROM reservations WHERE (id='5658') UNION SELECT res_finished.* FROM res_finished WHERE (id='5658') UNION SELECT res_cancel.* FROM res_cancel WHERE (id='5658') UNION SELECT res_trash.* FROM res_trash WHERE (id='5658')
This practical example shows a function that returns a rowset of either latest or if a available favourite blog entries of a specific year (artwork blog):
public function fetchBestOf($year)
{
$selectLatest = $this->select()->where('isHidden = 0')
->where('YEAR(dateCreated) = ' . $year)
->where('isHighlight = 0');
$selectHighlights = $this->select()->where('isHidden = 0')
->where('YEAR(dateCreated) = ' . $year)
->where('isHighlight = 1');
$selectUnion = $this->select()->union(array($selectLatest, $selectHighlights), Zend_Db_Select::SQL_UNION_ALL)
->order('isHighlight DESC')
->order('dateCreated DESC')
->order('workID DESC')
->limit('5');
$rowset = $this->fetchAll($selectUnion);
return $rowset;
}
The best way Zend suggest is like follows....
$sql = $this->_db->select()
->union(array($select1, $select2,$select3))
->order('by_someorder');
echo $sql->__toString();
$stmt = $db->query($sql);
$result = $stmt->fetchAll();
echo will show the query
Here $select1, $select2, $select3 can be different select queries with same
number of columns...
This is how it works for me:
$select1 = $this->select();
$select2 = $this->select();
After getting the necessary data in both queries the UNION syntax goes like this:
$select = $this->select()->union(array('('.$select1.')', '('.$select2.')'));

Categories