I am using a php session-based flash messenger available here. The issue is sometimes I get multiple messages of the same type when I generate errors, display messages, so on and so fourth. This is mostly due to some AJAX issues. Assuming that I wanted to only apply a fix in the display code here:
public function display($type = 'all', $print = true)
{
$messages = '';
$data = '';
if (!isset($_SESSION['flash_messages'])) {
return false;
}
// print a certain type of message?
if (in_array($type, $this->msgTypes)) {
foreach ($_SESSION['flash_messages'][$type] as $msg) {
$messages .= $this->msgBefore . $msg . $this->msgAfter;
}
$data .= sprintf($this->msgWrapper, $this->msgClass, $this->msgClassPrepend.'-'.$type, str_replace('messages', 'autoclose',$this->msgClassPrepend.'-'.$type), $messages);
// clear the viewed messages
$this->clear($type);
// print ALL queued messages
} elseif ($type == 'all') {
$counter = 1;
foreach ($_SESSION['flash_messages'] as $type => $msgArray) {
$count = $counter++;
$messages = '';
foreach ($msgArray as $msg) {
$messages .= $this->msgBefore . $msg . $this->msgAfter;
}
$data .= sprintf($this->msgWrapper, $this->msgClass, $this->msgClassPrepend.'-'.$type, str_replace('messages', 'autoclose', $this->msgClassPrepend.'-'.$type), $messages);
}
// clear ALL of the messages
$this->clear();
// invalid message type?
} else {
return false;
}
// print everything to the screen or return the data
if ($print) {
echo $data;
} else {
return $data;
}
}
How would I make it so that duplicate messages are detected on a 1 for 1 basis. So if the message is "Hello" and "Hello" and "Hello." I can remove one of the first two, and keep the later as it is a different message so to speak. All the workarounds I can think of would be overly complex, and I was wondering if anyone could think of a simple solution.
Additional info: display is encased in class Messages and a new message is created with
$msg = new Messages();
$msg->add('e', 'Some error here.');
You could simply run the message array through array_unique() before the $messages string is built. For example, these two additions to the display method should do the trick...
if (in_array($type, $this->msgTypes)) {
$filtered = array_unique($_SESSION['flash_messages'][$type]);
foreach ($filtered as $msg) {
and...
foreach ($_SESSION['flash_messages'] as $type => $msgArray) {
$count = $counter++;
$messages = '';
$filtered = array_unique($msgArray);
foreach ($filtered as $msg) {
Alternatively, you could override the add method with a unique check. For example
public function add($type, $message, $redirect_to = null, $ignoreDuplicates = true) {
// snip...
// wrap the array push in this check
if (!($ignoreDuplicates && in_array($message, $_SESSION['flash_messages'][$type]))) {
$_SESSION['flash_messages'][$type][] = $message; // this is the existing code
}
// snip...
}
Related
I have regular use cases of PHP \Exception sub classes where I want to collect up data and then bundle it into a final error message. For example:
checking some data has contiguous days
$missing = new MissingAdjustmentDataException('');
$testDate = $period->getPreviousPeriod()->getEnd();
$z = 0;
while ($testDate <= $period->getEnd() && $z < 500){
if (!in_array($testDate, array_column($activationRedemptionAdjustmentDays, 'effective') )){
$missing->addMissingRedemptionAdjustment($testDate);
}
if (!in_array($testDate, array_column($platformAdjustmentDays, 'effective') )){
$missing->addMissingPlatformAdjustment($testDate);
}
$testDate->add(new \DateInterval('P1D'));
$z++;
}
Then in my exception, I'm collecting the data in arrays:
class MissingAdjustmentDataException extends \Exception
{
private $missingRedemptionAdjustment = [];
private $missingPlatformAdjustment = [];
public function updateMessage()
{
$message = 'Missing Adjustment data: ';
if ($this->missingRedemptionAdjustment){
$ra = [];
foreach ($this->missingRedemptionAdjustment as $item){
$ra[] = $item->format('Y-m-d');
}
$message .= 'RedemptionAdjustment: '.implode(',',$ra);
}
if ($this->missingPlatformAdjustment){
$pl = [];
foreach ($this->missingRedemptionAdjustment as $item){
$pl[] = $item->format('Y-m-d');
}
$message .= 'PlatformAdjustment: '.implode(',',$pl);
}
$this->message = $message;
}
public function inError() : bool
{
if ($this->missingRedemptionAdjustment || $this->missingPlatformAdjustment){
return true;
}else{
return false;
}
}
public function addMissingRedemptionAdjustment(\DateTime $dateTime){
$this->missingRedemptionAdjustment[] = clone $dateTime;
$this->updateMessage();
}
public function addMissingPlatformAdjustment(\DateTime $dateTime){
$this->missingPlatformAdjustment[] = clone $dateTime;
$this->updateMessage();
}
}
My main problem is that I cannot find a way to do the formatting of the message in a "lazy" way when $missing->getMessage() is called. It seems to have update $this->message inside the Exception every time I add a data point to the exception.
Is there a better way to do this?
The issue is that you are mixing two different things: the object that keeps track of the errors, and the exception.
You should properly seperate them. For example:
class MissingDataCollector
{
private $missingRedemptionAdjustment = [];
private $missingPlatformAdjustment = [];
public function addMissingRedemptionAdjustment(\DateTime $dateTime)
{
$this->missingRedemptionAdjustment[] = clone $dateTime;
}
public function addMissingPlatformAdjustment(\DateTime $dateTime)
{
$this->missingPlatformAdjustment[] = clone $dateTime;
}
public function check()
{
if ($this->missingRedemptionAdjustment || $this->missingPlatformAdjustment)
throw new \Exception($this->getMessage());
}
private function getMessage()
{
$message = 'Missing Adjustment data:';
if ($this->missingRedemptionAdjustment){
$ra = [];
foreach ($this->missingRedemptionAdjustment as $item){
$ra[] = $item->format('Y-m-d');
}
$message .= ' RedemptionAdjustment: '.implode(',', $ra);
}
if ($this->missingPlatformAdjustment){
$pl = [];
foreach ($this->missingRedemptionAdjustment as $item){
$pl[] = $item->format('Y-m-d');
}
$message .= ' PlatformAdjustment: '.implode(',', $pl);
}
return $message;
}
}
And the way to use it:
$missing = new MissingDataCollector();
// Some processing that may call addMissingRedemptionAdjustment() or addMissingPlatformAdjustment()
...
// Throw an exception in case of missing data
$missing->check();
You can execute updateMessage() while catching the exception
catch(MissingAdjustmentDataException $e) {
$e->updateMessage();
echo $e->getMessage();
}
You will find some advices and hacks in How to change exception message of Exception object?
below there's a code that I use very often on my website (it's a MyBB forum) and there's a specific web page where I have written it 10+ times.
To make code easier to read I decided to turn it into a function and call it with different arguments each time. Unfortunately it isn't working, for some reason I keep getting the $fail code while without the function I get $success.
It's the first time I use PHP functions but from what I read at w3schools I should be doing good, theoretically. Not much when coming to practice. Mind checking my syntax and tell me if it is wrong?
<?php
//function code
function canviewcheck($allowedgroups)
{
$groups = $mybb->user['usergroup'];
if ($mybb->user['additionalgroups']) {
$groups .= "," . $mybb->user['additionalgroups'];
}
$explodedgroups = explode(",", $groups);
$canview = 0;
foreach ($explodedgroups as $group) {
if (in_array($group, $allowedgroups)) {
$canview = 1;
echo $success;
break;
}
}
if (!$canview) {
echo $fail;
}
}
//Parameters that I want to use
$allowedgroups = [4, 19];
$pid = 'URL';
$success = "<a href=URL><span style='color:green; font-size:20px;'>SUCCESS</span></a>";
$fail = "<span style='color:#DE1603; font-size:20px;'>FAIL</span>;";
//Call to function
canviewcheck($allowedgroups, $pid, $success, $fail);
You need to add all the necessary parameters to the function, and $mybb also needs to be passed as an argument.
$pid isn't used in the function, so you don't need to pass that as an argument.
<?php
//function code
function canviewcheck($allowedgroups, $success, $fail, $mybb)
{
$groups = $mybb->user['usergroup'];
if ($mybb->user['additionalgroups']) {
$groups .= "," . $mybb->user['additionalgroups'];
}
$explodedgroups = explode(",", $groups);
$canview = 0;
foreach ($explodedgroups as $group) {
if (in_array($group, $allowedgroups)) {
$canview = 1;
echo $success;
break;
}
}
if (!$canview) {
echo $fail;
}
}
//Parameters that I want to use
$allowedgroups = [4, 19];
$pid = 'URL';
$success = "<a href=URL><span style='color:green; font-size:20px;'>SUCCESS</span></a>";
$fail = "<span style='color:#DE1603; font-size:20px;'>FAIL</span>;";
//Call to function
canviewcheck($allowedgroups, $success, $fail, $mybb);
I am modifying some code i had written for my by a developer who is no longer working with us, essentially the code pulls data from a web service and parses to an array, it then looks for keys within the array and publishes associated values to an HTML table, it all works fine when each of the entries exists in the data however the point of modifying the code if to return a generic value ("not submitted") if the value is not found in the array.
background info is helpful so the use case is:
Array is made up of the sales team, they each login to a website and submit their sales totals for the day, we interrogate the web service to return the data via a SOAP call which pulls the data into the code. The data is parsed and the values are represented in a table on a web page.
If a single sales team member does not submit data then the code fails to return any data.
I've been googling and hitting my pluralsight account to learn as much as i can about how this is done but i'm falling short.
class SalesResponseFactory
{
private $date;
//private $keyArray = ['KE', 'JY', 'OR', 'KR', 'SY', 'DB'];
public $responseData = [];
function __construct($date)
{
libxml_use_internal_errors(true);
$this->date = $date;
}
private function getResponseData($date)
{
....
}
private function parserToArray($data)
{
$data = substr($data, strpos($data, "<DataResult>"));
$data = substr($data, 0, strpos($data, "</DataResult>") + strlen("</DataResult>"));
$xml = simplexml_load_string($data);
if ($xml === false) {
throw new Exception("Invalid user credentials.");
}
$json = json_encode($xml);
$array = json_decode($json,TRUE);
if (empty($array['Results'])) {
throw new Exception("Holiday - No Sales Data Recorded");
}
return $array['Results']['Data'];
}
private function alignmentArray($sales)
{
if ($sales['Name'] == 'Market Code' || $sales['Name'] == 'Sales Volume' || $sales['Name'] == 'Turnover Volume' || $sales['Name'] == 'Date') {
if($sales['Name'] == 'Market Code') {
$this->responseData[$sales['Instrument']]['Market Code'] = $sales['Value'];
}
if($sales['Name'] == 'Sales Volume') {
$this->responseData[$sales['Instrument']]['Sales Volume'] = $sales['Value'];
}
if($sales['Name'] == 'Turnover Volume') {
$this->responseData[$sales['Instrument']]['Turnover Volume'] = $sales['Value'];
}
else {
$this->responseData[$sales['Instrument']]['Date'] = $sales['Value'];
}
}
}
public function parser()
{
try {
$salesArray = $this->getResponseData($this->date);
} catch (Exception $e) {
$response['status'] = 'error';
$response['message'] = $e->getMessage();
$response['results'] = '';
return json_encode($response);
}
foreach ($salesArray as $sales) {
$this->alignmentArray($sales);
}
$response['status'] = 'ok';
$response['message'] = 'success';
$response['results'] = [];
foreach ($this->responseData as $row) {
array_push($response['results'], $row);
}
return json_encode($response);
}
}
?>
i'd expect that null values should still be output but whats actually happening is that no data is being returned to the HTML table.
I have a function inside a class, and I would like to get the result of this function, something like:
Returned dangerous functions are: dl, system
Here is my code
public final function filterFile(){
$disabled_functions = ini_get('disable_functions');
$disFunctionsNoSpace = str_replace(' ', '', $disabled_functions);
$disFunctions = explode(',', $disFunctionsNoSpace);
$this->disFunctions = $disFunctions;
// get file content of the uploaded file (renamed NOT the temporary)
$cFile = file_get_contents($this->fileDestination, FILE_USE_INCLUDE_PATH);
$found = array();
foreach($this->disFunctions as $kkeys => $vvals)
{
if(preg_match('#'.$vvals.'#i', $cFile))
{
array_push($found, $vvals);
}
} // end foreach
} // end filterFile
// calling the class
$up = new uploadFiles($filename);
$fileterringFile = $up->filterFile();
print_r($fileterringFile);
var_dump($fileterringFile);
EDIT: add 2 functions for errors:
// check if any uErrors
public final function checkErrors(){
$countuErrors = count($this->uErrors);
if((IsSet($this->uErrors) && (is_array($this->uErrors) && ($countuErrors > 0))))
{
return true;
}
return false;
} // end checkErrors()
// print user errors
public final function printErrors(){
$countuErrors = count($this->uErrors);
if((IsSet($this->uErrors) && (is_array($this->uErrors) && ($countuErrors > 0))))
{
echo '<ul>';
foreach($this->uErrors as $uV)
{
echo '<li>';
echo $uV;
echo '</li>';
}
echo '</ul>';
}
} // end printErrors()
Thanks in advance
at the end of end filterFile, add:
return 'Returned dangerous functions are: '.implode(',',$found);
I'm using Laravel 4 for a project, but got an issue. I'm not sure, what i'm doing wrong.
Details:
Form is posted to the controller's save function.
When validation fails, i'm redirecting to the create function
After redirect (using Redirect::to(somewhere)->withErrors($validator)->withInput()):
Validation errors are being displayed correctly (if any)
Input::old() is empty (it should contain previously submitted data)
Create function in controller
public function create()
{
$this->scripts[] = 'various js path here';
return View::make('admin.modules.events.create', array(
// Loading various scripts specified in this function
'scripts' => $this->scripts,
));
}
In the view:
...
{{ Form::bsInput('event_name', 'Event title', 'event title goes here', $error = (($errors->has('event_name')) ? $errors->get('event_name') : false), $type = 'text', Input::old('event_name')) }}
...
Note: bsInput is a wrapper around Form::Input() to create bootstrap controls together with labels
Controller:
public function save()
{
if (Input::has('submitEventSave'))
{
$event = Mihirevent::find(Input::get(event_id));
$event_add = false;
}
else
{
$event = new Mihirevent();
$event_add = true;
}
if ($event === false)
{
// doing something else
}
else
{
$event->event_name = Input::get('event_name');
$event->event_slug = Input::get('event_slug');
$event->event_description = Input::get('event_description');
$event->event_location_text = Input::get('event_location_text');
$event->event_location_data = Input::get('event_location_data');
$event->event_status = Input::get('event_status');
$event->featured_image = Input::get('featured_image');
$event->event_date_from = Input::get('event_date_from');
$event->event_date_until = Input::get('event_date_until');
$validation_rules = $event_add === true?$event->rules:$event->update_rules;
$inputs = array(
'event_name' => $event->event_name,
'event_slug' => $event->event_slug,
'event_location_text' => $event->event_location_text,
);
$validator = Validator::make($inputs, $validation_rules);
if ($validator->fails())
{
Input::flash();
if ($event_add === true)
{
return Redirect::to('admin/event/create')
->withErrors($validator)->withInput();
}
else
{
return Redirect::to('admin/event/edit/'.$event->event_id)
->withErrors($validator)->withInput();
}
}
// save
MihirEvent::save();
// redirect to list
return Redirect::route('adminEvent');
}
}
Update:
bsInput macro:
Form::macro('bsInput', function($name, $text, $placeholder = null, $error = false, $type = 'text', $default = null, $class=null)
{
$label = Form::label($name, $text, array('class' => 'control-label'));
$input = Form::input($type, $name, $default, array('placeholder' => $placeholder, 'class' => 'form-control'.($class?' '.$class:'')));
$error_messages = false;
if($error)
{
$error_messages = '<ol>';
foreach ($error as $value) {
$error_messages .= '<li>'.$value.'</li>';
}
$error_messages .= '</ol>';
}
$html = '<div class="form-group'.(($error) ? ' has-error' : '').'">';
$html .= $label;
$html .= $input;
$html .= (($error_messages) ? '<div class="alert alert-danger">'.$error_messages.'</div>' : '');
$html .= '</div>';
return $html;
});
Looking at the Laravel 4 source:
/**
* Flash an array of input to the session.
*
* #param array $input
* #return \Illuminate\Http\RedirectResponse
*/
public function withInput(array $input = null)
{
$input = $input ?: $this->request->input();
$this->session->flashInput($input);
return $this;
}
It looks like if you don't pass an array of Input with ->withInput it tries to pull it from the original request. Try modifying the line like so:
if ($event_add === true)
{
return Redirect::to('admin/event/create')
->withErrors($validator)->withInput(Input::all());
}
else
{
return Redirect::to('admin/event/edit/'.$event->event_id)
->withErrors($validator)->withInput(Input::all());
}
This should hopefully force it to pass the array of input values, instead of relying on the
'$this->request->input()'
still existing in the session.
You are doing Input::flash() and then withInput(), which effectively does Input::flash() twice, probably invalidating the flashed input. Try only doing one of the two.
Also, MihirEvent::save(); is wrong, you want to do $event->save();.
Finally i found the issue: There was a leading space in the routes.php file, before the <?php opening tag. (was working on a team and someone else added that space).