Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mysqli_result::fetch_array with key [table.attribute] in the array?

I'm trying to create a general method to automatically instantiate objects from a query like this:

SELECT town.*, content.*, user.*
FROM townhub.content
LEFT JOIN town ON content.townReceiver = town.id_town
LEFT JOIN user ON content.author = user.id_user

The method that I want to build should return 3 type of objects: Town, User and Content into an array. I thought on something like that:

protected function build_objects($result, Array $classes) {
    $data = array();
    $i = 0;
    while ($row = $result->fetch_array(MYSQLI_ASSOC)) {

        foreach ($classes as $class) {
            $$class = new $class;
            $$class = $$class->fill_object($$class, $row);
            $data[$i][$class] = $$class;


        }
        $i++;
    }
    return $data;
}

And then, in each class, a method like that:

public function fill_object($object, Array $row) {
    $attributes = get_object_vars($object);
    foreach ($row as $attribute => $value) {
        foreach ($attributes as $objAtt => $emptyValue) {
            if ($attribute == $objAtt) {
                $object->$attribute = $value;
            }
        }
    }
    return $object;
}

Actually, this is doing what I want, the following array (was printed using using var_dump($data) in build_objects() ):

array (size=4)
  0 => 
    array (size=3)
      'Content' => 
        object(Content)[4]
          protected 'id_content' => string '1' (length=1)
          public 'title' => string 'Hello World!' (length=10)
          public 'description' => string 'Hello world description' (length=43)
          public 'category' => string '1' (length=1)
          public 'date' => string '2015-01-01' (length=10)
          public 'townReceiver' => string '1' (length=1)
          public 'author' => string '1' (length=1)
          private 'dbHost' (Model) => string 'localhost' (length=9)
          private 'dbUser' (Model) => string 'root' (length=4)
          private 'dbPass' (Model) => string 'root' (length=4)
          private 'dbName' (Model) => string 'townhub' (length=7)
          private 'conn' (Model) => null
      'Town' => 
        object(Town)[5]
          protected 'id_town' => string '1' (length=1)
          public 'name' => string 'Isaac' (length=5)
          public 'population' => string '750' (length=3)
          private 'dbHost' (Model) => string 'localhost' (length=9)
          private 'dbUser' (Model) => string 'root' (length=4)
          private 'dbPass' (Model) => string 'root' (length=4)
          private 'dbName' (Model) => string 'townhub' (length=7)
          private 'conn' (Model) => null
      'User' => 
        object(User)[6]
          protected 'id_user' => string '1' (length=1)
          protected 'dni' => string '20011225' (length=9)
          private 'password' => string '1234' (length=4)
          public 'name' => string 'Isaac' (length=5)
          public 'firstSurname' => string 'Surname1' (length=5)
          public 'secondSurname' => string 'Surname2' (length=5)
          public 'birthdate' => string '0000-00-00' (length=10)
          public 'gender' => string 'H' (length=1)
          public 'email' => string '[email protected]' (length=19)
          public 'isAdmin' => string '1' (length=1)
          public 'id_town' => string '1' (length=1)
          private 'dbHost' (Model) => string 'localhost' (length=9)
          private 'dbUser' (Model) => string 'root' (length=4)
          private 'dbPass' (Model) => string 'root' (length=4)
          private 'dbName' (Model) => string 'townhub' (length=7)
          private 'conn' (Model) => null

The problem is that when I fech_array (in fill_object() method) town's names are overridden by user's names; so I can't get the town's name. The easy solution is to change attribute's names on db and classes; but I think that will be a bad solution... Keep in mind that attribute's names should be equals on db and classes, so alias in the query is not possible.

There are any way to get with fetch_array an Array with key [table.attribute] instead [attribute]?
I would also like to know better ways to do this if what I want to do is not possible.

like image 758
Isaac Bosca Avatar asked May 23 '26 21:05

Isaac Bosca


1 Answers

 <?php

class DataCollectionHelper
{
    /**
     * $result var is the result of:
     * "SELECT *
     * FROM townhub.content".
     * 
     * As you left join your tables, it may appear that you haven't any towns and users
     * for particular content.
     *
     * @param $result
     * 
     * @return array
     */
    protected function build_objects($result)
    {
        $data = array();
        $i = 0;
        while ($row = $result->fetch_array(MYSQLI_ASSOC)) {
            $contentObject = new Content();
            $contentObject->fill_object($row);
            $data[$i]['Content'] = $contentObject;
            $data[$i]['User'] = $this->getUserByContentAuthor($contentObject->getAuthor());
            $data[$i]['Town'] = $this->getTownByContentByTownReceiver($contentObject->getTownReceiver());
            $i++;
        }

        return $data;
    }

    /**
     * @param integer $townReceiver
     *
     * @return Town
     */
    private function getTownByContentByTownReceiver($townReceiver)
    {
        /**
         * Here you have to get town data by your $townReceiver - property
         *  and return the object of Town
         */
    }

    /**
     * @param integer $author
     *
     * @return User
     */
    private function getUserByContentAuthor($author)
    {
        /**
         * The same here for users
         */
    }
}

class Content
{
    /**
     * @var integer
     */
    protected $content_id;
    /**
     * @var string
     */
    public $title;

    /**
     * @var integer
     */
    public $townReceiver;

    /**
     * @var string
     */
    public $description;

    /**
     * @var integer
     */
    public $author;
    /* other vars */

    /**
     * @param array $row
     *
     * @return $this
     */
    public function fill_object(array $row)
    {
        /*
         * It's not the best approach, to do like that.
         * It's better to use setters or just set your properties
         * $this->title = $row['title']; etc
         *
         * Still you could use $this instead of your $object variable
         */
        $attributes = get_object_vars($this);
        foreach ($row as $attribute => $value) {

            foreach ($attributes as $objAtt => $emptyValue) {
                if ($attribute == $objAtt) {
                    $this->$attribute = $value;
                }
            }
        }

        return $this;
    }

    /**
     * @return int
     */
    public function getTownReceiver()
    {
        return $this->townReceiver;
    }

    /**
     * @return int
     */
    public function getAuthor()
    {
        return $this->author;
    }
}
like image 110
jaro1989 Avatar answered May 25 '26 11:05

jaro1989



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!