Welcome Guest, Not a member yet? Register   Sign In
turn array into object active record can use
#1

[eluser]dionysus[/eluser]
I'm running a query and then decrypting it in the controller. After it is decrypted I was putting the results into an array and sending that to the view. The problem is with this solution I need to rewrite all of my views to parse the arrays sent instead of the active record objects sent before.

Is there a way to turn the decrypted array back into an object that will work with existing active record code in the view?
Before

Controller:

Code:
$name = $this->Clients_model->getNameData('*','client_id='.$clid,'');
$data['name'] = $name;
$this->load->view('names/name_view',$data);

View:

Code:
if($name->num_rows()) > 0){
    foreach($name->result() as $row){
        echo $row->data;
[...]

Now

Controller:

Code:
$name = $this->Clients_model->getNameData('*','client_id='.$clid,'');
$nameArray= array();
foreach ($name->result() as $row){
    $x = $row;
    $keys = array('id','client_id');
    $unenc = array();
    foreach ($x as $key=>$value){
        if(! in_array($key, $keys)){
            $unenc[$key]=$this->encrypt->decode($value,$this->e_key);
        }else{
            $unenc[$key]=$value;
        }
    }
    array_push($nameArray,$unenc);
}

//Creates an object with the data, but doesn't work with CI active record
//foreach ($nameArray as $akey  => $aval) {
//    $namea -> {$akey} = $aval;
//}

//return $data;
$data['name'] = $nameArray;
$this->load->view('names/name_view',$data);

View:

Code:
if(count($name) > 0){
    foreach($name as $key=>$row){
        echo $row['data'];
[...]

In the second (now) controller there is some commented out code that will make an object, but it doesn't behave as expected with active record. Is there a way to take the $nameArray() array and change it into an object that will work with existing view code (such as the code in the 'before:view' above)?

Thanks!
#2

[eluser]danmontgomery[/eluser]
Code:
foreach ($nameArray as $akey  => $aval) {
    $namea -> {$akey} = $aval;
}

Can be written as:

Code:
$namea = (object)$nameArray;

I don't really understand the question here, what "doesn't work"?
#3

[eluser]dionysus[/eluser]
Because there may be multiple rows returned and because the data needs to be decrypted I have to manipulate the data before returning it to the view. As a result, the views no longer receive the data as a CI mysql result object which they are set up to use. My initial idea was to decrypt the data, stick that into an array and send that to the view (see the second or "now" code). Problem with this is I have to rewrite all the views then to work with the arrays instead of the mysql result object (eg I'd have to change all the $row->data type code to $row['data'] type code). Thanks.
#4

[eluser]mddd[/eluser]
I think the root of the problem is that you start with a 'result object' from CodeIgniter ($name). This object has methods like 'result()' and 'num_rows()'. Then you decode it. In the process of decoding, you make an array ($nameArray). That array does not have those methods. You can't do $nameArray->result(). That's what you have to change the view.

If you want to keep everything the same, you should decode the data in the object itself. You could extend the database class to add a 'decode()' method to the result object. Or you can do it a bit 'dirtier', by operating on the object. This is 'dirty' because if the CI DB class changes and you upgrade your CI installation, it might stop working. But as long as that's not the case it will work.

For reference, here's the result_object method that is used by CI to get the results you want.
Code:
// this code is in /system/database/DB_result.php

    function result_object()
    {
        if (count($this->result_object) > 0)
        {
            return $this->result_object;
        }
        
        // In the event that query caching is on the result_id variable
        // will return FALSE since there isn't a valid SQL resource so
        // we'll simply return an empty array.
        if ($this->result_id === FALSE OR $this->num_rows() == 0)
        {
            return array();
        }

        $this->_data_seek(0);
        while ($row = $this->_fetch_object())
        {
            $this->result_object[] = $row;
        }
        
        return $this->result_object;
    }

As you can see, CI assembles the object and returns it. But if it's already assembled, it just returns it right away. So what you can do is call the result() method yourself beforehand and then decode the information in the object. You then pass it to the view, and the view calls the result() method, it gets the information already decoded by you.

Code:
// controller code

// do the query
$name = $this->Clients_model->getNameData('*','client_id='.$clid,'');

// first call the result
$dummy = $name->result();

// now decode the information
$ignore_keys = array('id', 'client_id');
foreach ($name->result_object as &$row) {  // watch! we're getting the row as a reference so we're really changing it; not working on a copy
     foreach (get_object_vars($row) as $key=>$value){
        if(!in_array($key, $ignore_keys)){
            $row->$key = $this->encrypt->decode($value,$this->e_key);
        }
    }
}

// show it; in the view, $name->result() will get the decoded results.
$data = array('name'=>$name);
$this->load->view('names/name_view',$data);
#5

[eluser]dionysus[/eluser]
Wow. Thanks for the excellent reply!!

Just one question: you said 'a bit dirtier by operating on the object itself'. In that do you mean like your example where the object is manipulated within the controller? That seems like a better choice as an upgrade to CI wouldn't effect how it operates. Am I misinterpreting something?

Thanks again; this is exactly what I was looking for.
#6

[eluser]mddd[/eluser]
Well, the tricky part is that the code I wrote above relies on the fact that there is a variable called $result_object inside the CI DB result class. If a future version of CI changes that, the code will not work. That's why I say it's 'dirty'.

It would be a bit less dirty if you replaced the result_object() method in the CI DB result class with a method that gets the result and immediately decodes it. This could be done by extending the class. There could be an optional flag: result_object($use_decode = false) { ... } But still, that would leave places where stuff could break: the result_object method calls _fetch_object and that could also change in some future version.. so I guess there is always a possibility for breakage..
#7

[eluser]dionysus[/eluser]
Magic. Got it.

Again, thanks for the brilliant help. I don't know why, but that is one of the best replies I've ever had to a coding question (maybe because you just saved me having to go through 80+ views and changing hundreds if not thousands of lines of code to work the way I had it Smile ). It's also nice to learn something, but yeah, that's a lot of code to rewrite.

BIG thanks!

p.s. I think that since the app is still evolving and I'm not 100% sure which fields will or will not be encrypted (which maybe is where the optional flag comes in?), and since I'm kind of flying by the seat of my pants- the solution you proposed works fine. Especially since, as you mentioned, there are any number of things that could 'break it' no matter where it lives. Maybe a little while down the line I can extend the class, but for now this is fine.
#8

[eluser]mddd[/eluser]
No problem. It's fun to try and think of smart solutions Smile That's why we got into programming, right? I'm glad it works for you!
#9

[eluser]bretticus[/eluser]
If you are a bit sketchy about CI core libs changing and breaking your decoding implementation down the road, please note that you can do the encryption and decryption in your SQL. That is, your database is doing the encrypt/decrypt. This is a little less secure because your keys are going over the wire in your queries to the database. Here the MySQL manual page.
#10

[eluser]dionysus[/eluser]
Thanks. I looked into handling the encryption purely within mysql when setting up the encryption scheme, but though it may be a little more costly in terms of performance and otherwise, handling the encryption in php on the web server was a preferable choice. The key management system in place is complex and security paramount, so for the foreseeable future encryption will be done outside of mysql.

Thanks again for your input!




Theme © iAndrew 2016 - Forum software by © MyBB