EditableGrid, "addcolumn" loop - php

Trying to make a loop for EditableGrid code.
This is how it looks now.
$grid->addColumn('id', 'ID', 'integer');
$grid->addColumn('site', 'Site', 'string');
So if I need to add a new column to the page, I add a new column in MySQL database and also add a new row in this code, like:
$grid->addColumn('newcolumn', 'A brand new column', 'string');
In order to automatically add new columns to the page I want to make a loop, which gets inputs for the first argument (name of the field in the database) taken from the table:
CREATE TABLE price (
id INT(11) NOT NULL AUTO_INCREMENT,
site VARCHAR(50) NOT NULL,
and the other two arguments (label that will be displayed in the header and data type of the column in MySQL) taken from this table:
CREATE TABLE header (
header_name VARCHAR(50) NOT NULL,
header_type VARCHAR(50) NOT NULL,

Ok, think I found the solution. In order to create the loop, we create 2 queries, which are:
$get=$mysqli->query('SELECT header_name, header_type FROM header');
$get1=$mysqli->query('SHOW COLUMNS FROM price');
then we make a loop
while($row = mysqli_fetch_assoc($get) and $row1 = mysqli_fetch_assoc($get1)){
$grid->addColumn(''.$row1['Field'].'', ''.$row['header_name'].'', ''.$row['header_type'].'');}
I, guess, that's it. Also, if you need to exclude some of the columns, use this piece of code:
if($row1 == 'id' || $row1 == 'site')
continue;

Related

Update dynamic SQL table with history table

I was successful in implementing a table's history (for auditing) based on this answer that basically suggests to create two tables wherein one contains the current version and the other a table of versions with the real data:
CREATE TABLE dbo.Page(
ID int PRIMARY KEY,
Name nvarchar(200) NOT NULL,
CreatedByName nvarchar(100) NOT NULL,
CurrentRevision int NOT NULL,
CreatedDateTime datetime NOT NULL
CREATE TABLE dbo.PageContent(
PageID int NOT NULL,
Revision int NOT NULL,
Title nvarchar(200) NOT NULL,
User nvarchar(100) NOT NULL,
LastModified datetime NOT NULL,
Comment nvarchar(300) NULL,
Content nvarchar(max) NOT NULL,
Description nvarchar(200) NULL
My UPDATEs to static, non-dynamic fields are OK where the versioning is recognised correctly (rough pseudocode adapted from dev't code):
$sql_pagecontent = array(
'PageID' => // logic to get PageID
'Title' => $data['Title']
'User' => $data['User'],
'LastModified' => $this->get_date(),
'Comment' => $data['Comment'],
'Content' => $data['Content'],
'Description' => $data['Description']
);
$this->db->insert('PageContent', $sql_pagecontent);
$id_version = $this->db->insert_id();
$sql_page = array(
'CurrentRevision' => $id_version
);
if($type_version === 'UPDATE')
{
$this->db->where('ID', $page_id_to_replace);
$this->db->update('Page', $sql_page);
}
else
{
$this->db->insert('Page', $sql_page);
}
The problem is when I apply this to dynamic tables with UPDATE.
During UPDATE, I want to achieve the following, just similar to the non-dynamic tables (context of Page and PageContent):
a new PageContent row is INSERTed (new PageContent), a new row of CurrentRevision in Page is added
a new PageContent row is INSERTed (update of existing PageContent), the CurrentRevision in Page UPDATEd with this new row
deleted PageContents are removed from Page
NOTE I want each row of these dynamic tables preserved in both Page and PageContent if ever the user wants to check the changes so I just cannot do INSERT which will just flood the table.
I cannot seem to filter these dynamic values correctly with the current implementation.
Please advise on how to deal with this use case.
Solution
I am not sure if my current implementation of my said requirements is correct, feasible or recommended but it does the job:
get ID of current PageContent being modified
get ID of current Page being modified
delete all rows of Page that has the ID of #1
perform INSERT and apply UPDATE as type of action of PageContent
Number 3 is key to make sure whether existing rows are edited/deleted or new rows added are saved as the current version in Page. Number 4 puts this into place to make sure every row is recognised.

Codeigniter: Display only last date entry

I need to display just the last date entry for a person in a table, taken from joined tables.
I only seem to able to display the first entry or all.
Controller
public function session_view($id)
{
$data['main_view'] = 'session_view';
$data['view'] = $this->Swim_model->CRUD_read_session($id);
$this->load->view('load_view',$data);
}
Model
public function CRUD_read_session($sessionid)
{
return $this->db->select('*')
->from('sessionsandswimmers')
->join('child', 'ID = SwimmersID')
->join('swimmersawards', 'PersonID = ID')
->join('awards', 'AwardID = AwardsID')
->order_by('LastName')
->order_by('DateAwarded')
->where('SessionID', $sessionid)
->get();
}
View
foreach ($view->result() as $row)
{
echo '<tr>'.$row->FirstName.'</td><td'.$row->LastName.'</td><td>'.$row->Description.'</td><td>'.$row->DateAwarded.'</td></tr>';
}
Result
As you can see, there are several entries for each person (except 1st).
I need to display just the latest date entry for each person.
So there should only be 4 entries.
Table structure
sessionsandswimmers - each session has 4 swimmers
1 tempid Primary int(11) No None AUTO_INCREMENT
2 SessionID int(11) No None
3 SwimmersID int(11) No None
4 SessionSeasonID int(11) No None
5 Year int(11) No None
6 LocationSS int(11) No None
child - gets the swimmers name
swimmersawards - multiple entries per child
1 PersonID int(11) No None
2 AwardsID int(11) No None
3 DateAwarded date No None
awards - gets the name of the award
change ->order_by('DateAwarded') to ->order_by('DateAwarded','DESC') . Need to specify which type of ordering you want. And for just one entry per person use :
->group_by('FirstName,LastName')
If I understood correctly, the result you displayed is the table structure. Where you want the latest entry by date for each "name". If this is right then follow,
SELECT DISTINCT `name` FROM `<your-joined-tables>` order by `date` DESC
Sorry I am not good with CI's query builder.
Hope it works.

Using array in where clause, where the checked field contains coma separated words

Please, read the question carefully before you mark it as duplicate. It is not.
I have a table named questions, and I have field questionMetaTags in that table which accepts coma separated values (keywords)
Here is my table:
`questionID` int(11) NOT NULL AUTO_INCREMENT,
`questioncategoryID` int(11) NOT NULL,
`questionstatusID` int(11) NOT NULL,
`organizationID` int(11) NOT NULL,
`legalformID` int(11) DEFAULT NULL,
`questionProtocolID` varchar(45) DEFAULT NULL,
`questionDisplayedRecordID` int(11) NOT NULL,
`questionTitle` text NOT NULL,
`questionSummary` text,
`questionText` longtext NOT NULL,
`questionAnswerSummary` text,
`questionAnswerText` longtext,
`questionMetaTags` text,
`questionAskedBy` int(11) NOT NULL,
`questionAnsweredBy` int(11) DEFAULT NULL,
`questionAskedOnDate` datetime NOT NULL,
`questionAnsweredOnDate` datetime DEFAULT NULL,
`questionAskedFromIp` varchar(255) NOT NULL
I am trying to create a query which will "produce" related questions. I am displaying one specific question on my page, and I want bellow to display only the questions that:
1. Belong to same category
AND
2. Have at least 2 or more same keywords
In those 2 variables I am holding the category and the keywords of the displayed question, and I would now like to build the query which will display "related" questions.
$keywordsInQurrentQuestion (array that holds the keywords)
$questioncategoryID (category of the question)
I am trying with something like:
SELECT *
FROM question WHERE `questionstatusID` = 5
AND questioncategoryID = $questioncategoryID
// I have no idea how to check if the question have at least 2 keywords that exists in the $keywordsInQurrentQuestion array
");
I have found answers on how to use array in where clause since I want to check for at least 2 same keywords, those answers are not helpful to me.
Your database schema is not really made for that kind of queries. MySQL is a relational database after all.
Solution in MySQL (change of DB schema required)
It would be better to have an extra table for just keywords (or meta tags):
ID tag
1 oranges
2 apples
... ...
154 motor oil
A second table would then hold the relations between questions and tags:
questionID tagID
1 1
1 2
1 37
2 3
... ...
18 102
19 154
Now, when querying for a similar/related question, you can do so by checking your minimum of identical tags. First, a subquery is used to get all tags from your displayed question:
SELECT tagID FROM relations WHERE questionID = 123;
This will then be used in the actual query that retrieves the similar questions:
SELECT DISTINCT(r1.questionID)
FROM relation r1
INNER JOIN relation r2
ON r1.questionID = r2.questionID AND NOT r1.tagID = r2.tagID
WHERE r1.tagID IN (SELECT tagID FROM relations WHERE questionID = 123)
AND r2.tagID IN (SELECT tagID FROM relations WHERE questionID = 123)
This query joins the relation table with itself (selfjoin), looking for rows with an identical question ID but different tag IDs. In the WHERE clause it checks if both joined tags are within the set of the original question. Finally, it will remove all duplicates (DISTINCT) and give you a list of related question IDs.
This query still has to be expanded to check for the category, this has been left out to make the statement clear.
Solution in PHP
According to your comment, you do not want to change the DB schema. Although retrieving all questions from the database first and then get the related ones in PHP might not be the best choice in terms of execution time and performance, it is still possible.
Assuming you have all terms of your original question in some value
$meta_tags = "oranges,apples,avocados,olive oil";
and all your questions from the same category in an array containing at least the question ID and the respective keywords
$questions = array(
0 => array(
"questionID" => 1,
"metaTags" => "apples,olive oil",
),
1 => array(
"questionID" => 2,
"metaTags" => "oranges,motor oil",
),
2 => array(
"questionID" => 3,
"metaTags" => "oranges,avocados",
),
...
);
you can loop through your questions, check if at least two keywords are identical and then store the question IDs in some array:
function check_tags($needles, $haystack) {
$original_tags = explode(',', $haystack);
$original_tags = array_map('trim', $original_tags);
$tags_to_check = explode(',', $needles);
$tags_to_check = array_map('trim', $tags_to_check);
$count = 0;
foreach ($tags_to_check as $t) {
if (in_array($t, $original_tags)) {
count++;
}
}
return $count;
}
$related = array();
foreach ($questions as $q) {
if (check_tags($q['metaTags'], $meta_tags) >= 2) {
$related[] = $q['questionID'];
}
}
The array $related now contains all question IDs which are similar to your original question.

INSERT record if field value doesn't exist for another field

I have a form to edit a record (specimen). On the form is a multiple select list which contains records from a table (topic). This select list shows topics as selected that exist for the specimen (as identified in the specimen_topic lookup table) as well as those that can be added to the specimen (from the topic table).
I want to be able to add topics not selected in the list to the lookup table where the topic_fk does not already exist for the specimen_fk:
CREATE TABLE IF NOT EXISTS `specimen_topic_lookup` (
`specimen_topic_lookup_pk` int(6) NOT NULL AUTO_INCREMENT,
`specimen_fk` int(6) NOT NULL,
`topic_fk` int(3) NOT NULL,
PRIMARY KEY (`specimen_topic_lookup_pk`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_swedish_ci AUTO_INCREMENT=8 ;
Any ideas how I can do this?
UPDATE
I have made the fields specimen_fk and topic_fk UNIQUE. Using the code below, only one record is created in specimen_table lookup, when two records should have been created (before making the fields UNIQUE, two records were created OK...). I assume this is because $specimen_pk is the same value for each insert.
foreach($topics as $topic){
$query_topics = "INSERT IGNORE INTO specimen_topic_lookup(specimen_fk, topic_fk)
VALUES ('$specimen_pk', '$topic')";
$result_topics = mysql_query($query_topics, $connection) or die(mysql_error());
}
Looks like having UNIQUE is stopping having a record made with the same value (which is at least what I expected...)
THIS WORKS
Without having to make specimen_fk OR topic_fk UNIQUE...
foreach($topics as $topic){
$query_topics = "INSERT INTO specimen_topic_lookup(specimen_fk, topic_fk)
SELECT '$specimen_pk', '$topic'
FROM DUAL
WHERE NOT EXISTS (SELECT 1
FROM specimen_topic_lookup
WHERE specimen_fk = '$specimen_pk' AND topic_fk = '$topic')";
$result_topics = mysql_query($query_topics, $connection) or die(mysql_error());
Create a unique index on the table and use insert ignore or on duplicate key update:
create unique index specimen_topic_lookup(specimen_fk, topic_fk);
insert ignore into specimen_topic_lookup(specimen_fk, topic_fk)
select $speciment_fk, $topic_fk;
Or, alternatively, you can just do the following without the unique index:
insert into specimen_topic_lookup(specifmen_fk, topic_fk)
select $speciment_fk, $topic_fk
from dual
where not exists (select 1
from specimen_topic_lookup
where specimen_fk = $specimen_fk and topic_fk = $topic_fk
);
Use an INSERT IGNORE statement. This will insert any rows that do not violate the unique key, and ignore the ones that do.

IF and ELSE IF statements within a WHILE loop not working properly

I'm trying to create notification system for my community website, am trying to use a while loop to get data, when ever a condition in the if statement is met within the while loop, it should display/print data to the page. For some reason it's only displaying one result, dunno why.
The structure of my database:
CREATE TABLE IF NOT EXISTS `notifications` (
`notification_id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`to_id` int(11) NOT NULL,
`notification_identifier` enum('1','2','3','4','5','6') NOT NULL,
`notify_id` int(11) NOT NULL,
`opened` enum('0','1') NOT NULL,
`timestamp` datetime NOT NULL,
PRIMARY KEY (`notification_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;
The notification_identifier tell me what type of notification it is(e.g. profile comment, status update, likes) and the notify_id tells me id of each specific table i need to check with.
My code:
<?
$DisplayNotification ="";
$unread = "0";
$mynotify = mysql_query("SELECT * FROM notifications WHERE to_id='$logOptions_id' AND opened='$unread'") or die (mysql_error());
$notify_Count = mysql_num_rows($mynotify);
if($notify_Count>0){
while($row = mysql_fetch_array($mynotify)){
$notification_id = $row["notification_id"];
$memb_id = $row["user_id"];
$identifier = $row["notification_identifier"];
$notify_id =$row["notify_id"];
$timestamp = $row["timestamp"];
$convertedTime = ($myObject -> convert_datetime($timestamp));
$when_notify = ($myObject -> makeAgo($convertedTime));
if($identifier == 1){// condition 1
$DisplayNotification ='user added you as a friend';
}else if ($identifier == 2) {//condition 2
$DisplayNotification ='user commented on your post';
}
}
}else{// End of $notify
$DisplayNotification ='You have no new notifications.';
}
?>
any help appreciated
Where is $DisplayNotification actually displayed? It's certainly not within the body of your loop.
Each time through the loop you assign $DisplayNotification a new value, which of course replaces the old value. By the time you get done, no matter what's happened, the most recent change is the only one left.
Most likely I suspect you meant to do something like
$DisplayNotification .= "User added you as a friend\n";
The .= will continue adding new text to the same variable throughout the loop.
Or perhaps you could use an array, in which case you'd do
$DisplayNotifications[] = "User added you as a friend";
Then you could display all the items at the end however you'd like.
It looks like you run the while statement fully before actually dumping the variable $DisplayNotification. If that is the case, you're just switching values on the variable during the loop. You either need to store the values to be dumped inside an Array or just dump them inside the loop.

Categories