PHPExcel conditionally formatting a range with a formula - php

I have the following code:
$vOffset = 2;
$offset = 6;
$formatRows = 100;
$formatColumns = 100;
//set conditional formatting in place
for($row=$vOffset;$i<$formatRows;$row++){
for($col=$offset+1;$col<$formatColumns;$col+3){
//prepare conditional styles
//if verbal is bigger
$conditionalStyle_RED = new PHPExcel\Style_Conditional();
$conditionalStyle_RED->setConditionType(PHPExcel\Style_Conditional::CONDITION_CELLIS);
$conditionalStyle_RED->addCondition(
"=" . $this->coordinates($col, $row) . " > " . $this->coordinates($col+1,$row)
);
$conditionalStyle_RED->getStyle()->getFont()->getColor()->setARGB(PHPExcel\Style_Color::COLOR_RED);
array_push($conditionalStyles, $conditionalStyle_RED);
$this->getActiveSheet()
->getStyle($this->coordinates($col, $row) . ':' . $this->coordinates($col+1, $row))
->setConditionalStyles($conditionalStyles);
}
}
Where I attempt to set a conditional style with the formula akin to:
=A1 > A3
It isn't yet working. Anyone know how to accomplish this?

Quite a late response, but I have been looking through the internet for a similar issue. Eventually I solved it. Incase people in the future might come across this problem I will note down a few things.
I have been struggling with the same kind of issue and I managed to solve it. What you want is to insert a formula into the conditional formatting. This sounds trickier than it actually is.
For your specific piece of code this should most likely work.
$vOffset = 2;
$offset = 6;
$formatRows = 100;
$formatColumns = 100;
//set conditional formatting in place
for($row=$vOffset;$i<$formatRows;$row++){
for($col=$offset+1;$col<$formatColumns;$col+3){
//prepare conditional styles
//if verbal is bigger
$conditionalStyle_RED = new PHPExcel\Style_Conditional();
$conditionalStyle_RED->setConditionType(PHPExcel\Style_Conditional::CONDITION_EXPRESSION);
$conditionalStyle_RED->setConditions(array("(" . $this->coordinates($col, $row) . " > " . $this->coordinates($col+1,$row) . ")"));
$conditionalStyle_RED->getStyle()->getFont()->getColor()->setARGB(PHPExcel\Style_Color::COLOR_RED);
array_push($conditionalStyles, $conditionalStyle_RED);
$this->getActiveSheet()
->getStyle($this->coordinates($col, $row) . ':' . $this->coordinates($col+1, $row))
->setConditionalStyles($conditionalStyles);
}
}
The "condition_expression" is used in order to place a formula inside a conditional format. As far as I was able to figure out the only way to implement a formula is by using the "setConditions". With this you can give an array of strings, with each string being a formula.
In your code this would result in the color of red when the first coordinate is bigger than the second one.
Now back to your code, I haven't tested it so you might want to tweak a few values, but this should at least push you towards the right direction. Good luck mate!

Related

How to make Behat look for occurences of a specific text?

I'd like to create a function that makes Behat parse my HTML and tell me how many times he finds a specific text. I found countless ways to do so, but since I'd like to reuse the concept, I can't give him a specific div class where to find it since it could be outside of a div.
This is what I did so far
testfeature.feature
And I should see "CISIA - Arcueil" 2 times
FeatureContext.php
public function iShouldSeeTimes($text, $count) {
$element = $this->getSession()->getPage();
$result = $element->findAll('css', sprintf('div:contains("%s")', $text));
if(count($result) == $count && strpos(reset($result)->getText(), $text)) {
return;
}
else {
throw new ExpectationException('"' . $text . '" was supposed to appear ' . $count . ' times, got ' . count($result) . ' instead', $this->getSession());
}
}
This is a bit messy but I'll tidy all of this up once it works. So far, with this code, I get 19 elements, which are every text contained by every div inside the page I want to check. In a way, I have a possibility to get to my goal, but what I'd like is to directly get what I need (my two occurences) inside $result. However, it looks like I'm doing something wrong with the sprintf() function.
Is there a way to make Behat look for a specific text?
Thank you in advance
Use XPath that matches any type of element with contains instead of css.
For example:
$text = 'my text';
findAll('xpath', "//*[contains(text(), '$text')]");
The second alternative would be to use regular expressions. I recommend the first one.

Possible to overide a foreach variable parameter within itself?

I have made a small script which uses the Twitch API. The API only allows a maximum of 100 results per query. I would like to have this query carry on until there are no more results.
My theory behind this, is to run a foreach or while loop and increment the offset by 1 each time.
My problem however, is that I cannot change the foreach parameters within itself.
Is there anyway of executing this efficiently without causing an infinite loop?
Here is my current code:
<?php
$newcurrentFollower = 0;
$offset=0;
$i = 100;
$json = json_decode(file_get_contents("https://api.twitch.tv/kraken/channels/greatbritishbg/follows?limit=25&offset=".$offset));
foreach ($json->follows as $follow)
{
echo $follow->user->name . ' (' . $newcurrentFollower . ')' . "<br>";
$newcurrentFollower++;
$offset++;
$json = json_decode(file_get_contents("https://api.twitch.tv/kraken/channels/greatbritishbg/follows?limit=25&offset=".$offset));
}
?>
Using a While loop:
while($i < $total)
{
$json = json_decode(file_get_contents("https://api.twitch.tv/kraken/channels/greatbritishbg/follows?limit=25&offset=".$offset));
echo $json->follows->user->name . ' (' . $newcurrentFollower . ')' . "<br>";
$newcurrentFollower++;
$offset++;
$i++;
}
Ends up echoing this (No names are successfully being grabbed):
Here is the API part for $json->follows:
https://github.com/justintv/Twitch-API/blob/master/v2_resources/channels.md#get-channelschannelfollows
You can use this:
$offset = 0;
$count = 1;
do {
$response = json_decode(file_get_contents(
'https://api.twitch.tv/kraken/channels/greatbritishbg/follows?limit=100&offset=' . $offset
));
foreach($response->follows as $follow) {
echo $follow->user->name . ' (' . ($count++) . ')' . "</br>";
}
$offset+=25;
} while (!empty($response->follows));
You want to use a while loop here, not just a foreach. Basically:
while (the HTTP request returns results)
{
foreach ($json->follows as $follow)
{
do stuff
}
increment offset so the next request returns the next one not already processed
}
The trickiest part is going to be getting the while condition right so that it returns false when the request gets no more results, and will depend on what the API actually returns if there are no more results.
Also important, the cleanest way would be to have the HTTP request occur as part of the while condition, but if you need to do some complicated computation of the JSON return to check the condition, you can put an initial HTTP request before the loop, and then do another request at the end of each while loop iteration.
The problem is you're only capturing the key not the value. Place it into a datastructure to access the information.
Honestly I find a recursive function much more effective than a iterative/loop approach then just update a datatable or list before the next call. It's simple, uses cursors, lightweight and does the job. Reusable if you use generics on it too.
This code will be in c#, however I know with minor changes you'll be able to get it working in php with ease.
query = //follower object get request//
private void doProcessFollowers(string query)
{
HTTPParse followerData = new HTTPParse(); //custom json wrapper. using the basic is fine. Careful with your cons though
var newRoot = followerData.createFollowersRoot(query); // generates a class populated by json
if (newRoot[0]._cursor != null)
{
populateUserDataTable(newRoot); //update dataset
doProcessFollowers(newRoot[0]._links.next); //recurse
}
}
Anyway - This just allows you to roll through the cursors without needing to worry about indexes - unless you specifically want them for whatever reason. If you're working with generics you can just reuse this code without issue. Find a generic example below. All you need to do to make it reuseable is pass the correct class within the <> of the method call. Can work for any custom class that you use to parse json data with. Which is basically what the 'createfollowerroot()' is in the above code, except that's hard typed.
Also I know it's in c# and the topic is php, with a few minor changes to syntax you'll get it working easily.
Anyway Hope this helped somebody
Generic example:
public static List<T> rootSerialize<T>(JsonTextReader reader)
{
List<T> outputData = new List<T>();
while (reader.Read())
{
JsonSerializer serializer = new JsonSerializer();
var tempData = serializer.Deserialize<T>(reader);
outputData.Add(tempData);
}
return outputData;
}

Iterating variables in PHP not working

I've done hours of research on this now, so I believe I'm not repeating, even though this seems like it would have a simple solution.
I have an HTML form sending values to PHP, where it takes the value, and sets them all to a variable. When I submit the values and load the PHP, it completely breaks as if there is a syntax problem, but I can't find anything obvious.
I'm setting the variables from POST like so:
$ital1=$_POST['checkbox1'];
$bold1=$_POST['checkbox2'];
$ital2=$_POST['checkbox3'];
$bold2=$_POST['checkbox4'];
I'm then using these variables with simplexml to write to an xml document for databasing. Here's a snippet of that:
$xml = simplexml_load_file('settings.xml');
function loops()
{
$italvar = (eval('return $' . "ital{$string}"));
$boldvar = (eval('return $' . "bold{$string}"));
$alertvar = (eval('return $' . "alerttitle{$string}"));
$pagevar = (eval('return $' . "page{$string}n"));
$colorvar = (eval('return $' . "colorset{$string}"));
$string = strval($i);
for($i=1; $i<21; $i++)
{
if($xml->settings->checkbox->"ital{$string}" == $empty && $italvar == "on")//ITAL1
{
$xml->settings->checkbox->"ital{$string}" = $italvar;
}
else if($italvar == $empty && $xml->settings->checkbox->"ital{$string}" == "on")
{
$xml->settings->checkbox->"ital{$string}" = $empty;
}
else
{
continue;
}
}
$xml->asXML('settings.xml');
This is just a piece of the function, but the rest is basically this repeated for different types of variables. I know the issue is within the loops function as when I delete loops(), the PHP at least loads some echos at the top of the doc.
I'm not sure what in here is breaking. I'm guessing it's the syntax with how I'm combining and iterating variables, which explains the title.
So my questions is this. How do I combine strings and variables correctly?
$italvar = (eval('return $' . "ital{$string}"));
$string = strval($i);
In this instance I want the end result to be $ital#, # being the current iteration of the forloop, so I can correctly write to xml the value of the set variable from $_POST as shown at the top.
"ital{$string}"
$string = strval($i);
And here I just want it to be a string such as ital1, then ital2, as that's what the nodes are called in the xml. I'm sure what I'm doing wrong is very obvious, but I'm very new to PHP and I can't seem to figure it out. Thank you very much in advance for any input!
You have a $_POST array. Use it.
for( $i=1; $i<=20; $i++) {
$ital = $_POST['checkbox'.($i*2-1)];
$bold = $_POST['checkbox'.($i*2)];
// now do stuff with `$bold` and `$italic`
}

How To Stop Duplicates Being Listed On PHP Results?

I've made up a PHP script which assigns a score to listings on a website and assigns it to the results page. I have got it to work in that it shows the score and the details but it keeps listing the same results over and over.
I can't work out what it is doing but there is a small section of code I was hoping would prevent duplicate listings. Could anyone give it a tweak and see if I am going wring somewhere?
The Code is:
$dupCatch .= $adId.",";
$dupResults = explode(',', $dupCatch);
foreach($dupResults as $dupResult){
if($dupResult == $adId){
print "";
} else {
print $showResults;
$scoreBox = 'THIS IS THE SCORE: ' . $finalScore . '';
print $scoreBox;
}
}
Thanks in advance!
Jack
The problem is that you add your current $adId to the duplicate list before you check if it is there - which it will always be, of course.
Storing a bunch of numbers in a string, explodeing it every time, is a little weird, use an array instead. You also don't need to manually loop through all the items, just use in_array()
if( !in_array($adId, $dupCatch) ){
print $showResults;
$scoreBox = 'THIS IS THE SCORE: ' . $finalScore . '';
print $scoreBox;
}
$dupCatch[] = $adId;
Needless to say: it would be a better idea to fix the part that gives you the duplicate results in the first place.
You can either try to use array_unique from php side or use unique attribute at field in mysql this way duplicates can be prevent before even inserting them.

Latency problem on FF and safari and IE

so i've build a function to scan a dir based on a $_GET var, the code:
$dir="img/".$_GET["gal"];
$a=scandir($dir);
$b=array_slice($a,2);
for($i=1,$j=1;$i,$j<=count($b);$i++,$j++){
$marginRight=($i==6||$i==12||$i==18||$i==24||$i==30||$i==36)?"margin-right: 0":"margin-right: 13px";
if($i<10 && $j<10)
echo '<div class="GalThumbs" style="'.$marginRight.'"><img src="'.$dir.'/'.$_GET["gal"].'-0'.$i.'.jpg"/></div>';
else{
echo '<div class="GalThumbs" style="'.$marginRight.'"><img src="'.$dir.'/'.$_GET["gal"].'-'.$i.'.jpg"/></div>';
}
/* if($i==11)
break; */
}
if there are more than ten images to scan a latency occurs(redraw of the browser slowish)
i discover this using the commented:
if($i==11)
break;
if it's :
if($i==10)
break;
there will be no latency. don't understand what's going on here..
Let's take a look at your code, I think you are somehow lost in all that code and what it does. With a little bit of clean-up you should be able to debug your latency issue far easier.
Let's start with the for-loop:
for($i=1,$j=1;$i,$j<=count($b);$i++,$j++)
Both iterator variables are set in parallel. I'm sure you have thought about something when you wrote it, but this makes no sense. Try to reduce problems if you're unsure how to go on.
One variable does the job. Same here:
if($i<10 && $j<10)
And then I stumbled over this:
$marginRight=($i==6||$i==12||$i==18||$i==24||$i==30||$i==36)?"margin-right: 0":"margin-right: 13px";
You are actually looking for modulo: Get the remainder of $i divided by 6.
The if/else blocks both contain the same code. There is no need to use it at all.
Then I assume for debugging you want to quit the for-loop with break.
Next to that your code can benefit from indentation.
And the directory is actually only read to get the number of files, so the code can be reduced to get the count of files.
Let's try:
$gal = $_GET["gal"]; // FIXME sanitize the input
$dir = sprintf('img/%s', $gal);
$max = count(scandir($dir))-2;
for($i=1; $i<=$max; $i++)
{
$marginRight = ($i % 6 ? '13px' : '0');
$style = sprintf('margin-right: %s', $marginRight);
$src = sprintf('%s/%s-0%d.jpg', $dir, $gal, $i);
echo '<div class="GalThumbs" style="', htmlspecialchars($style), '">',
'<a href="', htmlspecialchars($src), '" rel="example3">',
'<img src="', htmlspecialchars($src),'"/>',
'</a>',
'</div>'
;
// FIXME debug
/* if($i==11) break; */
}

Categories