Using Laravel 5.5 with PHP 7.0, trying to create and append some queries to pagination following the docs.
https://laravel.com/docs/5.5/pagination#displaying-pagination-results
However with some queries which have multiple values, rendered links have different keys.
Simplest reproducing code is:
>>> User::query()->paginate(30)->appends(['query' => ['foo', 'bar', 'baz']])->nextPageUrl()
=> "http://homestead.app?query%5B0%5D=foo&query%5B1%5D=bar&query%5B2%5D=baz&page=2"
# expecting "http://homestead.app?query%5B%5D=foo&query%5B%5D=bar&query%5B2%5D=baz&page=2"
In other words, the next url of /user?page=1&query[]=1&query[]=2 should be:
/user?page=2&query[]=1&query[]=2
but actually
/user?page=2&query[0]=1&query[1]=2
What is wrong in my code?
Related
In Symfony 5, I would like to generate an URL partially based on GET paramaters already posted.
Let's assume that the URL posted is:
user/edit/5?foo=1&bar=1&baz=1&qux=1
I would like to generate in the controller without foo:
user/edit/5?bar=1&baz=1&qux=1
First, I remove foo parameter :
$request->query->remove('foo');
If I didn't get the user_id in the URL as route parameter (5), I would use:
$this->generateUrl('user_edit', $request->query->all());
But this is not working because user_id is missing. So how can I generated such URL without rewriting all variables:
$this->generateUrl('user_edit', ['id' => $user->getId(), ???]);
I was thinking about PHP function array_merge() but this seems to me more a trick than an elegant solution:
$this->generateUrl('user_edit', array_merge(
['id' => $user->getId()],
$request->query->all())
);
There is nothing wrong in using array_merge(). That's exactly what you want to accomplish. It's not a "trick", it's a language feature.
If you want a less verbose syntax, just use +.
$this->generateUrl('user_edit', $request->query->all() + ['id' => $user->getId()]);
The end result is exactly the same for the above, and it's shorter.
So in Laravel 5 there's the handy thing called JSON Where Clauses using MySQL's new ability to store and fetch JSON stored in a column:
User::where('meta->colors', 'red')->get()
would return all rows, where colors in the column meta would be set to red.
Now let's say colors is not a string, but an array containing multiple colors (colors => ['red', 'blue', 'green']).
What would be an efficient way to retrieve all rows, where colors contains e.g. the value red?
JSON_CONTAINS() does exactly what you're looking for:
JSON_CONTAINS(target, candidate[, path])
Indicates by returning 1 or 0 whether a given candidate JSON document is contained within a target JSON document, or—if a path argument was supplied—whether the candidate is found at a specific path within the target. — 12.16.3 Functions That Search JSON Values
Currently, Laravel's query builder does not provide a corresponding API. There's an open internals proposal for it though.
In the meantime, you can execute a raw query:
\DB::table('users')->whereRaw(
'JSON_CONTAINS(meta->"$.colors", \'["red"]\')'
)->get();
Which would return all users that have "red" in their meta->colors JSON field. Note that the -> operator requires MySQL 5.7.9+.
You can also call the whereRaw() directly on an Eloquent model.
Laravel 5.6
As of the 5.6 release, Laravel's query builder contains a new whereJsonContains method.
I think a way would be using the like operator:
User::where('meta->colors', 'like', '%"red"%')
However, this would only work if the values never contain the character " and the delimiters wouldn't change.
An update for this answer, according to MySQL or MariaDb, the correct syntax must be JSON_CONTAINS(#json, 'red', '$.colors'), and is necessary to use JSON_EXTRACT.
So them, the code inside Laravel (for version 5.5 or less).
Like say #Elwin, meta column must contains the following JSON: { "colors": ["red", "blue", "green"] }
User::whereRaw("JSON_CONTAINS(JSON_EXTRACT(meta, '$.colors'), '\"{$color}\"')")
Remember to use double quotes in value sentence.
JSON_CONTAINS(JSON_EXTRACT(meta, '$.colors'), '"red"')
The whereIn method verifies that a given column's value is contained within the given array.
Try this:
$colorArray = ['red', 'blue', 'green'];
$user = User::whereIn($meta->color, $colorArray)->get();
More about Laravel's whereIn.
I'm looking to call an array through a URL, and I have looked through the questions but from what I've seen they're all for creating a url from an array/something of that sort.
I'm a bit new to HTML and such, but I can read and understand a decent amount. What I'm trying to do is make a shortcut on a website that allows me to call an array through the URL.
I get an error saying I can either use an int or an array, but I haven't found if I need a certain value in the url or I'm just calling the array the wrong way. I know how to make one in java/javascript and C++, as well as calling via code, but not through URL like it's saying I can.
Reason I'm looking to do this is get something done at a faster pace, and all at once instead of one by one. I'm using Google Chrome, and the website uses yuigen, as well as javascript, but the URL doesn't direct anything through PHP thatI know of.
Based on your comments, you want to take a URL like this:
http://this.com/?thisArray=1|2|5|6|10|5
and get an array of the values in thisArray. Just do this:
$theArray = explode('|', $_GET['thisArray']);
// now, $theArray is a PHP array: [1, 2, 5, 6, 10, 5]
$_GET['thisArray'] accesses your URL parameter, and explode('|', ...) splits it on the pipes.
Say your HTTP request is formatted like this:
GET /path/to/file.php?var[]=1&var[]=2
PHP will populate that into an array named $_GET: array('var' => array(1, 2))
My question is... is this a PHP thing or is this behavior governed by an RFC? How would a web accessible node.js or Python script deal with this?
PHP by default will overwrite previous values, and you end up with the LAST key:value pair found in the query string. But in PHP you can use the [] array as fieldname hack:
example.com?foo=bar&foo=baz&foo=qux
example.com?foo[]=bar&foo[]=baz&foo[]=qux
Line #1 produces $_GET like this:
$_GET = array(
'foo' => 'qux'
);
Line #2 produces
$_GET['array'] = array
'foo' => array('bar', 'baz', 'qux');
}
Note that this behavior is PHP specific. Other languages do their own thing. As far as I remember, Perl by default will keep all values as an array.
This is a specific feature of PHP with no related RFCs or other specs. I can't find any specific statements to that effect, but reading this FAQ Q/A seems to imply the same:
http://docs.php.net/manual/en/faq.html.php#faq.html.arrays
Background: Using CodeIgniter with this MongoDB library.
This is my first go-round with mongodb and I'm enjoying it thus far. It's taken a while for me to separate myself from the sql way of thinking, but it is a perfect fit for my current project.
I'm trying to push an array into a document using...
$this->mongo_db->where(array('_id'=>$estimate_id))->push("measurements", $newData)->update('estimates');
If I encode $newData using json_encode($newData) I get {"levels":[{"level_qty":12,"level_uom":"ft"}]}
The problem is, when my function creates the measurements line in the mongodb document, it automatically starts an array with my insertion at [0]. Like this...
"measurements" : [ { "levels" : [ { "level_qty" : 12, "level_uom" : "ft" } ] }]
...leaving me with...
-measurements
--0
----levels
-----0
------level_qty => 2,
------level_uom => ft
What I really want is...
-measurements
--levels
---0
----level_qty => 2,
----level_uom => ft
I'm certain I'm missing something fairly elementary (i.e. php related & not mongodb related), but I'm an admitted amateur who has waded too deep.
$push is used to append a value to an array. In your example, measurements is an array and Mongo is appending $newData as its first element. This explains the 0 index between measurements and levels. In your desired result, measurements is an object equivalent to $newData (i.e. it has a levels property, which in turn has an array of objects within).
Either of the following examples should accomplish what you want:
// if $newData is {"levels": [{"level_qty":12,"level_uom":"ft"}]}
->set("measurements", $newData)
// if $newData is [{"level_qty":12,"level_uom":"ft"}]
->set("measurements.levels", $newData)
// if $newData is {"level_qty":12,"level_uom":"ft"}
->push("measurements.levels", $newData)
Note: $push is going to be more flexible if you want to append data with future updates, whereas $set will naturally overwrite the given field.