Welcome Guest, Not a member yet? Register   Sign In
Simple Flashdata extension to retrieve array of flashadata based on key.
#1

[eluser]Grimbog[/eluser]
Hi guys,

Just thought to share this as it may be useful in certain cases - at the moment session->flashdata is only returned as a single string, but in my own case I needed a way to show multiple notifications to the screen at once.

Why? Lets say that you submit a form, and it goes away to do its thing... not only do I have form validation going on, but there is also the process of accessing the database and checking data, or processing user input. Rather than having just 1 ambiguous line of text saying "an error has occurred", I prefer to have types of notifications in the following categories:

notice, success, pending, warning, error

So for each function that's run, it attempts to carry its task out and creates a global notifications array filled with types of messages like so:

Code:
core()->set_notification( 'The login you provided appears to be invalid.', 'warning');

Code:
core()->set_notification('Sorry, an error has occurred submitting this form.', 'error');

Don't worry about core(), this is just a master class library I wrote for my own app, but the function set_notification() is as follows:

Code:
/**
  * Sets a global notification
  *
  * @access public
  * @return bool
  */    
public function set_notification($message = NULL, $type = 'error')
{
  if (!empty($message))
  {
   // Generate the error string
   $prefix = sprintf('<li class="%s rounded">', $type);
   $suffix = '</li>';  
   $str = $prefix.'<strong>'.ucfirst($type).'</strong>: '.$message.$suffix."\n";

   $this->notifications[] = array(
    'notifications' => $str
   );

   $this->ci->session->set_flashdata($this->notifications);

   return TRUE;  
  }

  return FALSE;
}

So the function populates a global array called 'notifications', that is then filled with the message and error type. Finally this global array is sent to the session->set_flashdata. Now, we still can't do anything nice, because the stock set_flashdata function for CI was not designed to traverse multidimensional arrays. So, the trick is to extend the Session class with MY_Session.php and do a few changes.

Code:
&lt;?php if (!defined('BASEPATH')) exit('No direct script access allowed');

/**
* CI Session Extension Class
*
* @author Lawrence Eldridge
* @subpackage Auth Class
* @category Library
*
*/
class MY_Session extends CI_Session {
    
    /**
     * Constructor method
     *
     * @access public
     * @return void
     */
    function __construct()
    {
        parent::__construct();
    }    


    // --------------------------------------------------------------------
    // Main Methods (PUBLIC)
    //   These are methods that can be called externally by the system.
    // --------------------------------------------------------------------

    /**
     * Add or change flashdata, only available
     * until the next request
     *
     * @access  public
     * @param   mixed
     * @param   string
     * @return  void
     */
    function set_flashdata($newdata = array(), $newval = '')
    {
        if (is_string($newdata))
        {
            $newdata = array($newdata => $newval);
        }

        if (count($newdata) > 0)
        {
            foreach ($newdata as $key => $val)
            {
                if (is_array($val))
                {
                    foreach ($val as $item => $content)
                    {
                        $flashdata_key = $this->flashdata_key.':new:'.$item.$key;
                        $this->set_userdata($flashdata_key, $content);
                    }        
                }
                else
                {
                    $flashdata_key = $this->flashdata_key.':new:'.$key;
                    $this->set_userdata($flashdata_key, $val);
                }
            }
        }
    }

    /**
     * Keeps existing flashdata available to next request.
     *
     * @access  public
     * @param   string
     * @return  void
     */
    function keep_flashdata($key)
    {
        $userdata = $this->all_userdata();

        foreach ($userdata as $key => $value)
        {
            // make sure we're only dealing with flashes
            if (strpos($key, ':old:'.$item))
            {
                // get value from old flash key
                $value = $this->userdata($key);

                // convert flash back to new
                $parts = explode(':old:', $key);
                if (is_array($parts) && count($parts) === 2)
                {
                    $new_name = $this->flashdata_key.':new:'.$parts[1];
                    $this->set_userdata($new_name, $value);
                }              
            }
        }
    }    

    /**
     * Retrieve array of all flashdata
     *
     * @access public
     * @return array
     */
    public function flashdata($item)
    {
        $flasharray = array();
        $userdata = $this->all_userdata();

        foreach ($userdata as $key => $value)
        {
            // check key haystack with item value and use it!
            if (strpos($key, ':old:'.$item))
            {
                array_push($flasharray, $value);
            }
        }

        return $flasharray;
    }    

}
/* End of file MY_Session.php */

So here, we have 'set_flashdata' which has been altered slightly so that it checks if the value of $newdata is actually an array itself (taken from the global notifications array). It then traverses the multiarray and generates the flastdata key with the numeric key value from the global notifications to ensure the flashdata keys are kept unique and not overwritten.

The 'keep_flashdata' is basically altered so that I can still set which key I want to keep for another run/process. So because we simply look for the :old: value and then convert it to :new: we can safely split it via explode.

The final function 'flashdata' just ensures that we retain the array when we push it to view, rather than a single string.
#2

[eluser]Grimbog[/eluser]
Please note, in your view file you need to set up flashdata like so:

Code:
&lt;?php if($this->session->flashdata('notifications')) : ?&gt;
     &lt;!-- start flashdata messages --&gt;
     <ul id="flashes">
      &lt;?php foreach($this->session->flashdata('notifications') as $notification) : ?&gt;
       &lt;?= $notification ?&gt;
      &lt;?php endforeach; ?&gt;
     </ul>
     &lt;!-- end flashdata messages --&gt;
    &lt;?php endif; ?&gt;
#3

[eluser]marcogmonteiro[/eluser]
So with this I'll be able to have 2 flashdata messages of the same type?

I can do this?
Code:
set_notification( 'The login you provided appears to be invalid.', 'warning');
set_notification( 'The password you provided appears to be invalid.', 'warning');

#4

[eluser]Grimbog[/eluser]
[quote author="marcogmonteiro" date="1340358723"]So with this I'll be able to have 2 flashdata messages of the same type?

I can do this?
Code:
set_notification( 'The login you provided appears to be invalid.', 'warning');
set_notification( 'The password you provided appears to be invalid.', 'warning');

[/quote]

Hey Marco,

Yes, because the global array keys for notifications are created on the fly (0,1,2 etc.), and then merged with the multiarray key name (notifications), so it creates a new key using both the numeric and string keys (notifications1). This is then sent to userdata as '[flash:old:notifications0], [flash:old:notifications1]' etc. etc.
#5

[eluser]Grimbog[/eluser]
Should also say that you'll need to have some sort of global controller (MY_Controller.php) with the 'set_notification' function placed in and the following...

Code:
public $notifications = array();

... placed before the constructor as a property declaration.

set_notification accesses it with $this->notifications[].
#6

[eluser]marcogmonteiro[/eluser]
Aye, sounds awesome man! Good job...

I might have some use for this. =)




Theme © iAndrew 2016 - Forum software by © MyBB