So I have a Post which has Comments -- I'm trying to get the Comment # position within that post. For example, a Post has 15 comments, I want to be able to get the numerical position (i.e 1 (first post), 2 (second post), 3 (third post), etc, etc), and put this into a function somehow. That way when I can call $comment->position() and it will show as the 4th, 5th, whatever position in it is in.
I've done some searching around the web and couldn't find a solution. Any help is greatly appreciated! This is what I have so far:
public function position($id,$arr)
{
$total = $this->post->comments->count();
$position = $this->pluck('post_id')->search($this->id) + 1;
return ceil($total / $position);
//$comments_per_page = 25;
//$pos = array_search($id,$arr);
//$pos = $pos+1;
//return ceil($pos/$comments_per_page);
}
You should first get all your comments as collection.
// all comments as collection
$comments = $this->post->comments;
Then you can search through the collection using the search function and inserting an id you want to search for ... or any other param you want.
$id = 2;
$commentIndex = $comments->search(function($comment) use ($id) {
return $comment->id === $id;
});
Related
I have a table that contains different versions of a text. I want to display the diffs of each version with the previous version. I also want to paginate through the versions, in case there are more than 20. However, to diff the last text on each page I would need the first text of the next page. I cannot just make the page size one larger (21 in this case), because the second page would skip its first entity, and the third its first two etc.
$config = $this->Paginator->getConfig();
$this->Paginator->setConfig('limit', $config['limit'] + 1);
$inscriptions = $this->paginate($query);
I might instead be able to solve the problem by making a separate ->paginate() call for the single entity, but I would rather not execute a second query if possible.
$inscriptions = $this->paginate($query);
$config = $this->Paginator->getConfig();
$this->Paginator->setConfig([
'limit' => 1,
'page' => ($config['page'] * $config['limit']) + 1
]);
$inscriptions[] = $this->paginate($query)->first();
Is there a way to skip the first n results? In that case I could set the page size to 21 but set the page number to 1, and skip the first ((old page number - 1) * old page size) entities.
It is possible to make a custom paginator that extends the default one, but functions as described:
<?php
namespace App\Datasource;
use Cake\Core\InstanceConfigTrait;
use Cake\Datasource\Paginator;
use Cake\Datasource\QueryInterface;
use Cake\Datasource\RepositoryInterface;
class DiffPaginator extends Paginator
{
use InstanceConfigTrait;
protected function getQuery(RepositoryInterface $object, ?QueryInterface $query = null, array $data): QueryInterface
{
$data['options']['offset'] = ($data['options']['page'] - 1) * $data['options']['limit'];
$data['options']['limit'] += 1;
unset($data['options']['page']);
return parent::getQuery($object, $query, $data);
}
protected function buildParams(array $data): array
{
$paging = parent::buildParams($data);
if ($paging['current'] == $paging['perPage'] + 1) {
$paging['current'] -= 1;
}
return $paging;
}
}
In your controller then use the following:
$this->Paginator->setPaginator(new DiffPaginator);
I try to make a "getThreeWorks" method with Laravel. Each view post to its 'orientation'. It is stored in the same table. For example, "Work 1 has the web orientation, Work 2 has the 2D orientation and Work 3 has the 3D orientation".
At the end of each post, I would like to propose a link to 3 other works (in a random order).
So I would like a link to a work that has the "web" orientation, another that has the "2D" orientation and one that has the "3D" orientation.
I can't get SQL query at all. Can you help me ? Thank you !
public function getThreeWorks()
{
$workFrom3D = Work::where('orientation', '3D')->inRandomOrder->limit(1)->get();
$workFrom2D = Work::where('orientation', '2D')->inRandomOrder->limit(1)->get();
$workFromWeb = Work::where('orientation', 'web')->inRandomOrder->limit(1)->get();
}
Can't you remove the limit(1) and instead use a group by orientation? Then you get one of each.
You can create a new collection with your current code.
$work = collect([$workFrom3D, $workFrom2D, $workFromWeb]);
If i understood, you want show some "posts" on footer of each post, right ? you can try this:
public function getThreeWorks()
{
$workFrom3D = Work::where('orientation', '3D')->get();
$workFrom2D = Work::where('orientation', '2D')->get();
$workFromWeb = Work::where('orientation', 'web')->get();
$randomFrom3d = $workFrom3D->random();
$workFrom2D = $workFrom2D->random();
$workFromWeb = $workFromWeb->random();
}
also, you should include one more condition on your where, to avoid repeat the same post on page where will show this list, like:
$workFromWeb = Work::where('orientation', 'web')
->where('post_id','!=', $actualPostId)->get();
I am building a project using Codeigniter + MySQL + Active Record.
In my MySQL db i have a table named Requests with columns protocol,year and some other columns where i store general information of a request (like title, subject etc...), nothing special to mention.
Protocol and year are TYPE INT and must be auto generated like below.
Every year, at 01/01/XXXX-00:00:00 the protocol field must reset to number 1 (the first request saved after 01/01/XXXX, must have protocol value 1) and for the upcoming requests, increase it sequentially by 1, until next year and so on.
To reset the protocol, i will add a cron in a later phase where i will do a trick to reset. Still don't know how.
What i need to do now:
Whenever i add a new request, the protocol of the new row must be increased by 1.
Pseudocode:
new_protocol = previous_protocol + 1
What i am doing so far
I have a function in my model which Inserts a new request, but so far i do nothing about the protocol number, i enter it manually through my form.
public function addRequest($request) {
$this->db->insert('requests', $request);
if ($this->db->affected_rows() == 1)
return $this->db->insert_id();
return FALSE;
}
What is the most efficient way to achieve this?
Should i find the last protocol number in my Controller -> add 1 -> send to model to add?
Should i find the LAST and MAX protocol number in model -> add 1 -> insert to db?
Something else?
Any ideas will be appreciated.
I'd approach like so:
add column ID in your table and set it to auto-increment
php - set the default timezone to use (since PHP 5.1): date_default_timezone_set('UTC');
php - get current year: $cyear=date("Y");
get row max(ID) and compare if the stored year has changed compared to $cyear
if it has changed and following your pseudocode example:
new_protocol = 1
otherwise
new_protocol = previous_protocol + 1
Ok so i created a library in Codeigniter and wrote 2 functions, 1 in Library and 1 in Model.
Library
public function getProtocolNumber() {
$CI = &get_instance();
$year = date('Y');
$max_protocol = $CI->request_model->getYearsProtocol($year);
$max_protocol = $max_protocol['max_protocol_number'];
if ($max_protocol && !empty($max_protocol) && $max_protocol != NULL) {
$protocol_number = (int) $max_protocol + 1;
} else {
$protocol_number = 1;
}
return $protocol_number;
}
Model
public function getYearsProtocol($year) {
$qry = $this->db->select('MAX(protocol_number) as max_protocol_number')
->from('requests')
->where('protocol_year', $year)
->get();
if ($qry->num_rows() > 0)
return $qry->row_array();
return FALSE;
}
Can anyone please show me how to filter an Aerospike LLIST bin not by the key and return all the result using PHP.
In my case the bin 'notes' is containing many rows of key, title, desc & category. I can retrieve all rows using the following code but
I need to do a filter on the category and get the results of only those within the same category. If udf is needed please assist to show me the udf code as well and how to apply the filter to get the results.
$db = new Aerospike($config, false);<br/>
$key = $db->initKey('mynamespace', 'myset', $userid);<br/>
$list = new \Aerospike\LDT\LList($db, $key, 'notes');<br/>
$status = $list->scan($results);
The LList.scan method has an optional module name, function name pair of parameters, allowing you to call a Lua function to filter each element.
There's an example PHP script provided with the client repo, which calls an example Lua module:
function keyfilters.even_filter(element)
local remainder = -1
if type(element) == "number" then
remainder = element % 2
elseif (getmetatable(element) == getmetatable(map())) and element['key'] then
remainder = element['key'] % 2
end
if remainder == 0 then
return element
else
return nil
end
end
Is invoked by
$rental_history->scan($elements, 'keyfilters', 'even_filter');
Manage to modify the UDF as follows and it works.
local category_filters = {}
function category_filters.filterBy(element,val)
if element['category'] == val[1] then
return element
else
return nil
end
end
return category_filters
Invoked by
$status = $list->scan($results, 'category_filters', 'filterBy', array($category));
I am making a real estate related app and I've been having a hard time figuring out how to set up the query so that it would return "Only Apartments or Duplexes within selected areas" I'd like to user to be able to find multiple types of property in multiple selected quadrants of the city.
I have a database with a column "type" which is either "Apartment", "House", "Duplex", "Mobile"
In another column I have quadrant_main with values: "NW", "SW", "NE", "SE".
My code works when there is only 1 quadrant selected, but when I select multiple quadrants, I seem to get results which includes ALL the property types from the second or third or 4th quadrant, instead of only "Apartment" and "Duplex" or whatever types the user selects... Any help will be appreciated! thx in advance.
My controller function looks like this:
public function quadrants()
{
$input = \Request::all();
$currentPage = null;
$column = "price";
$order = "desc";
//
// Looks like the input is like 0 => { key: value } ...
// (an Array of key/value pairs)
$q = Listing::where('status','=','Active')->where(function($query) {
$input = \Request::all();
$currentPage = null;
$typeCount = 0;
$quadrantCount = 0;
foreach( $input as $index => $object ) {
$tempObj = json_decode($object);
$key = key((array)$tempObj);
$val = current((array)$tempObj);
if ( $key == "type" ) {
if ( $typeCount > 0 ) {
$query->orWhere('type', '=', $val );
}
else {
$query->where('type', '=', $val );
$typeCount++;
}
}
if ( $key == "quadrant_main" ) {
if ( $quadrantCount > 0 ) {
$query->orWhere('quadrant_main', '=', $val );
}
else {
$query->where('quadrant_main', '=', $val );
$quadrantCount++;
}
}
// else {
// $query->orWhere($key,$val);
// }
}
if( $currentPage ) {
//Force Current Page to Page of Val
Paginator::currentPageResolver(function() use ($currentPage) {
return $currentPage;
});
}
});
$listings = $q->paginate(10);
return $listings;
Looking at your question, its a bit confusing and not much is given to answer definitely. Probable causes of your troubles may be bad data in database, or maybe corrupted input by user.
Disclaimer: Please note that chances are my answer will not work for you at all.
In that case please provide more information and we will work things
out.
There is one thing that I think you have overlooked and thus you are getting awry results. First let me assume a few things.
I think a sample user input should look like this:
array(
0: '{type: Apartment}',
1: '{type: Duplex}',
2: '{quadrant_main: NW}',
3: '{quadrant_main: SW}',
)
What the user meant was give me any apartment or duplex which belongs in NW or SW region.
So after your loop is over, the final SQL statement should be something like this:
Oh and while we are at SQL topic, you can also log the actual
generated SQL query in laravel so you can actually see what was the
final SQL getting generated. If you can post it here, it would help a
lot. Look here.
select * from listings where status = 'Active' and (type = 'Apartment' or type = 'Duplex' and quadrant_main = 'NW' or quadrant_main = 'SW');
What this query will actually produce is this:
Select any listing which is active and:
1. Type is an apartment, or,
2. Type is a duplex, or,
3. Quadrant is SW, and,
4. Quadrant is NW
So assuming you have a database like this:
id|type|quadrant_main
=====================
1|Apartment|NW
2|Apartment|SW
3|Apartment|NE
4|Apartment|SE
5|Duplex|NW
6|Duplex|SW
7|Duplex|NE
8|Duplex|SE
9|House|NW
10|House|SW
11|House|NE
12|House|SE
You will only receive 1, and 5 in the result set. This result set is obviously wrong, plus it is depended on NW because that was the and condition.
The correct SQL query would be:
select * from listings where status = 'Active' and (type = 'Apartment' or type = 'Duplex') and (quadrant_main = 'NW' or quadrant_main = 'SW');
So structure your L5 app such that it produces this kind of SQL query. Instead of trying to cram everything in one loop, have two loops. One loop should only handle type and another loop should only handle quadrant_main. This way you will have the necessary and condition in the right places.
As a side note:
Never directly use user input. Always sanitize it first.
Its not a best practice to put all your logic in the controller. Use repository pattern. See here.
Multiple where clauses are generally applied via Criteria. Check that out in the above linked repository pattern.
You code logic is very complicated and utterly un-necessary. Instead of sending JSON objects, simply send the state of checkboxes. Don't try to generalize the function by going in loop. Instead handle all checkboxes one by one i.e. is "Apartments" selected, if yes, add that to your clause, if not, don't add.