mapare clasa peste tabela

Secţiune dedicată începatorilor.

Moderatori: Moderatori, Start Moderator

vekand
Average Member
Mesaje: 83
Membru din: Dum Mai 03, 2015 9:15 am

Re: mapare clasa peste tabela

Mesajde vekand » Mar Mai 24, 2016 5:31 pm

Salut nevvermind, este mult mai profesionist cu clase parinte-copil. Am mutat metodele INSERT, UPDATE, DELETE in clasa parinte (acestea sint comune la toate clasele), iar in clasa copil (Ore) am lasat numai ce este specific clasei. Tot in clasa copil am mai introdus citeva metode pentru generarea array-urilor de add/modify, array pt.tabela html si inca o metoda de preluare a fostelor variabile GLOBAL (desi acestea nu se introduc in baza de date, sint folosite doar pentru titluri de coloane in tabelul html (<th>) si in form-uri (<label>) )
Nu stiu daca am facut totul bine (in sensul de profesionist), dar functioneaza, am testat. N-am putut modifica chiar in toata baza de date sau aplicatie, mi-ar fi luat prea mult timp, dar pe viitor voi tine cont de sugestiile tale.
Noua varianta de clasa Ore:

Cod: Selectaţi tot

class Ore extends AbstractTableMapper {
   protected $vclasa = 'Ore'; // numele clasei (il folosesc sa verific obiectul cu care lucrez la un moment dat)
   protected $vtabela = 'ore'; // numele tabelei (folosit la fisierul modelinsert.php, modelupdtae.php,   
                            //modelselect.php - am un singur fisier de inserare)
   protected $vnumeid = 'ore_id'; //numele cimpului ID din tabela (sa nu-l mai caut ulterior)
   protected $v=[];
   protected $languages = [];
   protected $vtabel = [];
   
function __construct(){ 
   parent::__construct();  // face conexiunea
   $languages = $this->getFromLanguages(); // preluare fostele variabile GLOBAL
   $this->v = $this->showColumnsFromTableAdd($languages); // array pentru add/modify
   $this->vtabel = $this->showColumnsFromTableHTML($languages); // array pentru tabela html
  }
protected function getFromLanguages(){
   $dir_lang = isset($_SESSION['language']) ? $_SESSION['language'] : 'ro';
   include (dirname(__DIR__).'/language/'.$dir_lang.'/limba.php');
   $languages = [];
   $languages += array(0=>$lang['ore']['anul']);
   $languages += array(1=>$lang['ore']['luna']);
   $languages += array(2=>$lang['ore']['oreluc']);
   return $languages;
}
protected function showColumnsFromTableAdd($languages){
   $sql= 'SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA =\'atis\' AND TABLE_NAME=\'ore\'';
   $rows = $this->conn->sqlExec($sql); //preluare lista cimpuri din tabela   
   $rows = array_slice($rows, 1, -1);   //sterg primul si ultimul (ore_id si datamod de care nu am nevoie la add)
   $nr_ar = count($rows);
   for($i=0; $i<$nr_ar; $i++){  // sterg cimpurile care nu-mi trebuie (nu le folosesc in formular)
      foreach($rows[$i] as $k=>$v){
      if($v =='aredoc') unset($rows[$i]);
      if($v =='userid') unset($rows[$i]);
      }
   }
   $numItems = count($languages);
   $i=0;
   foreach ($rows as $k=>$v){   // completez array add/modify
      if($i<$numItems)
      $this->v += [$languages[$i]=>$v[0]];
      $i++;
   }
   return $this->v;
}
protected function showColumnsFromTableHTML($languages){
   $sql= 'SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA =\'atis\' AND TABLE_NAME=\'ore\'';
   $rows = $this->conn->sqlExec($sql);    
   $rows = array_slice($rows, 1, -1);   
   $nr_ar = count($rows);
   for($i=0; $i<$nr_ar; $i++){
      foreach($rows[$i] as $k=>$v){
      if($v =='aredoc') unset($rows[$i]);
      if($v =='userid') unset($rows[$i]);
      }
   }
   $numItems = count($languages);
   $i=0;
   foreach ($rows as $k=>$v){   
      if($i<$numItems)
      $this->vtabel += [$languages[$i]=>$v[0]];
      $i++;
   }
   return $this->vtabel;
}
protected function getMappedTableName(){
   return $this->vtabela;
}
protected function getPrimaryKeyColumnName(){
   return $this->vnumeid;
}
public function getClasa(){
   return $this->vclasa;
}
public function getTabela(){
   return $this->vtabela;
}
public function getNumeid(){
   return $this->vnumeid;
}
public function getVariabile(){
   return $this->v;
}
public function getTabel(){
   return $this->vtabel;
}
   
}



nevvermind
Senior Member
Mesaje: 1264
Membru din: Mar Iun 22, 2010 3:17 pm

Re: mapare clasa peste tabela

Mesajde nevvermind » Mar Mai 24, 2016 6:53 pm

1. Cand ti-am spus sa eviti globalele, indirect ma refeream si la accesarea super-globalelor: $_SESSION, $_POST etc. Din nou: injecteaza-ti dependintele:

Cod: Selectaţi tot

$dir_lang = !empty($_SESSION['language']) ? $_SESSION['language'] : 'ro';
$ore = new Ore($dir_lang);

// in clasa Ore
public function __construct($dir_lang)
{
    $this->language = $dir_lang;
}


2. Mapper-ul tau stie de tabele HTML, stie unde sunt fisierele de limba etc. Stie prea multe. Un mapper trebuie sa cunoasca NUMAI conexiunea, tabelele, cum se insereaza/sterge valori in doar acel tabel. Nimic mai mult.
Facusi un canal de php pe freenode - ##php-ro : https://webchat.freenode.net/

vekand
Average Member
Mesaje: 83
Membru din: Dum Mai 03, 2015 9:15 am

Re: mapare clasa peste tabela

Mesajde vekand » Mar Mai 24, 2016 7:30 pm

Inseamna ca array-ul cu variabilele de limba ar trebui sa-l fac in alta parte si in clasa doar sa-l folosesc cind e nevoie. Nici mie nu-mi place ca in clasa am functii INCLUDE. Mapperul nu stie de tabele HTML, el face doar un simplu array cu anumite cimpuri din tabela, acel array il folosesc in alta parte in afara clasei. Dar voi studia. Multumesc!

vekand
Average Member
Mesaje: 83
Membru din: Dum Mai 03, 2015 9:15 am

Re: mapare clasa peste tabela

Mesajde vekand » Mie Mai 25, 2016 9:54 am

PS: am rezolvat cu variabilele de limba, fac array-ul in alta parte si il preiau ca parametru in constructorul clasei. Am scapat astfel de instructiunile INCLUDE din clasa. Acum mapper-ul stie mult mai putine.

vekand
Average Member
Mesaje: 83
Membru din: Dum Mai 03, 2015 9:15 am

Re: mapare clasa peste tabela

Mesajde vekand » Vin Mai 27, 2016 9:20 am

Multumesc nevvermind pentru ajutorul acordat, am optimizat mapper-ele (foarte important!) dar vreau sa merg mai departe: vreau sa fac clasele de interogare (SELECT), eu am pus in mapper (in clasa parinte, linga INSERT, UPDATE, DELETE) o metoda SELECT care face SELECT * FROM tabela, dar nu e suficient, in majoritatea cazurilor am INNER JOIN intre tabele, deci nu pot aplica mapper-ul in aceste cazuri. O idee cum sa rezolv? Trebuie sa face alte clase, dar astea nu vor mai fi specializate. Multumesc.

nevvermind
Senior Member
Mesaje: 1264
Membru din: Mar Iun 22, 2010 3:17 pm

Re: mapare clasa peste tabela

Mesajde nevvermind » Vin Mai 27, 2016 12:20 pm

Da, de asta urma sa te lovesti. Acum dai de un alt acronim: DBAL.

- http://framework.zend.com/manual/1.12/e ... elect.html
- http://docs.doctrine-project.org/projec ... ilder.html

Poti lua ruta intermediara, si sa faci niste helper-e (sau doar unul) specializate in interogari SQL, cu metode precum: select, innerJoin, outerJoin, insert, update, delete, createTable, addForeignKey etc. Astea vor primi mai multi parametri, in functie de necesitati. Apoi doar le chemi din mapper-ii tai.
Facusi un canal de php pe freenode - ##php-ro : https://webchat.freenode.net/

nevvermind
Senior Member
Mesaje: 1264
Membru din: Mar Iun 22, 2010 3:17 pm

Re: mapare clasa peste tabela

Mesajde nevvermind » Vin Mai 27, 2016 12:24 pm

As vrea totusi ca in thread-ul asta sa fie mai mult cod decat este acuma. Arata-ti clasa, omu, n-o mai ascunde atata.
Foloseste https://gist.github.com/ sau pastie.org cu un snippet privat ceva, sau direct in forum.
Facusi un canal de php pe freenode - ##php-ro : https://webchat.freenode.net/

vekand
Average Member
Mesaje: 83
Membru din: Dum Mai 03, 2015 9:15 am

Re: mapare clasa peste tabela

Mesajde vekand » Vin Mai 27, 2016 12:59 pm

N-am pus mult cod ca n-am vrut sa plictisesc lumea, acum pun clasa parinte varianta finala (zic eu):

Cod: Selectaţi tot

abstract class AbstractTableMapper
{
protected $conn;
public function __construct()
{
    include_once (dirname(__DIR__).'/include/class.pdo_mysqli.php');
   include (dirname(__DIR__).'/conect.php');
   $this->conn = new pdo_mysqli($mysql);
}
abstract protected function getMappedTableName();

abstract protected function getPrimaryKeyColumnName();

protected function modelInsert($data){
   $cols = implode(', ', array_keys($data));  //get the keys
   $vals = "'". implode("', '", array_values($data)) ."'";  //get the values
   $sql ="INSERT INTO $this->vtabela ( $cols ) VALUES ( $vals )";
   $rows = $this->conn->sqlExec($sql);  // executa INSERT
   return $rows;
}
protected function modelUpdate($data, $id){
   $i = 0;
   $numItems = count($data);
   $re='';
   foreach ($data as $key => $value) {
      $re .= "$key = '$value' ";
      if(++$i < $numItems) $re .= ",";
   }   
   $sql ="UPDATE $this->vtabela SET $re WHERE $this->vnumeid=".$id;
   $rows = $this->conn->sqlExec($sql);
   return $rows;
}
protected function modelDelete($id)
{
   if ($id>0){
   $sql = "DELETE FROM $this->vtabela WHERE $this->vnumeid= ".$id;
   $rows = $this->conn->sqlExec($sql);
   return $rows;
   }
}
protected function modelSelect($id, $where)
{
   if ($id>0){
   $sql = "SELECT * FROM $this->vtabela ".$where;
   } else {
   $sql = "SELECT * FROM $this->vtabela WHERE $this->vnumeid= ".$id." ".$where;
   }
   $rows = $this->conn->sqlExec($sql);
   return $rows;   
}
public function getInsert($data){
   return $this->modelInsert($data) ;
}
public function getUpdate($data, $id){
   return $this->modelUpdate($data, $id) ;

public function getSelect($id, $where){
   return $this->modelSelect($id, $where) ;
}
public function getDelete($id){
   return $this->modelDelete($id) ;
}        
}


si una din clasele copil (Ore):

Cod: Selectaţi tot

class Ore extends AbstractTableMapper {
   protected $vclasa = 'Ore';
   protected $vtabela = 'ore';
   protected $vnumeid = 'ore_id';
   protected $v=[];
   protected $languages = [];
   protected $vtabel = [];
   
function __construct($languages){ 
   parent::__construct();  // face conexiunea
   $this->v = $this->showColumnsFromTableAdd($languages); // array pentru add/modify
   $this->vtabel = $this->showColumnsFromTableHTML($languages); // array pentru tabela html
  }
protected function showColumnsFromTableAdd($languages){
   $sql= 'SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA =\'atis\' AND TABLE_NAME=\'ore\'';
   $rows = $this->conn->sqlExec($sql); //preluare lista cimpuri din tabela   
   $rows = array_slice($rows, 1, -1);   //sterg primul si ultimul (ore_id si datamod de care nu am nevoie la add)
   $nr_ar = count($rows);
   for($i=0; $i<$nr_ar; $i++){  // sterg cimpurile care nu-mi trebuie (nu le folosesc in formular)
      foreach($rows[$i] as $k=>$v){
      if($v =='aredoc') unset($rows[$i]);
      if($v =='userid') unset($rows[$i]);
      }
   }
   $numItems = count($languages);
   $i=0;
   foreach ($rows as $k=>$v){   // completez array add/modify
      if($i<$numItems)
      $this->v += [$languages[$i]=>$v[0]];
      $i++;
   }
   return $this->v;
}
protected function showColumnsFromTableHTML($languages){
   $sql= 'SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA =\'atis\' AND TABLE_NAME=\'ore\'';
   $rows = $this->conn->sqlExec($sql);    
   $rows = array_slice($rows, 1, -1);   
   $nr_ar = count($rows);
   for($i=0; $i<$nr_ar; $i++){
      foreach($rows[$i] as $k=>$v){
      if($v =='aredoc') unset($rows[$i]);
      if($v =='userid') unset($rows[$i]);
      }
   }
   $numItems = count($languages);
   $i=0;
   foreach ($rows as $k=>$v){   
      if($i<$numItems)
      $this->vtabel += [$languages[$i]=>$v[0]];
      $i++;
   }
   return $this->vtabel;
}
protected function getMappedTableName(){
   return $this->vtabela;
}
protected function getPrimaryKeyColumnName(){
   return $this->vnumeid;
}
public function getClasa(){
   return $this->vclasa;
}
public function getTabela(){
   return $this->vtabela;
}
public function getNumeid(){
   return $this->vnumeid;
}
public function getVariabile(){
   return $this->v;
}
public function getTabel(){
   return $this->vtabel;
}
   
}

Vreau sa mai spun ca acele 2 array-uri care se creeaza in mapper nu sint folosite aici, mapperul doar asociaza variabilele de limba cu cimpuri din tabela, array-urile le folosesc mai tirziu cind construiesc formularul, respectiv tabelul HTML (ambele se genereaza co foreach(){} pe array-ul corespunzator).
Acum vreau sa fac interogari (cu INNER JOIN), pentru astea inca n-am facut clase, doar functii, dar vreau sa fac pentru a putea construi alte array-uri (exemplu array pentru raport) care sa fie generate in acelasi mod.

vekand
Average Member
Mesaje: 83
Membru din: Dum Mai 03, 2015 9:15 am

Re: mapare clasa peste tabela

Mesajde vekand » Vin Mai 27, 2016 1:15 pm

Mai pun un exemplu de functie generare formular (pentru Ore):

Cod: Selectaţi tot

function formOre($variabile, $tabela, $clasa, $numeid, $dateupdate, $flag){
$clasa = $_SESSION['clasa'];
$numItems = count($variabile);
$codverif = setCaptcha('codverif');
$datacurenta= date('Y-m-d');
$_SESSION['document']='';
$_SESSION['drapel']=$flag;
$drapel=$flag;
$flag='I';  // inchide form Insert
$i=0;
$display='';
$culoare = $_SESSION["temauser"];
$re='';
$re .='<div id="'.$tabela.'" ><form action="/atis/prelucrari.php" onsubmit="return existaanluna('."'".$tabela."', '".$drapel."'".')" id="'.$tabela.'" class="'.$culoare.$tabela.'" method="POST" style="position: absolute; top:15%;right: 45%;text-align: right;"><span style="float: left; font-size: 24px;">&nbsp;&nbsp;'.$clasa.'</span><a href = "#" onclick = "ascundeFormular('."'".$clasa."'".","."'".$flag."'".');" style=" float:right;" ><img src="/atis/img/x.png" alt="" /></a><br/><br/><br/>';
foreach ($variabile as $key => $value) {  //  aici se parcurge array-ul construit in mapper corespunzator lui Add/Modify
if ($drapel=='A') {$display = "";}
 if(!empty($dateupdate)){
    if ($value=='anul' ){
    $re .= '<label for="'.$value.'" style="'.$display.'">'.$key.'</label><input type="number" name="'.$value.'" id="'.$value.'"  min="2016" max="2030" autocomplete="off" value="'.$dateupdate[$value].'" align="right" style="text-align: center; width: 200px; height: 22px; margin: 3px; '.$display.'" />';
    }
    else if ($value=='luna' ){
    $re .= '<label for="'.$value.'" style="'.$display.'">'.$key.'</label><input type="number" name="'.$value.'" id="'.$value.'"  min="1" max="12" autocomplete="off" value="'.$dateupdate[$value].'" align="right" style="text-align: center; width: 200px; height: 22px; margin: 3px; '.$display.'" />';
    }   
    else if ($value=='oreluc' ){
    $re .= '<label for="'.$value.'" style="'.$display.'">'.$key.'</label><input type="number" name="'.$value.'" id="'.$value.'"  min="1" max="200" autocomplete="off" value="'.$dateupdate[$value].'" align="right" style="text-align: center; width: 200px; height: 22px; margin: 3px; '.$display.'" />';
    }      
   if (empty($display)) $re .= '<br />';
 }
else {
    if ($value=='anul' ){
    $re .= '<label for="'.$value.'" style="'.$display.'">'.$key.'</label><input type="number" name="'.$value.'" id="'.$value.'"  min="2016" max="2030"  autocomplete="off" value="'.date("Y").'" onfocus="this.select();" align="right" style="text-align: center; width: 200px; height: 22px; margin: 3px; '.$display.'" />';
    }
    else if ($value=='luna' ){
    $re .= '<label for="'.$value.'" style="'.$display.'">'.$key.'</label><input type="number" name="'.$value.'" id="'.$value.'" min="1" max="12" autocomplete="off" value="'.date("m").'" onfocus="this.select();" align="right" style="text-align: center; width: 200px; height: 22px; margin: 3px; '.$display.'" />';
    }   
    else if ($value=='oreluc' ){
    $re .= '<label for="'.$value.'" style="'.$display.'">'.$key.'</label><input type="number" name="'.$value.'" id="'.$value.'"  min="1" max="200" autocomplete="off" value="0" onfocus="this.select();" align="right" style="text-align: center; width: 200px; height: 22px; margin: 3px; '.$display.'" />';
    }         
   if (empty($display)) $re .= '<br />';
   }   
   $i++;
   
}

$re .= '<input type="hidden" name="valanluna" id="valanluna" value="" />';
$re .= '<input type="hidden" name="numeclasa" id="numeclasa" value="'.$clasa.'" />';
$re .= '<input type="hidden" name="numetabela" id="numetabela" value="'.$tabela.'" />';
$re .= '<input type="hidden" name="numeid" id="numeid" value="'.$numeid.'" />';   // nume cimp id
$re .= '<input type="hidden" name="valoareid" id="valoareid" value="" />';   // valoare cimp id
$re .= '<input type="hidden" name="codverif" id="codverif" value="'.$codverif.'" />';
$re .= '<input type="hidden" name="accept" id="accept" value="" />';   //verificare cod securitate
$re .= '<input type="hidden" name="modalitate" id="modalitate" value="'.$drapel.'" />'; // adaugare - modificare                     
$re .= "<br /><input type='submit' value ='Save'  />&nbsp;&nbsp;";
$re .= '</form></div><br/>';
return $re;
}

Functia de generare formular este folosita atit pentru Add cit si pentru Modify. Nu arata foarte bine dar tocmai de asta vreau s-o fac mai profesionist.

vekand
Average Member
Mesaje: 83
Membru din: Dum Mai 03, 2015 9:15 am

Re: mapare clasa peste tabela

Mesajde vekand » Mie Iun 01, 2016 6:34 pm

Salut nevvermind, am reusit sa fac clasele de interogare, dar a trebuit sa fac citeva modificari:
1. In loc de ierarhie de 2 clase am ierarhie de 3 clase.
2. Clasa parinte (superclasa) face doar conexiunea.
3. Clasele intermediare (si copil si parinte) sint 2: una pentru mappere si una pentru interogari combinate (INNER JOIN).
4. Mapperele creeaza acum un singur array - cel pentru Add/Modify (care tine strict de tabela). Celelalte array-uri (pentru tabele html si pentru rapoarte)
le-am mutat in clasele de interogare. Am obtinut astfel un dublu avantaj: pe de o parte mapper-ul a devenit strict specializat pe o tabela, pe de alta parte array-ul pentru tabele HTML (sau rapoarte) poate contine cimpuri din mai multe tabele (din query-ul combinat).
5. Pentru fiecare SELECT combinat am facut cite o clasa, pentru ca aici construiesc si array-urile pentru tabele html si rapoarte (deocamdata e facut array-ul pentru tabele html).
Postez ca exemplu cele 3 clase ierarhizate pentru interogari combinate (fara clasele mapper ca astea le-am pai pus):
Clasa parinte;

Cod: Selectaţi tot

class BaseTableMapperSelect
{
   protected $conn;
public function __construct()
{
    include_once (dirname(__DIR__).'/include/class.pdo_mysqli.php');
   include (dirname(__DIR__).'/conect.php');
   $this->conn = new pdo_mysqli($mysql);
}      
}

Clasa intermediara pentru interogari (am eliminat cconstructorul ca sa oblig clasa copil sa apeleze constructorul din superclasa):

Cod: Selectaţi tot

class ClassBuilderSelect extends BaseTableMapperSelect
{
protected function buildSelect(){   
   return " SELECT ";
}
protected function buildDistinct(){
   return " DISTINCT ";
}
protected function buildFields($arrayfields){
   return implode(', ', $arrayfields);
}
protected function buildFrom($table, $prefix){
   return  " FROM ".$table." ".$prefix;
}   
protected function buildAnd(){
   return " AND ";
}   
protected function buildOr(){
   return " OR ";
}
protected function buildInner($table, $prefix, $relation ){
   return " INNER JOIN ".$table." ".$prefix. " ON ".$relation;
}
protected function buildLeft($table, $prefix){
   return " LEFT JOIN ".$table." ".$prefix;
}
protected function buildOnFirst($prefix, $field){
   return " ON ".$prefix.".".$field;
}
protected function buildOnSecond($prefix, $field){
   return " = ".$prefix.".".$field;
}
protected function buildWhere($prefix, $field){
   return " WHERE ".$prefix.'.'.$field;
}
protected function buildGroup($group){
   return " GROUP BY ".$group;
}
protected function buildOrder($order){
   return " ORDER BY ".$order;
}

public function getbuildSelect(){   
   return $this->buildSelect();
}
public function getbuildDistinct(){
   return $this->buildDistinct();
}
public function getbuildFields($arrayfields){
   return $this->buildFields($arrayfields);
}
public function getbuildFrom($table, $prefix){
   return $this->buildFrom($table, $prefix);
}   
public function getbuildAnd(){
   return $this->buildAnd();
}   
public function getbuildOr(){
   return $this->buildOr();
}
public function getbuildInner($table, $prefix){
   return $this->buildInner($table, $prefix);
}
public function getbuildLeft($table, $prefix){
   return $this->buildLeft($table, $prefix);
}
public function getbuildOnFirst($prefix, $field){
   return $this->buildOnFirst($prefix, $field);
}
public function getbuildOnSecond($prefix, $field){
   return $this->buildOnSecond($prefix, $field);
}
public function getbuildWhere($where){
   return $this->buildWhere($where);
}
public function getbuildGroup($group){
   return $this->buildGroup($group);
}
public function getbuildOrder($order){
   return $this->buildOrder($order);
}



Clasa de interogare (aici construiesc instructiunea SQL si array-ul pentru tabele html, array-ul cu variabilele de limba este deja preluat in constructor):

Cod: Selectaţi tot

class SelectEchipe extends ClassBuilderSelect {
   protected $varfields = '';
   protected $stringsql = '';
   protected $prefix = '';
   protected $languages = [];
   protected $vararraytable = [];
   protected $vtabel = [];
   protected $vtabelstring = '';
function __construct($languages){
   parent::__construct();  // connection
   // sql expression to build select multiple tables
   $this->stringsql .= $this->getbuildSelect();
   $this->stringsql .= $this->showColumnsStringFromSelect('echipa_id,echipa','ec').', '; //echipe
   $this->stringsql .= $this->showColumnsStringFromSelect('nume','us').', '; // useri
   $this->stringsql .= $this->showColumnsStringFromSelect('idsef,aredoc','ec');  //echipe   
   $this->stringsql .= $this->getbuildFrom('echipe','ec');
   $this->stringsql .= $this->getbuildLeft('useri','us');
   $this->stringsql .= $this->getbuildOnFirst('ec','idsef');
   $this->stringsql .= $this->getbuildOnSecond('us','user_id');
   // array for html table (removed from mapper and included here)
   $this->vtabel = $this->createArrayForHTMLTable($languages, 'echipa, nume');
   }
protected function showColumnsStringFromSelect($varfields,$prefix){
   $vararray = explode(',',$varfields);
   $varstring = '';
   foreach ($vararray as $v){
   $this->vararraytable[] = $v;
   if (end($vararray) == $v) $varstring .= $prefix.'.'.$v;
   else $varstring .= $prefix.'.'.$v.', ';
   }
   return $varstring;
}
protected function createArrayForHTMLTable($languages, $fields){
   $vararray = explode(',',$fields);
   $numItems = count($languages);
   $i=0;
   foreach ($vararray as $v){   
      if($i<$numItems)
      $this->vtabel += [$languages[$i]=>$v];
      $i++;
   }
   return $this->vtabel;
}
public function getStringSQL(){  //retrieve sql expression
     return $this->stringsql;
}
public function getTabel(){ //retrieve array for html table
     return $this->vtabel;
}
}

Te rog frumos daca ai timp sa-ti dai cu parerea. Am incercat sa le fac cit mai flexibile, nu stiu daca sint facute ca lumea. Multumesc.

nevvermind
Senior Member
Mesaje: 1264
Membru din: Mar Iun 22, 2010 3:17 pm

Re: mapare clasa peste tabela

Mesajde nevvermind » Mie Iun 01, 2016 7:50 pm

Revin cu detalii mai incolo (stau mai prost cu timpul acum), dar ai o problema (zic eu mare): mapper-ul tau deodata a devenit o interogare. Conceptual, e o zacusca. Un mapper e un mapper, si o interogare e altceva. Eu despre asta ti-am spus in ultimul meu reply.

Ierarhia inseamna mai multe, printre care asemanare conceptuala. Daca B extinde A, inseamna ca B este A, doar mai specializat. Dar, la tine, un mapper NU este un select. Doar se foloseste de el. Asta inseamna compozitie: B nu este A, ci foloseste A.

Imagine

Si ajungem la capitolul "favor composition over inheritance". Cauta pe net despre. Gasesti o gramada.

Ai nevoie de o clasa noua, care reprezinta o interogare SQL - un "SQL query builder". Simplu. N-o intereseaza daca e folosita intr-un mapper sau e instantiata direct. Uite cum arata una: https://github.com/zendframework/zf1/bl ... Select.php

Uite alte exemple:
- https://packagist.org/search/?q=query%20builder
- https://github.com/nilportugues/php-sql-query-builder

PS:
"am eliminat cconstructorul ca sa oblig clasa copil sa apeleze constructorul din superclasa"
Poti chema ctorul parintelui cu parent::__construct();. Deci adauga constructori unde crezi ca e necesar (adica unde crezi ca functionalitatea instantei are absoluta nevoie de anumite valori).

PPS: Aeriseste-ti codul; lasa un rand gol intre metode macar. Mi-e greu sa-l citesc. Uite cum mi l-a formatat phpstorm: http://pastie.org/private/ppy3rs2cipnv8r3k2w5q. Mai lizibil, este?

PPS: Nu inteleg de ce faci asa:

Cod: Selectaţi tot

public function getbuildLeft($table, $prefix){
   return $this->buildLeft($table, $prefix);
}
public function getbuildOnFirst($prefix, $field){
   return $this->buildOnFirst($prefix, $field);
}
public function getbuildOnSecond($prefix, $field){
   return $this->buildOnSecond($prefix, $field);
}

Scapa de alea protected deocamdata. Is degeaba. Ramai numai cu publicele. Si tot nu-ti inteleg denumirile; nici ale metodelor, nici ale variabilelor. Ce inseamna "buildOnSecond"? Dar "vararray"? Ma faci sa cred ca tu copiezi de undeva. Si e bine c-o faci, dar afla ce copiezi. Nu baga tipul variabilelor in numele lor, wtf? Spune ce reprezinta intr-un limbaj natural: "columns", "fields", "tableName" etc.
Facusi un canal de php pe freenode - ##php-ro : https://webchat.freenode.net/

vekand
Average Member
Mesaje: 83
Membru din: Dum Mai 03, 2015 9:15 am

Re: mapare clasa peste tabela

Mesajde vekand » Mie Iun 01, 2016 10:12 pm

Multumesc de raspunsurile critice, chiar imi folosesc, dar cred ca eu nu m-am facut suficient inteles:
1. N-am copiat nimic de niciunde, "vararray" si altele citeva sint variabile intermediare (ajutatoare) pentru construirea de array-uri in clasa, aceste variabile nu "ies" din clasa, deci n-am considerat necesar sa le explicitez.
2. Clasele de interogari nu sint gindite ca mappere, singurele mappere pe care le am sint cele facute la inceput pe fiecare tabela, clasele de interogari sint doar clase care ma ajuta sa fac query-uri ma scutesc sa scriu manual array-ul HTML table si array-ul raport. De asta le-am pus pe fir separat. Dar mapperele mele (cele facute chiar in prima faza) arata exact cum mi-ai desenat in schita, iar ce ai pus in box-ul SELECT sint chiar clasele mele de interogare (care nu sint mappere).
3. "buildOnSecond" este metoda din clasa superioara si indica al doilea criteriu de relationare de dupa INNER JOIN (ex. INNER JOIN useri u ON e,iduser=u.user_id), deci ce este dupa semnul =. De altfel toate metodele sint definite in clasa superioara celei in care construiesc query.
4. Exista parent::__construct(); in clasa de jos, care merge direct la superclasa (nu mai trece prin clasa intermediara, acolo n-am nevoie de constructor).

Voirevedea in amanunt ce mi-ai spus si voi face corectille.

nevvermind
Senior Member
Mesaje: 1264
Membru din: Mar Iun 22, 2010 3:17 pm

Re: mapare clasa peste tabela

Mesajde nevvermind » Mie Iun 01, 2016 11:16 pm

Atunci poate n-am inteles eu, sorel.

Pe scurt, ar trebui sa poti ajunge sa faci:

Cod: Selectaţi tot

class MyMapper {
    public function getTable2Values()
    {
        $query = new QueryBuilder();

        $query
            ->from('table1', ['col1', 'col2'])
            ->where('col1.field = ' . $someValue)
            ->join('table2', 'table1.id = table2.id', 'table2.somefield > 2000');

        var_dump($select->toString()); // SELECT col1, col2 FROM table1 INNER JOIN table2 ...

        return $this->connection->query(query->toString());   
    }   
}

Dupa cum vezi, clasa de mai sus n-are nevoie de conexiune la DB, e doar un builder OOP pentru un string (in cazul de fata, o interogare SQL).
Ideea este sa decuplezi mapper-ele de creare de interogari SQL.

Daca ruta asta e prea dificila, poti face o clasa mai putin complicata.

Daca si asta e prea complicat, atunci mapper-ele pot face interogari direct ("hard-coding"), sigur, dar e mai greu de abstractizat asa ceva.

-----------------------
"vararray" si altele citeva sint variabile intermediare (ajutatoare) pentru construirea de array-uri in clasa, aceste variabile nu "ies" din clasa, deci n-am considerat necesar sa le explicitez.

Gandesti asa fiindca vii din lumea lui "global". Nu numai variabilele globale trebuie denumite bine, ci toate, pe cat posibil. Asta pentru a te ajuta atat pe tine - cand iti vei reciti codul in 6 luni -, cat si pe altii, care trebuie sa-si dea seama ce vroiai sa spui. Nu neglija importanta denumirilor. Dupa cum vezi, nu-i asa de simplu. De ex, eu pot sa-mi dau seama cand tu nu intelegi un concept fiindca le denumesti aiurea.

Compara
a)
withJoinCondition('ec.idsef = us.user_id)

cu b)
buildOnFirst('ec.idsef');
buildOnSecond('us.user_id');

Sa-mi arati si mie prostul care nu intelege din prima ce face a).

PS: Ai citit PM-ul pe care ti l-am trimis?
Facusi un canal de php pe freenode - ##php-ro : https://webchat.freenode.net/

vekand
Average Member
Mesaje: 83
Membru din: Dum Mai 03, 2015 9:15 am

Re: mapare clasa peste tabela

Mesajde vekand » Joi Iun 02, 2016 1:03 am

Consider ca toate observatiile tale sint corecte. Iti sint recunoscator pentru rabdarea ta.
Cred ca am farimitat prea mult metodele de la construirea query-ului. Trebuie sa le mai regrupez. Pe de alta parte mi-am dat seama ca nici clasa de interogare n-are nevoie de conexiune pentru ca SELECT-ul nu se executa aici, deci este tot un QueryBuilder.

N-am citit nici un PM, unde l-ai trimis?

vekand
Average Member
Mesaje: 83
Membru din: Dum Mai 03, 2015 9:15 am

Re: mapare clasa peste tabela

Mesajde vekand » Joi Iun 02, 2016 8:44 am

PS: acum am citit PM-ul, voi studia.


Înapoi la “PHP Incepători”

Cine este conectat

Utilizatori ce ce navighează pe acest forum: Niciun utilizator înregistrat și 62 vizitatori