PHP custom sort preg_match_all? - php

So I know there are articles out there about custom ordering but I think my situation may be a little different (Or could just be my workaround sucks :P ). Here is the quick scenario.
I pull XML data from curl off a report url that we have. (not properly formatted!) So let's use the following example: I get the following data back in one long list.
<Site>My Sites</Site>
<Customer>PHPSTEVE</Customer>
<Name>Griswald</Name>
<Site> Evil Dead</Site>
<Customer>Bruce</Customer>
<Name>Campbell</Name>
I can't use the XML function because the format header is incorrect so I won't get into that.. So instead I use a preg_match_all
preg_match_all("/<Site>(.*?)<\/Site>|<Customer>(.*?)<\/Customer>|<Name>(.*?)<\/Name>/is", $resp, $output_array[]);
Then I go through and I know this is not good but it works..
foreach(array_reverse($output_array[0][0]) as $info){
$myinfo = $info . $myinfo;
}
Everything works as I use a str_replace and just put in my table tags etc.. Obviously I'm doing the reading in reverse.. it's ok I want it that way for this.
Site | Customer | Name
----------+----------+------
Evil Dead | Bruce | Campbell
What if I want "Customer" field first? So basically I'm changing the horizontal order of Site and Customer etc... Remember there are multiple records all in a line so I am trying to figure out how I would move Customer to where I want it.. or any field for that matter. Based off of my code above, I don't believe I can accomplish it the way I want to so I'm not sure of another way to do it.
I would like to report it as this:
Customer | Site | Name
---------+-----------+------
Bruce | Evil Dead | Campbell
Any help would be appreciated. NOTE: I don't care about reading bottom up or top down.. just field changes. Thanks
UPDATE: The XMl issue I run into is:
This XML file does not appear to have any style information associated with it. The document tree is shown below.
<results>
<Site>My Sites</Site>
<Customer>PHPSTEVE</Customer>
<Name>Griswald</Name>
<Site> Evil Dead</Site>
<Customer>Bruce</Customer>
<Name>Campbell</Name>
</results>

Maybe something like this?
function sortCustomerKeys($a, $b)
{
if ( $a == 'Customer' && $b != 'Customer' ) {
return 1;
} else if ( $a != 'Customer' && $b == 'Customer' ) {
return -1;
}
return strnatcasecmp($a, $b);
}
$customers = array();
$advance = array(
'Customer' => 0,
'Name' => 0,
'Site' => 0
);
if ( preg_match_all('#<(Customer|Name|Site)>\\s*(.*?)\\s*</\\1>#is', $resp, $m) ) {
for ($i = 0, $j = 0; $i < count($m[1]); $i++) {
$tag = $m[1][$i];
$value = $m[2][$i];
$customers[$j][$tag] = $value;
$advance[$tag] = 1;
if ( array_sum($advance) == count($advance) ) {
$advance = array(
'Customer' => 0,
'Name' => 0,
'Site' => 0
);
uksort($customers[$j], 'sortCustomerKeys');
$j++;
}
}
}
var_dump($customers);

Related

Twilio filter if the recording source is recordverb

I need to filter the recording list and I just only need to get the record verb for making my voicemails but the conference source is not filtered
$temp_arr = array();
foreach ($client->account->recordings->getIterator(0, 50, array('CallSid' => 'call sid here' , 'Source' => 'Recordverb')) as $recording){
$recording_uri = "https://api.twilio.com".$recording->uri;
$arr = array(
'rec' => $recording_uri,
);
array_push($temp_arr, $arr);
}
Are you trying to filter recordings based upon Conference or RecordVerb?
Source from the docs:
The type of call that created this recording. Possible values are
RecordVerb, DialVerb, Conference, OutboundAPI, Trunking.
You also have this 'Source' => 'Recordverb' where you could just have a typo with the lowercase 'v'.
I am late to respond but maybe someone else will get benefit from this. You may simply use this code for getting RecoredVerb
$recordings = $twilio->recordings->read([], 200);
foreach ($recordings as $record) {
if($record->source == 'RecordVerb'){
$record_sid= $record->sid;
}else if($record->source == 'DialVerb'){
}else {
}
}
You can do your desired work inside the conditions.

Laravel Eloquent: how to filter multiple and/or criteria single table

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.

Polymorph String To Pattern

I'm working on an issue where users (truck drivers in this case) use SMS to send in information about work status. I want to keep the keying simple as not all users have smart phones so I have adopted some simple short codes for their input. Here are some examples and their meanings:
P#123456-3 (This is for picking up load 123456-3)
D#456789-1 (For the dropping of load 456789-1)
L#345678-9 (Load 345678-9 is going to be late)
This is pretty simple but users (and truck drivers) being what they are will key the updates in somewhat deviant manners such as:
#D 456789-1
D# 456789 - 1
D#.456789-1 This load looks wet to me do weneed to cancelthis order
You can pretty much come up with a dozen other permutations and it's not hard for me to catch and fix those that I can imagine.
I mostly use regular expressions to test the input against all my imagined "bad" patterns and then extract what I assume are the good parts, reassembling them into the correct order.
It's the new errors that cause me problems so I got to wondering if there was a more generic method where I can pass a "pattern" and a "message" to a function that would do it's best to turn the "message" into something matching the "pattern".
My searches have not found anything that really fits what I'm trying to do and I'm not even sure if there is a good general way to do this. I happen to be using PHP for this implementation but any type of example should help. Do any of you have a method?
If the user has problems with your software, fix the software, not the user!
The problem arises because your format looks unnecessary complicated. Why do you need the hash in the first place? How about simplifying it down to the following:
operation-code maybe-space load-number maybe-space and comment
Operation codes are assigned to different phone keys, so that J, K and L mean the same thing. Load-numbers can be sent as digits and as letters as well, e.g. agja means 2452. It's hard for the user to make a mistake using this format.
Here's some code to illustrate this approach:
function parse($msg) {
$codes = array(
3 => 'DROP',
5 => 'LOAD',
// etc
);
preg_match('~(\S)\s*(\S+)(\s+.+)?~', $msg, $m);
if(!$m)
return null; // cannot parse
$a = '.,"?!abcdefghijklmnopqrstuvwxyz';
$d = '1111122233344455566677777888999';
return array(
'opcode' => $codes[strtr($m[1], $a, $d)],
'load' => intval(strtr($m[2], $a, $d)),
'comment' => isset($m[3]) ? trim($m[3]) : ''
);
}
print_r(parse(' j ww03 This load looks wet to me'));
//[opcode] => LOAD
//[load] => 9903
//[comment] => This load looks wet to me
print_r(parse('dxx0123'));
//[opcode] => DROP
//[load] => 990123
//[comment] =>
Try something like this:
function parse($input) {
// Clean up your input: 'D#.456789 - 1 foo bar' to 'D 456789 1 foo far'
$clean = trim(preg_replace('/\W+/', ' ', $input));
// Take first 3 words.
list($status, $loadId1, $loadId2) = explode(' ', $clean);
// Glue back your load ID to '456789-1'
$loadId = $loadId1 . '-' . $loadId2;
return compact('status', 'loadId');
}
Example:
$inputs = array(
'P#123456-3',
'#D 456789-1',
'D# 456789 - 1',
'D#.456789-1 This load looks wet to me do weneed to cancelthis order',
);
echo '<pre>';
foreach ($inputs as $s) {
print_r(parse($s));
}
Output:
Array
(
[status] => P
[loadId] => 123456-3
)
Array
(
[status] => D
[loadId] => 456789-1
)
Array
(
[status] => D
[loadId] => 456789-1
)
Array
(
[status] => D
[loadId] => 456789-1
)
First, remove stuff that shouldn't be there:
$str = preg_replace('/[^PDL\d-]/i', '', $str);
That gives you the following normalised results:
D456789-1
D456789-1
D456789-1ldlddld
Then, attempt to match the data you want:
if (preg_match('/^([PDL])(\d+-\d)/i', $str, $match)) {
$code = $match[1];
$load = $match[2];
} else {
// uh oh, something wrong with the format!
}
Something like
/^[#\s]*([PDL])[#\s]*(\d+[\s-]+\d)/
or to be even more relaxed,
/^[^\d]*([PDL])[^\d]*(\d+)[^\d]+(\d)/
would get you what you want. But I'd prefer HamZa's comment as a solution: throw it back and tell them to get their act together :)

post an array and iterate throught it in PHP codeigniter

This is the first time i create my own webservice (someone always did it for me before), so please bear with me.
I post this array :
$data = array(
'user_id' => $this->post('user_id'),
'group_id' => $this->post('group_id'),
'child_id' => $this->post('child_id'), //will be nested array
'custom' => $this->post('custom'),
'time' => $this->post('time'),
'date' => $this->post('date')
);
I tried to create a nested array with this : $this->post('child_id'), because user can post multiple child_id at once.
Then i tried to iterate through the child_id, because i need to insert them to the mysql :
for($i = 0; $i < sizeof($data['child_id']); $i++)
{
$result2 = $this->schedule_m->add_trans('transaction_schedule', $data, $result_id[0]['id']);
}
What should i do, so i can have an array of child_id in my $data array? (nested array)
And how to iterate through it?
UPDATE :
I have updated the codes above.
I use advanced rest client for testing, and i tried to post something like this in the form content type :
child_id=1&user_id=1&group_id=1&custom=&time=17%3A17%3A00&date=&child_id=2
Notice that theres two child_id (left most and right most), but only the last one (right most) is inserted.
And this is the add_trans in the model :
function add_trans($table, $data, $schedule_id) {
$query = $this->db->insert($table, array('child_id' => $data['child_id'], 'schedule_id' => $schedule_id));
return $query;
}
Thanks a lot for your time.
Even thought you set the name attribute as child[] on the markup,
You still need to call it as:
'child_id' => $this->post('child_id')
It will still return an array.
for($i = 0; $i < sizeof($data['child_id']); $i++) {
$result2 = $this->schedule_m->add_trans('transaction_schedule', $data, $result_id[0]['id']);
}
EDIT:
Looking upon you query string, that seems to be the culprit:
child_id=1&user_id=1&group_id=1&custom=&time=17%3A17%3A00&date=&child_id=2
^ same index , same index, same index, it will overwrite and you will get only `2`
If you want to get them all into an array format, you need to set them like this
child_id[]=1&user_id=1&group_id=1&custom=&time=17%3A17%3A00&date=&child_id[]=2
^ it needs to be set like this
UPDATE:
And in your model, if you want each id per row, well you can also loop in this case:
function add_trans($table, $data, $schedule_id) {
foreach($data['child_id'] as $child_id) {
$query = $this->db->insert($table, array('child_id' => $child_id, 'schedule_id' => $schedule_id));
}
// return $this->db->insert_id();
return $query;
}
ofcourse that won't work, it has to be
for($i = 0; $i < sizeof($data['child_id']); $i++)
{
$result2 = $this->schedule_m->add_trans('transaction_schedule', $data['child_id'][$i], $result_id[0]['id']);
}
because you've not set $data['child_id[]'] so it doesn't exist, the key is just a string or number, it does not validate or parse anything
you don't need to give child[] in post method. just give only child, it will get complete array what are you sending from views
replace
'child_id' => $this->post('child_id[]')
with
'child_id' => $this->post('child_id')

Indented list to multidimensional array

I was surprised not to find an answer to this on SO (or elsewhere on the internet for that matter). It concerns a nested indented list which I want to convert into a multidimensional array according to the level of indentation.
By way of an example, here is some sample input:
Home
Products
Product 1
Product 1 Images
Product 2
Product 2 Images
Where to Buy
About Us
Meet the Team
Careers
Contact Us
Ideally I'd like to feed this into some (recursive?) function and get the following output:
array(
'Home' => array(),
'Products' => array(
'Product 1' => array(
'Product 1 Images' => array(),
),
'Product 2' => array(
'Product 2 Images' => array(),
),
'Where to Buy' => array(),
),
'About Us' => array(
'Meet the Team' => array(),
'Careers' => array(),
),
'Contact Us' => array(),
);
I'm confused by the logic required to perform such a task, so any help would be appreciated.
As it's still unclear if you're trying to read from some given structure (html-dom) or from the given string as plain text, I assumed it's the string you're trying to parse. If so, try:
<?php
$list =
'Home
Products
Product 1
Product 1 Images
Product 2
Product 2 Images
Where to Buy
About Us
Meet the Team
Careers
Contact Us';
function helper($list, $indentation = ' ') {
$result = array();
$path = array();
foreach (explode("\n", $list) as $line) {
// get depth and label
$depth = 0;
while (substr($line, 0, strlen($indentation)) === $indentation) {
$depth += 1;
$line = substr($line, strlen($indentation));
}
// truncate path if needed
while ($depth < sizeof($path)) {
array_pop($path);
}
// keep label (at depth)
$path[$depth] = $line;
// traverse path and add label to result
$parent =& $result;
foreach ($path as $depth => $key) {
if (!isset($parent[$key])) {
$parent[$line] = array();
break;
}
$parent =& $parent[$key];
}
}
// return
return $result;
}
print_r(helper($list));
Demo: http://codepad.org/zgfHvkBV
I'm not going to write the recursive function, but to point you in a helpful direction, take a look at PHP's substr_count function. Based on this, you could count the number of tabs in front of each line and compare it with the number of tabs in the previous line to figure out if it's a child, sibling, etc.
Am I the only one with a beautiful mind seeing the pattern?
The input array is almost the same thing!, with the lines ending in only 3 possible ways: opening, whole, or closing parentheses.
$L = 4;//estimate depth level
function tabbed_text_to_array ($raw, $L) {
$raw = preg_replace("/^(\\t*)([^\\t\\n]*)\\n?/m" , "\t$1'$2' => array(\n" , $raw );
for( ; $L > 0 ; $L-- ) {
for( $i=0; $i<3 ;$i++ ) {
$preL = $L-1;
$s = array( "^(\\t{{$L}})([^\\t\\),]*)(?=\\n\\t{{$L}}')", "^(\\t{{$L}})([^\\t\\),]*)(?=\\n(\\t{0,{$preL}})')", "^(\\t{{$L}})(\\),)(?=\\n(\\t{{$preL}})[^\t])" );
$r = array( "$1$2)," , "$1$2)\n" . str_repeat("\t",$preL) . ")," , "$1),\n$3)," );
$raw = preg_replace( "/$s[$i]/m" , $r[$i], $raw );
}
}
return "array(\n". $raw. ")\n);";
}
This function generates a string with a literal array. Then you just eval() it.
It's not as bad as it looks. The double backslashes makes the reading harder, but it's simple.
Like cell reproduction, it first adds in one pass the most common things: the quotation marks, commas and opening parentheses, and then it adds the smaller details in two more passes. All of them run once for each level you specify (You could waste code in finding out the deepest level to start processing from, but a guess is enough.)
See the working demo / tool to convert tab-indented text into array
Or visit a php fiddle with all the passes, so you can expand on this.
There is a class on PHP Scripts that will do what you need. You can find it here:
Array To List
It takes a multidimensional array and creates the HTML.
Updated
The opposite to this was actually required. To do this, it's probably best to use a DOMDocument object and load the HTML into a object representation.
http://php.net/manual/en/domdocument.loadhtml.php

Categories