我可以将SQL查询的结果转换为对象吗?

时间:2017-11-21 17:05:40

标签: php sql-server orm

我从Sql server db获得此查询结果:

Result query

我需要从PHP获取这个json输出:

{"Clientes":
  [{
     "CodCliente": 1,
     "NombreCliente": "Garcia",
     "Direcciones":[ 
       {
        "Direccion": "Av Uriburu 2569",
        "Telefono": "4558899"
       },
       {
        "Direccion": "Pte Roca 1527",
        "Telefono": "4887541"
       }
      ]
    },
    {
     "CodCliente": 2,
     "NombreCliente": "Gonzales",
     "Direcciones":[ 
       {
        "Direccion": "Lamadrid 475",
        "Telefono": "4897425"
       }
      ]
    },
    {
     "CodCliente": 3,
     "NombreCliente": "Ferreyra",
     "Direcciones":[ 
       {
        "Direccion": "Eva Peron 253",
        "Telefono": "4689553"
       },
       {
        "Direccion": "Laprida 658",
        "Telefono": "4658963"
       }
      ]
    }
  ]
}  

我想我应该有Clientes类和Direcciones类但我不能将查询结果与json相关联:

class Cliente
{
    public $CodCliente;   
    public $NombreCliente; 
    public $Direcciones;

    public function __construct(){}

}

class Direccion
{
    public $CodCliente;   
    public $Direccion; 
    public $Telefono;    
    public function __construct(){}  
}

这就是我查询的方式,我不确定我是否正确执行:

    $pdo = Database::connect();
    $sentencia = $pdo->prepare($comando);    
    $sentencia->execute();
    if ($sentencia) {
        $resultado = $sentencia->fetchAll(PDO::FETCH_CLASS, "Cliente"); 
         return $resultado;            
    } 

4 个答案:

答案 0 :(得分:1)

好吧,你必须手动处理数据库中的数据并创建新的数组,这些数组将被适当地格式化。可能是这样的吗?

...
$result = [];
$data = $sentencia->fetchAll(PDO::FETCH_ASSOC, "Cliente");
foreach ($data as $item) {
   // Create client if not exists
   $id = $item['CodCliente'];
   if (!isset($result[$id]) {
       $result[$id] = [
           'CodCliente' => $id, 
           'NombreCliente' => $item['NombreCliente'],
           // Create empty array
           'Direcciones' => [],
       ];
   }
   // Add new contact
   $result[$id]['Direcciones'][] = [
        'Direccion' => $item['Direccion'],
        'Telefono' => $item['Telefono'],
   ];
}
// Clear reference ids and get continuous numeric array
$result = array_values($result);
// Final encapsulation
$result = ['Clientes' => $result];
return json_encode($result, JSON_PRETTY_PRINT);

代码可能会在很多方面得到改进,具体取决于您使用的PHP和/或库的版本,但这是另一个故事。

答案 1 :(得分:0)

当您返回数据时,只需使用json对其进行编码 E.g echo json_encode($ data); 我们一般用于apis

答案 2 :(得分:0)

$data = '[{
        "CodCliente": "1",
        "NombreCliente": "Garcia",
        "Direccion": "Av Uriburu 2569",
        "Telefono": "4558899"
     }, {
        "CodCliente": "1",
        "NombreCliente": "Garcia",
        "Direccion": "Pte Roca 1527",
        "Telefono": "4887541"
     }, {
        "CodCliente": "2",
        "NombreCliente": "Gonzales",
        "Direccion": "Lamadrid 475",
        "Telefono": "4897425"
     }, {
        "CodCliente": "3",
        "NombreCliente": "Ferreyra",
        "Direccion": "Eva Peron 253",
        "Telefono": "4689553"
     }, {
        "CodCliente": "3",
        "NombreCliente": "Ferreyra",
        "Direccion": "Laprida 658",
        "Telefono": "4658963"
     }]';
     $array = [];
     $decodedData = json_decode($data, true);
     foreach ($decodedData as $key) {
        $tempArray[$key['CodCliente']]['CodCliente'] = $key['CodCliente'];
        $tempArray[$key['CodCliente']]['NombreCliente'] = $key['NombreCliente'];
        $tempDirec['Direccion'] = $key['Direccion'];
        $tempDirec['Telefono'] = $key['Telefono'];
        $tempArray[$key['CodCliente']]['Direcciones'][] = $tempDirec ;
        $array[$key['CodCliente']] = $tempArray[$key['CodCliente']];
     }
     $result = json_encode(array_values($array));
     echo "<pre>";
     echo print_r($result);
     echo "</pre>";die;

说明: 你需要只有一个CodCliente类型的对象,所以我们需要对剩下的东西进行分组,所以我做的是

  1. 首先将数据解码为数组
  2. 创建一个可以将CodCliente作为键的$数组(由此我们不会得到重复的CodCliente)
  3. 在每次迭代时,如果$ array update Direcciones
  4. 中已存在CodCliente键
  5. 所以最后从$ array中删除键并对其进行编码。

答案 3 :(得分:0)

SQL数据库是关系意味着结果集是每行,这实际上意味着(尤其是当连接数上升时),您可以拥有十分之一,数百甚至数千行,以便在对象表示中可以成为对象使用一些嵌套的对象。另一方面,对象尤其是具有嵌套对象的对象更像是树表示。在这种情况下,SQL结果可能来自保存个人详细信息的表和保存地址详细信息的另一个表之间的连接。 你在寻找什么称为关系到对象映射,有很多材料需要研究,只需看看这里开始https://scholar.google.gr/scholar?q=mapping+relational+to+object&hl=el&as_sdt=0&as_vis=1&oi=scholart&sa=X&ved=0ahUKEwjboszIwtDXAhVsDZoKHbS8AMAQgQMIJDAA

现在我可以尝试根据我在开发类似算法的经验给出答案。 我们开始讨论一些关键点: 1.pdo支持在对象上进行映射(就像您已经编写过的那样),但结果始终是一个级别对象,没有呈现嵌套对象,因此它不适合您。

2.你必须通过记住表关系来创建你的类,所以如果你在个人详细信息表和地址表之间有一对多的关系,这种关系必须在你的班级中以某种方式。一个简单的方法可能是Cliente类有一个数组,它包含类Direccion的对象,就像我已经看到的那样。

3.您需要一种可以进行映射的算法。由于pdo的结果使用$ sentencia-&gt; fetchAll(PDO :: FETCH_ASSOC);将是一个关联数组,算法需要知道何时映射类属性和何时对象。

以下是一种可以按原样使用的方法,请注意此代码可能需要更多优化,对于大量结果,性能会降低数千行。使用风险自负......

1.如果您更改为$ resultado = $ sentencia-&gt; fetchAll(PDO :: FETCH_ASSOC),则输入数据;应该是这样的数组

$resultado = array(
            array("CodCliente"=>1,"NombreCliente"=>"Garcia","Direccion"=>"Sv Uriburu 2569","Telefono"=>"4558899"),
            array("CodCliente"=>1,"NombreCliente"=>"Garcia","Direccion"=>"Pte Roce 1527","Telefono"=>"4887541"),
            array("CodCliente"=>2,"NombreCliente"=>"Gonzales","Direccion"=>"Lambadrid 475","Telefono"=>"4897425"),
            array("CodCliente"=>3,"NombreCliente"=>"Ferreyra","Direccion"=>"Eva Peron 253","Telefono"=>"4689553"),
            array("CodCliente"=>3,"NombreCliente"=>"Ferreyra","Direccion"=>"Laprida 658","Telefono"=>"4658963")
        );

2.您需要按以下方式更改课程

class Cliente{

    public $CodCliente;
    public $NombreCliente;
    public $Direcciones;

    public function getDirecciones(){
        if(!isset($this->Direcciones)){
            return array(new Direccion());
        }
        return $this->Direcciones;
    }

    public function setDirecciones($Direcciones){
        $this->Direcciones = $Direcciones;
    }

    public function getCodCliente(){
        if(!isset($this->CodCliente)){
            return 0;
        }
        return intval($this->CodCliente); //ensure for the data type
    }

    public function setCodCliente($CodCliente){
        $this->CodCliente = $CodCliente;
    }

    public function getNombreCliente(){
        if(!isset($this->NombreCliente)){
            return "";
        }
        return $this->NombreCliente;
    }

    public function setNombreCliente($NombreCliente){
        $this->NombreCliente = $NombreCliente;
    }

    public function __construct(){}
}

class Direccion{
    public $Direccion;
    public $Telefono;

    public function getDireccion(){
        if(!isset($this->Direccion)){
            return 0;
        }
        return $this->Direccion; 
    }

    public function setDireccion($Direccion){
        $this->Direccion = $Direccion;
    }

    public function getTelefono(){
        if(!isset($this->Telefono)){
            return "";
        }
        return $this->Telefono;
    }

    public function setTelefono($Telefono){
        $this->Telefono = $Telefono;
    }

    public function __construct(){}
}

3.添加此

$mapper = new rbe_mapper();
$result = array();
for($i=0;$i<count($resultado);$i++){
    $client = new Cliente();
    $client = $mapper->mapArrayToObjectByProperties($resultado[$i],$client); //each iteration map a singe row from the result

    $index = getItemIndexForValueByMethod($result,$client->getCodCliente(),"getCodCliente");
    if($index===false){
        array_push($result,$client);
    }else{
        $direction = $client->getDirecciones();
        $directions = $result[$index]->getDirecciones();
        array_push($directions,$direction[0]);
        $result[$index]->setDirecciones($directions);
    }
}

4.这个

function getItemIndexForValueByMethod($array,$value,$method){
    if(!is_array($array)){
        return false;
    }
    if(empty($array)){
        return false;
    }

    for($i=0;$i<count($array);$i++){
        if($array[$i]->$method()==$value){
            return $i;
        }
    }

    return false;
}

class rbe_mapper{

    public function mapArrayToObjectByProperties($row,$object){
        $class = get_class($object);

        $properties = get_class_vars($class);
        $keys = array_keys($properties);
        $plength = count($keys);
        for($i=0;$i<$plength;$i++){
            $property = ucfirst($keys[$i]);
            $setter = "set".$property;
            $getter = "get".$property;
            if(method_exists($class,$setter) && method_exists($class,$getter)){
                if(is_object($object->$getter())){
                    $object->$setter($this->mapArrayToObjectByProperties($row,$object->$getter())); //for nested objects
                }elseif(is_array($object->$getter())){
                    $ar = $object->$getter();
                    $ar[0] = $this->mapArrayToObjectByProperties($row,new $ar[0]()); //for arrays
                    $object->$setter($ar);
                }else{//value setting fonr non of the avove data types
                    $value = false;
                    if(isset($row[$property])){
                        $value = $row[$property];
                    }

                    if($value!==false){
                        $object->$setter($value);
                    }
                }
            }


        }

        return $object;
    }
}

最终代码应为

//class definition here sample 2,4
$pdo = Database::connect();
    $sentencia = $pdo->prepare($comando);    
    $sentencia->execute();
    if ($sentencia) {
        $resultado = $sentencia->fetchAll(PDO::FETCH_ASSOC); 
//add here sample 3
         return json_encode($result);            
    } 

并且json中的结果是

[{
        "CodCliente": 1,
        "NombreCliente": "Garcia",
        "Direcciones": [{
                "Direccion": "Sv Uriburu 2569",
                "Telefono": "4558899"
            }, {
                "Direccion": "Pte Roce 1527",
                "Telefono": "4887541"
            }
        ]
    }, {
        "CodCliente": 2,
        "NombreCliente": "Gonzales",
        "Direcciones": [{
                "Direccion": "Lambadrid 475",
                "Telefono": "4897425"
            }
        ]
    }, {
        "CodCliente": 3,
        "NombreCliente": "Ferreyra",
        "Direcciones": [{
                "Direccion": "Eva Peron 253",
                "Telefono": "4689553"
            }, {
                "Direccion": "Laprida 658",
                "Telefono": "4658963"
            }
        ]
    }
]

请注意,getItemIndexForValueByMethod函数和带有mapArrayToObjectByProperties方法的rbe_mapper类通常可以在大多数情况下工作,您可以尝试使用其他表和连接。只要使用setter / getter方法和嵌套对象创建类(可以轻松完成嵌套对象的示例)或者数组在顶级类中,此代码就可以工作。如果您需要更多说明或解释,请告诉我。

<强>解释 所有这一切背后的主要思想是有一个抽象方法mapArrayToObjectByProperties将嵌套数组映射到对象(pdo获取结果),map的指南就​​是它自己的对象,这就是你的类需要修改的原因。你仍然需要迭代pdo将返回的数组的每一行,这就是为什么我说你可能会降低性能的原因。通常mapArrayToObjectByProperties方法,从数组中映射一行,结果是一个对象。由于mapArrayToObjectByProperties方法的每个结果都是一个对象,因此您需要检查对象是否已存在于数组中,或者是否已添加到已对象(额外地址,电子邮件等),此检查由getItemIndexForValueByMethod执行。

我为你的例子做了一些补充,以证明你可以轻松地扩展这个理论。在我的例子中,每个用户可以有多个电子邮件和一辆汽车。这意味着Cliente类有一个额外的电子邮件对象数组和一个名为car的嵌套对象。

$input = array(
            array("CodCliente"=>1,"NombreCliente"=>"Garcia","Direccion"=>"Sv Uriburu 2569","Telefono"=>"4558899","Email"=>"test@gmail.com","Brand"=>"X brand","Model"=>"Y Model"),
            array("CodCliente"=>1,"NombreCliente"=>"Garcia","Direccion"=>"Pte Roce 1527","Telefono"=>"4887541","Email"=>"test@gmail.com","Brand"=>"X brand","Model"=>"Y Model"),
            array("CodCliente"=>1,"NombreCliente"=>"Garcia","Direccion"=>"Sv Uriburu 2569","Telefono"=>"4558899","Email"=>"test_@gmail.com","Brand"=>"X brand","Model"=>"Y Model"),
            array("CodCliente"=>1,"NombreCliente"=>"Garcia","Direccion"=>"Pte Roce 1527","Telefono"=>"4887541","Email"=>"test_@gmail.com","Brand"=>"X brand","Model"=>"Y Model"),
            array("CodCliente"=>1,"NombreCliente"=>"Garcia","Direccion"=>"Sv Uriburu 2569","Telefono"=>"4558899","Email"=>"test@gmail.com","Brand"=>"X brand","Model"=>"Y Model"),
            array("CodCliente"=>1,"NombreCliente"=>"Garcia","Direccion"=>"Pte Roce 1527","Telefono"=>"4887541","Email"=>"test@gmail.com","Brand"=>"X brand","Model"=>"Y Model"),
            array("CodCliente"=>1,"NombreCliente"=>"Garcia","Direccion"=>"Sv Uriburu 2569","Telefono"=>"4558899","Email"=>"test_@gmail.com","Brand"=>"X brand","Model"=>"Y Model"),
            array("CodCliente"=>1,"NombreCliente"=>"Garcia","Direccion"=>"Pte Roce 1527","Telefono"=>"4887541","Email"=>"test_@gmail.com","Brand"=>"X brand","Model"=>"Y Model"),
            array("CodCliente"=>2,"NombreCliente"=>"Gonzales","Direccion"=>"Lambadrid 475","Telefono"=>"4897425","Email"=>"test2@gmail.com","Brand"=>"","Model"=>""),
            array("CodCliente"=>3,"NombreCliente"=>"Ferreyra","Direccion"=>"Eva Peron 253","Telefono"=>"4689553","Email"=>"test3@gmail.com","Brand"=>"","Model"=>""),
            array("CodCliente"=>3,"NombreCliente"=>"Ferreyra","Direccion"=>"Laprida 658","Telefono"=>"4658963","Email"=>"test3@gmail.com","Brand"=>"","Model"=>"")
        );


class Cliente{
    public $CodCliente;
    public $NombreCliente;
    public $Direcciones;
    public $Emails;
    public $Car;

    public function getCar(){
        if(!isset($this->Car)){
            return new Car();
        }
        return $this->Car;
    }

    public function setCar($Car){
        $this->Car = $Car;
    }

    public function getEmails(){
        if(!isset($this->Emails)){
            return array(new Email());
        }
        return $this->Emails;
    }

    public function setEmails($Emails){
        $this->Emails = $Emails;
    }

    public function getDirecciones(){
        if(!isset($this->Direcciones)){
            return array(new Direccion());
        }
        return $this->Direcciones;
    }

    public function setDirecciones($Direcciones){
        $this->Direcciones = $Direcciones;
    }

    public function getCodCliente(){
        if(!isset($this->CodCliente)){
            return 0;
        }
        return intval($this->CodCliente); //ensure for the data type
    }

    public function setCodCliente($CodCliente){
        $this->CodCliente = $CodCliente;
    }

    public function getNombreCliente(){
        if(!isset($this->NombreCliente)){
            return "";
        }
        return $this->NombreCliente;
    }

    public function setNombreCliente($NombreCliente){
        $this->NombreCliente = $NombreCliente;
    }

    public function __construct(){}
}

class Direccion{
    public $Direccion;
    public $Telefono;

    public function getDireccion(){
        if(!isset($this->Direccion)){
            return 0;
        }
        return $this->Direccion; 
    }

    public function setDireccion($Direccion){
        $this->Direccion = $Direccion;
    }

    public function getTelefono(){
        if(!isset($this->Telefono)){
            return "";
        }
        return $this->Telefono;
    }

    public function setTelefono($Telefono){
        $this->Telefono = $Telefono;
    }

    public function __construct(){}
}

class Email{
    public $Email;

    public function getEmail(){
        if(!isset($this->Email)){
            return "";
        }
        return $this->Email;
    }

    public function setEmail($Email){
        $this->Email = $Email;
    }

    public function __construct(){}
}

class Car{
    public $Brand;
    public $Model;

    public function getBrand(){
        if(!isset($this->Brand)){
            return "";
        }
        return $this->Brand;
    }

    public function setBrand($Brand){
        $this->Brand = $Brand;
    }

    public function getModel(){
        if(!isset($this->Model)){
            return "";
        }
        return $this->Model;
    }

    public function setModel($Model){
        $this->Model = $Model;
    }

    public function __construct(){
    }
}

$mapper = new rbe_mapper();
$result = array();
for($i=0;$i<count($input);$i++){
    $client = new Cliente();
    $client = $mapper->mapArrayToObjectByProperties($input[$i],$client); //each iteration map a singe row from the result

    $index = getItemIndexForValueByMethod($result,$client->getCodCliente(),"getCodCliente");
    if($index===false){
        array_push($result,$client);
    }else{
        $direction = $client->getDirecciones();
        $directions = $result[$index]->getDirecciones();
        $_index = getItemIndexForValueByMethod($directions,$direction[0]->getDireccion(),"getDireccion");
        if($_index===false){
            array_push($directions,$direction[0]);
            $result[$index]->setDirecciones($directions);
        }

        $email = $client->getEmails();
        $emails = $result[$index]->getEmails();
        $_index = getItemIndexForValueByMethod($emails,$email[0]->getEmail(),"getEmail");
        if($_index===false){
            array_push($emails,$email[0]);
            $result[$index]->setEmails($emails);
        }
    }
}

echo json_encode($result);