Paginate search results in Cakephp - php

I made a report of the databases created in a server, showing some row counters results from similar tables on those databases, using a table named Host to change the database configuration..Now I'm trying to add a simple search form in the same view to show only the macthed results. But I having problems with pagination.
In the HostController:
<?php
class HostsController extends AppController {
public $paginate = array('limit' => 1); //just as a test
function index() {
$conditions = array();
if(!empty($_GET['host_name'])){
$asd=($_GET['host_name']);
$asd=strtoupper($asd);
$conditions = array(
'OR' => array(
'upper(Host.client_name) LIKE' => "%$asd%",
'upper(Host.contact_name) LIKE' => "%$asd%",
'upper(Host.contac_email) LIKE' => "%$asd%"));
}
$hosts = $this->Host->find('all', array('conditions'=>$conditions));
foreach ($hosts as $key => $host) {
App::import('model','Product');
$this->Product = new Product;
$this->Product->changeDataSource($host['Host']['db_name']);
if($this->changeDbSource($host['Host']['db_name'])) {
$count = $this->Product->query('SELECT count(id) as "Product__count" from products');
$hosts[$key]['Host']['count_products']= $count[0]['Product']['count'];
$options = array(
'conditions' => array(),
'order' => array(
'Product.created DESC'));
$product = $this->Product->find('first', $options);
$hosts[$key]['Host']['last_product'] = $product['Product'];
}
App::import('model','Sale');
$this->Sale = new Sale;
$this->Sale->changeDataSource($host['Host']['db_name']);
if($this->changeDbSource($host['Host']['db_name'])) {
$count = $this->Sale->query('SELECT count(id) as "Sale__count" from sales');
$hosts[$key]['Host']['count_sales']= $count[0]['Sale']['count'];
$options = array(
'conditions' => array(),
'order' => array(
'Sale.created DESC'));
$sale = $this->Sale->find('first', $options);
$hosts[$key]['Host']['last_sale'] = $sale['Sale'];
} }
$this->set(compact('hosts'));
$this->paginate ();}///<<<< Here is the problem?>
In the view:
<form method="GET" >
<input id="clientNameSearch" type="text" name="host_name"
value="<?php echo !empty($_GET['host_name']) ?
$_GET['host_name']:"";?>" placeholder="Client, Contact or email of the contact" >
<input type="submit" value="Search">
</form>
In the app controller(with a database config per row in hosts table):
function changeDbSource($database = 'default') {
$db = ConnectionManager::getInstance();
$connected = $db->getDataSource($database);
if($connected->isConnected()) {return true;} else {return false;}}
So, using just $this->paginate (); give me the WHOLE LIST of host table (or the search result) and doesnt paginate, only the leyend of the button result of
echo $this->Paginator->counter(array('format' => __());
in the view seems to work
I've been trying some variations on paginate() arguments, using conditions, definig a custom paginate() and others options suggested here with no positive result, probably because I'm new on this.
According to the documentation, I shoud be able to use:
<?php
if (!empty($_GET['host_name'])){
$asd=($_GET['host_name']);
$asd=strtoupper($asd);
$this->paginate = array(
'conditions' => array(
'OR' => array(
'upper(Host.client_name) LIKE' => "%$asd%",
'upper(Host.contact_name) LIKE' => "%$asd%",
'upper(Host.contac_email) LIKE' => "%$asd%")
),'limit' => 2);}//just a test
if(empty($_GET['host_name'])) {$this->paginate();}?>
Still, no results.
So, if anyone know how to make it work or any suggestion, I'm all ears.
Thanks in advance(sorry for the poor english and coding).
Solution:?
Since there was no anwsers..here is what I got:
I just put the next code before the foreach loops
if (!empty($_GET['host_name'])){
$getvar=($_GET['host_name']);
$getvar=strtoupper($getvar);
$this->paginate = array(
'conditions' => array(
'OR' => array(
'upper(Host.client_name) LIKE' => "%$getvar%",
'upper(Host.contact_name) LIKE' => "%$getvar%",
'upper(Host.contac_email) LIKE' => "%$getvar%",
'upper(Host.company_ruc) LIKE' => "%$getvar%")
),
'limit' =>2);}
$hosts=$this->paginate ();
And in the Index.php:
<?php
$args = $_GET;
unset($args['url']);
$paginator->options(
array(
'url' => $this->passedArgs + array('?'=>$args)
)
);?>
It shows what I need, in the way I need, but the sort option apparenly doesnt work..I guess I wont use it

Add the search form in your view:
echo $this->Form->create('Host');
echo $this->Form->text('keywords');
echo $this->Form->submit('Search');
echo $this->Form->end();
Add the search form method in your controller:
$settings = array();
// Simple search method
if(! empty($this->request->data['Host']['keywords'])){
$keywords = explode(' ',$this->request->data['Host']['keywords']);
foreach($keywords as $key=>$keyword){
$settings['conditions']['OR'][] = array('Host.foo Like' => '%'.$keyword.'%');
$settings['conditions']['OR'][] = array('Host.bar Like' => '%'.$keyword.'%');
}
}
$this->paginate = $settings;
$this->set('hosts', $this->Paginator->paginate('Host'));
(Replace Host.foo and Host.bar with the columns you want to search in your hosts table - you can add more if you need to).
The standard Cake paginator will work for you in your index view:
<table>
<thead>
<tr>
<th><?php echo $this->Paginator->sort('name'); ?></th>
</tr>
</thead>
<tbody>
<?php foreach ($hosts as $host): ?>
<tr>
<td><?php echo h($host['Host']['name']); ?> </td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
Remember the Paginator->sort('heading') must match the name of the column in your table, if you want a different title to show on your page you can use the second - title - argument i.e. Paginator->sort('column_name', 'Title to Display');
Should get you rolling.

Related

How to display the value of array as string or text not as index value

I have two table one for sections where each section has many questions when i echo i got the section text but the questions as index value 0 1 2
<?php
$result = mysql_query($query);
if ($result) {
$data = array();
while ($row = mysql_fetch_assoc($result)) {
$data[($row['SECTION_NAME'])][][($row['QUES_TEXT'])][] = array(
'SECTION' => $row['SECTION_NAME'],
'QUESTION' => $row['QUES_TEXT']
);
}
foreach ($data as $SECTION => $QUESTIONS) {
echo '<h2>',htmlentities($SECTION),'</h2>';
foreach ($QUESTIONS as $QUESTIONS_TEXT => $TEXT) {
echo '<h2>',($QUESTIONS_TEXT),'</h2>';
}
}
}
?>
You are creating extra nested arrays and also the parens are unneeded:
$data[$row['SECTION_NAME']][][$row['QUES_TEXT']][] = array(
'SECTION' => $row['SECTION_NAME'],
'QUESTION' => $row['QUES_TEXT']
);
Should be:
if (empty($data[$row['SECTION_NAME']]) {
$data[$row['SECTION_NAME']] = array();
}
$data[$row['SECTION_NAME']][$row['QUES_TEXT']] = array(
'SECTION' => $row['SECTION_NAME'],
'QUESTION' => $row['QUES_TEXT']
);
Also please see the comments to your original question, this is no longer a safe way to use MySQL from PHP.

How to delete records based on the multiple where conditions as an array in laravel

I am searching in docs and in the stack exchange for days that, is there any way that I can actually pass an array with multiple conditions in it to delete the record in the Laravel 4.2?
Example
I want to achieve something like below
DELETE FROM `employees` WHERE user_id = 5 AND dept_id = 5
For this can I do something like below?
$whereArray = array('user_id'=>5,'dept_id'=>5);
return DB::table('employees')->where($whereArray)->delete();
I know I can use multiple where conditions to achieve this. But for every time a new condition arrives I have to rewrite the function. And also I cannot use this function as dynamic one.
So please help me this? How can achieve this using the array?
You can't directly pass in the array, but you could process the array:
$whereArray = array('user_id' => 5,'dept_id' => 5);
$query = DB::table('employees');
foreach($whereArray as $field => $value) {
$query->where($field, $value);
}
return $query->delete();
This functionality can be extracted out into a function, or even a model scope, that accepts your array and builds and returns the query to you.
For example, if you have an Employee model:
class Employee extends Eloquent {
public function scopeWhereArray($query, $array) {
foreach($array as $field => $value) {
$query->where($field, $value);
}
return $query;
}
}
Then you could do:
$whereArray = array('user_id' => 5,'dept_id' => 5);
return Employee::whereArray($whereArray)->delete();
Edit
If you wanted to be able to supply the operator, as well, you'd just need to change the format of your array:
$whereArray = array(
array(
'field' => 'user_id',
'operator' => '=',
'value' => 5
),
array(
'field' => 'dept_id',
'operator' => '=',
'value' => 5
),
array(
'field' => 'salary',
'operator' => '<',
'value' => 5000
)
);
return Employee::whereArray($whereArray)->delete();
And you would need to update your function:
class Employee extends Eloquent {
public function scopeWhereArray($query, $array) {
foreach($array as $where) {
$query->where($where['field'], $where['operator'], $where['value']);
}
return $query;
}
}

Dynamic variables in looper

This is my simple looper code
foreach( $cloud as $item ) {
if ($item['tagname'] == 'nicetag') {
echo $item['tagname'];
foreach( $cloud as $item ) {
echo $item['desc'].'-'.$item['date'];
}
} else
//...
}
I need to use if method in this looper to get tags with same names but diferent descriptions and dates. The problem is that I dont know every tag name becouse any user is allowed to create this tags.
Im not really php developer so I'm sory if it's to dummies question and thanks for any answers!
One possible solution is to declare a temporary variable that will hold tagname that is currently looped through:
$currentTagName = '';
foreach( $cloud as $item ) {
if ($item['tagname'] != $currentTagName) {
echo $item['tagname'];
$currentTagName = $item['tagname'];
}
echo $item['desc'] . '-' . $item['date'];
}
I presume that your array structure is as follows:
$cloud array(
array('tagname' => 'tag', 'desc' => 'the_desc', 'date' => 'the_date'),
array('tagname' => 'tag', 'desc' => 'the_desc_2', 'date' => 'the_date_2'),
...
);
BUT
This solution raises a problem - if your array is not sorted by a tagname, you might get duplicate tagnames.
So the better solution would be to redefine your array structure like this:
$cloud array(
'tagname' => array (
array('desc' => 'the_desc', 'date' => 'the_date'),
array('desc' => 'the_desc_2', 'date' => 'the_date_2')
),
'another_tagname' => array (
array('desc' => 'the_desc_3', 'date' => 'the_date_3'),
...
)
);
and then you can get the data like this:
foreach ($cloud as $tagname => $items) {
echo $tagname;
foreach($items as $item) {
echo $item['desc'] . '-' . $item['date'];
}
}

php and mysql foreach only displays the first record four times

I built a function to get the records from the database, and I'm trying to print the results using a foreach loop.
Here's my function:
function get_posts($connection) {
$posts = array();
$sql = "SELECT * FROM posts ORDER BY stamp DESC";
$result = mysqli_query($connection, $sql);
while ($post = mysqli_fetch_object($result)) {
$posts = array('body' => $post->body,
'stamp' => $post->stamp,
'post_id' => $post->id,
'user_id' => $post->user_id);
}
return $posts;
}
And now I'm trying to display the results using the following code:
$posts = get_posts($connection);
foreach ($posts as $key => $value) {
echo $posts['body'] . "<hr>";
}
When using that bit of code it only returns the first record from the database 4 times. I've used var_dump to make sure it's indeed an array, and it is. I must be using the foreach loop incorrectly here.
PS: Could the mysqli_fetch_object be turned into mysqli_fetch_assoc for that matter? I think it might be easier to use that but I don't know how to use it inside a function. Any code bits are appreciated.
Thank you!
you should put new elements into new indexes of array like this:
while ($post = mysqli_fetch_object($result)) {
$posts[] = array('body' => $post->body,
'stamp' => $post->stamp,
'post_id' => $post->id,
'user_id' => $post->user_id);
}
Note that before this you should initialize $post as an array like:
$posts = array();
and then you can retrieve information this way:
foreach($posts as $postInfo) {
foreach($postInfo as $key => $val) {
echo '<p>' .$key . ': ' . $val. '</p>';
}
}
this will echo :
body : foo
stamp : (timestamp)
...
...
In the function get_posts you override the previous values in the $posts array.
Try this:
array_push($posts, array('body' => $post->body,
'stamp' => $post->stamp,
'post_id' => $post->id,
'user_id' => $post->user_id));
You need to change $posts into a multidimensional array which can easily be done by doing this:
...
$posts[] = array('body' => $post->body,
...
then the rest of your code will work as you planned.

Relationship in php array

I am using Gdata API to get Youtube video and comments. The reply is in XML which contains an array inside it.
For video ID and comments the XML response are different. For example I am getting array ID as video ID array and for one ID one or many comments in array.
Array of both video ID and comments is as follow:
foreach ($array as $entry)
{
$videoid = basename($entry);
$video[] = $videoid;
$logger->info('Response From Youtube:videoid=>' . $videoid);
}
$this->view->videoid = $video;
$author = array();
$content = array();
$arraycnt = array();
foreach ($video as $id)
{
$comment = "http://gdata.youtube.com/feeds/api/videos/".$id."/comments";
$sxml1 = simplexml_load_file($comment);
$entries = $sxml1->entry;
foreach ($entries as $a)
{
$author[] = $a->author->name;
$content[] = $a->content;
}
}
And the particular view as follow:
<table>
<tr>
<td>
<?php
for($i=0;$i<$length;$i++)
{
?>
<embed
width="420" height="345"
src="http://www.youtube.com/v/<?php echo $videoid[$i];?>"
type="application/x-shockwave-flash">
</embed>
<?php
}
?>
</td>
<td>
<?php
foreach($content as $cont)
{
?>
<p>Comment:<?php echo $cont;?></p>
<?php
}
?>
</td>
<td>
<?php
foreach($author as $auth)
{
?>
<p>Commented By:<?php echo $auth;?></p>
<?php
}
?>
</td>
</tr>
</table>
How can I show the video and comments in the view like:
videoA1 commentA1 commentA2
videoB1 commentB1 commentB2 commentB3
You can keep the id of the video in $author and $content arrays.
foreach ($video as $id)
{
foreach ($entries as $a)
{
$author[$id][] = $a->author->name;
$content[$id][] = $a->content;
}
}
So you can get comment's authors from specific video id:
foreach ($video as $id)
{
echo $id;
foreach($author[$id] as $auth) {
echo ' ', $auth;
}
}
The same goes with comment's content.
Of course you can extend this solution if you want to have just one array for comment's authors and content, but the logic stays the same.
What you actually have here is that you first iterate over the videos and then per each video you iterate over the comments.
So you have a nested iteration: Level 1: Videos, Level 2: Comments.
As I commented earlier you can create a data-structure that is able to have data that can be iterated that way in a multi-dimensional array. Let's take two Youtube videos here in the following example:
-FRm3VPhseI: The Clean Code Talks - "Global State and Singletons"
RlfLCWKxHJ0: The Clean Code Talks - Don't Look For Things!
So if you would want to create a multi-dimenstional array over these two videos with all their comments, you could choose the following format:
$videos = array(
'-FRm3VPhseI' => array(
'id' => '-FRm3VPhseI',
'title' => 'The Clean Code Talks - "Global State and Singletons"',
'href' => 'http://www.youtube.com/watch?v=-FRm3VPhseI&feature=youtube_gdata',
'comments' => array(
array(
'author' => 'Nelson ThePrimate',
'content' => 'There is a cost for r...',
),
array(
'author' => 'dennisdegreef',
'content' => 'That is also a global...',
),
array(
'author' => 'MorleyCode',
'content' => 'State is unavoidable,...',
),
// ...
array(
'author' => 'Jacob Jensen',
'content' => 'I don\'t quite underst...',
),
array(
'author' => 'unity20000',
'content' => 'Testing is not the on...',
),
array(
'author' => 'drummist180',
'content' => 'Turing machine > line...',
),
),
),
'RlfLCWKxHJ0' => array(
'id' => 'RlfLCWKxHJ0',
'title' => 'The Clean Code Talks - Don\'t Look For Things!',
'href' => 'http://www.youtube.com/watch?v=RlfLCWKxHJ0&feature=youtube_gdata',
'comments' =>
array(
array(
'author' => 'Nikolai Paul',
'content' => 'this guy sometimes so...',
),
array(
'author' => 'Madrid Softwaree',
'content' => 'Learn Selenium , QTP ...',
),
array(
'author' => 'Roger Keulen',
'content' => 'Di: Great as a FXCop ...',
),
// ...
array(
'author' => 'michaeldeng1981',
'content' => 'if I do outsourcing p...',
),
array(
'author' => 'Rico Lelina',
'content' => 'How about loggers? Is...',
),
array(
'author' => 'twistedbydsign99',
'content' => '11:55 it should defin...',
),
),
),
);
It first contains all videos keyed/indexed by the Youtube ID and then inside all the comments. To output this, you only have to nest two foreach clauses:
foreach ($videos as $videoId => $video)
{
printf("%s: %s\n", $videoId, $video['title']);
printf(" Comments (%d):\n", count($video['comments']));
foreach ($video['comments'] as $i => $comment)
{
printf(" #%d %s: %s\n", $i + 1, $comment['author'], $comment['content']);
}
echo "\n";
}
Which will create the following output:
-FRm3VPhseI: The Clean Code Talks - "Global State and Singletons"
Comments (6):
#1 Nelson ThePrimate: There is a cost for r...
#2 dennisdegreef: That is also a global...
#3 MorleyCode: State is unavoidable,...
#4 Jacob Jensen: I don't quite underst...
#5 unity20000: Testing is not the on...
#6 drummist180: Turing machine > line...
RlfLCWKxHJ0: The Clean Code Talks - Don't Look For Things!
Comments (6):
#1 Nikolai Paul: this guy sometimes so...
#2 Madrid Softwaree: Learn Selenium , QTP ...
#3 Roger Keulen: Di: Great as a FXCop ...
#4 michaeldeng1981: if I do outsourcing p...
#5 Rico Lelina: How about loggers? Is...
#6 twistedbydsign99: 11:55 it should defin...
Note that in this output the number of comments are limited to 6 each time because I reduced the amount of comments for the example array. Now compare closely how the structure of the nested, multi-dimensional array is read from with the nested foreach clauses. The outer foreach is reading the video, the inner foreach is reading the comments.
This btw. is the same with building that array, it works as well with two nested iterations. To make this more simple I first create a caching variable and some helper functions:
$gdataFetchCache = [];
$gdataFetch = function ($url) use (&$gdataFetchCache)
{
if (!isset($gdataFetchCache[$url]))
{
$gdataFetchCache[$url] = simplexml_load_file($url);
}
return $gdataFetchCache[$url];
};
$gdataNamed = function ($pattern) use ($gdataFetch)
{
return function ($value) use ($pattern, $gdataFetch)
{
return $gdataFetch(sprintf($pattern, $value));
};
};
$ytVideo = $gdataNamed('http://gdata.youtube.com/feeds/api/videos/%s');
$ytComments = $gdataNamed('http://gdata.youtube.com/feeds/api/videos/%s/comments');
These functions allow to fetch Youtube data more easily inside the nested foreach-es:
$videoIds = ['-FRm3VPhseI', 'RlfLCWKxHJ0'];
$videos = [];
foreach ($videoIds as $videoId)
{
$video = $ytVideo($videoId);
$videoArray = [
'id' => (string)$videoId,
'title' => (string)$video->title,
'href' => (string)$video->link['href'],
'comments' => [],
];
$videos[$videoId] = $videoArray;
foreach ($ytComments($videoId)->entry as $comment)
{
$videos[$videoId]['comments'][] = [
'author' => (string)$comment->author->name,
'content' => (string)$comment->content,
];
}
}
If you compare closely again, it has the same structure as the output code.
This is how you can read and create multi-dimensional arrays for which the count is not known in advance. By iterating you create the code for one element but use it as often as you have elements.
This also works nested.

Categories