Ankündigung

Einklappen
Keine Ankündigung bisher.

Klassenaufbau

Einklappen

Neue Werbung 2019

Einklappen
X
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • Klassenaufbau

    Hallo,

    ich bin gerade dabei eine Klasse zu programmieren mit der ein ein SQL Statement zusammenbasteln kann.

    Bislang sieht das ganze so aus.

    PHP-Code:
    final class SQLAssembler
    {
        
    /**
         * 
         * 
         * @var <array>
         */
        
    private $arrTables              = array();

        
    /**
         *
         *
         * @var <array>
         */
        
    private $arrJoinTables          = array();

        
    /**
         *
         *
         * @var <array>
         */
        
    private $arrFields              = array();

        
    /**
         *
         * @var <array>
         */
        
    private $arrJoins               = array();

        
    /**
         *
         *
         * @var <array>
         */
        
    private $arrWhereConditions     = array();

        
    /**
         *
         *
         * @var <array>
         */
        
    private $arrOrderByConditions   = array();

        
    /**
         *
         *
         * @var <array>
         */
        
    private $arrGroupByConditions   = array();

         
    /**
          *
          *
          * @var <array>
          */
         
    private $arrBlocks             = array();

         
    /**
          *
          *
          * @var <array>
          */
         
    private $arrConnectors         = array();

        
    /**
         *
         *
         * @var <integer>
         */
        
    private $intElementsCount       0;

        public function 
    __get($strKey)
        {
            
    $blnSuccess false;

            switch (
    $strKey)
            {
                case 
    'or':
                case 
    'xor':
                case 
    'and':
                    
    $this->arrConnectors[$this->intElementsCount 1] = mb_strtoupper($strKey);

                    
    $blnSuccess true;
                    break;

                case 
    'blockStart':
                    
    $this->arrBlocks[$this->intElementsCount 1] = '(';
                    
                    
    $blnSuccess true;
                    break;

                case 
    'blockEnd':
                    
    $this->arrBlocks[$this->intElementsCount 1] = ')';
                    
                    
    $blnSuccess true;
                    break;
            }

            if (
    $blnSuccess === true)
            {
                ++
    $this->intElementsCount;
            }

            return (
    $this);
        }

        
    /**
         *
         *
         * @param <string>              $strTableName   Tabellenname
         * @param <string|optional>     $strAliasName   Tabellenalias
         *
         * @return <object>
         */
        
    public function addTable($strTableName$strAliasName null)
        {
            
    $strTable '';
            
            if (!empty(
    $strTableName) &&
                
    is_string($strTableName))
            {
                
    $strTable '`' $strTableName '`';
            }

            if (!empty(
    $strTable) &&
                !empty(
    $strAliasName) &&
                
    is_string($strAliasName))
            {
                
    $strTable .= ' AS `' $strAliasName '`';
            }

            if (!empty(
    $strTable))
            {
                
    $this->arrTables[] = $strTable;
            }
            return (
    $this);
        }

        
    /**
         *
         *
         * @param <string>              $strFieldName               Feldname
         * @param <string|optional>     $strFieldAlias              Feldalias
         * @param <string|optional>     $strFieldFunction           Funktionsname
         * @param <string|optional>     $strFieldFunctionArguments  Funktionsargumente
         *
         * @return <object>
         */
        
    public function addField($strFieldName$strFieldAlias null$strFieldFunction null$strFieldFunctionArguments null)
        {
            
    $strField '';
            
            if (empty(
    $strFieldFunction))
            {
                
    $strField '`' $strFieldName '`';
            }
            else if (!empty(
    $strFieldFunction))
            {
                
    $arrValidFunctions = array
                (
                    
    'DATE_FORMAT'
                
    );     
            }

            if (!empty(
    $strField) &&
                !empty(
    $strFieldAlias))
            {
                
    $strField .= ' AS `' $strFieldAlias '`';
            }

            if (!empty(
    $strField))
            {
                
    $this->arrFields[] = $strField;
            }

            return (
    $this);
        }

        public function 
    addWhere($strField$strCondition$mixValue)
        {
            
    $this->arrWhereConditions[$this->intElementsCount 1] = '`' $strField '` ' $strCondition ' ' $mixValue;

            ++
    $this->intElementsCount;
            
            return (
    $this);
        }

        
    /**
         *
         *
         * @param <string>              $strOrderByName     Feldname
         * @param <string|optional>     $strOrderBySort     Sortierreihenfolge
         *
         * @return <object>
         */
        
    public function addOrderBy($strOrderByName$strOrderBySort 'desc')
        {
            
    $strOrderBy '';

            if (!empty(
    $strOrderByName) &&
                
    is_string($strOrderByName))
            {
                
    $strOrderBy '`' $strOrderByName '`';
            }

            if (!empty(
    $strOrderBy) &&
                !empty(
    $strOrderBySort) &&
                
    in_array($strOrderBySort, array('asc''desc')))
            {
                
    $strOrderBy .= ' ' mb_strtoupper($strOrderBySort);
            }

            if (!empty(
    $strOrderBy))
            {
                
    $this->arrOrderByConditions[] = $strOrderBy;
            }

            return (
    $this);
        }

        
    /**
         *
         * 
         * @param <sring>   $strGroupByName     Feldname
         *
         * @return <object>
         */
        
    public function addGroupBy($strGroupByName)
        {
            
    $strGroupBy '';
            
            if (!empty(
    $strGroupByName) &&
                
    is_string($strGroupByName))
            {
                
    $strGroupBy '`' $strGroupByName '`';
            }

            if (!empty(
    $strGroupBy))
            {
                
    $this->arrGroupByConditions[] = $strGroupBy;
            }

            return (
    $this);
        }

        private function 
    generateStatement()
        {
            
    $strTables implode(', '$this->arrTables);
            
    $strFields implode(', '$this->arrFields);

            
    $strWhere '';

            
    $arrWhereKeys   array_merge(array_keys($this->arrWhereConditions), array_keys($this->arrBlocks), array_keys($this->arrConnectors));
            
    $arrWhereValues array_merge($this->arrWhereConditions$this->arrBlocks$this->arrConnectors);

            
    $arrWhereCondition array_combine($arrWhereKeys$arrWhereValues);

            
    ksort($arrWhereCondition);

            
    $strWhere implode(' '$arrWhereCondition);

            
    $strGroupBy implode(', '$this->arrGroupByConditions);

            
    $strOrderBy implode(', '$this->arrOrderByConditions);

            
    $strQuery $strFields ' FROM ' $strTables;

            if (!empty(
    $strWhere))
            {
                
    $strQuery .= ' WHERE ' $strWhere;
            }

            if (!empty(
    $strGroupBy))
            {
                
    $strQuery .= ' GROUP BY ' $strGroupBy;
            }

            if (!empty(
    $strOrderBy))
            {
                
    $strQuery .= ' ORDER BY ' $strOrderBy;
            }

            return (
    $strQuery);
        }

        public function 
    getQuery($blnForceGenerate false)
        {
            static 
    $strStatement;

            if (empty(
    $strStatement) ||
                
    $blnForceGenerate === true)
            {
                
    $strStatement $this->generateStatement();
            }

            return (
    $strStatement);
        }

    Der Aufruf sieht beispielsweise so aus.

    PHP-Code:
    $SQLAssembler = new SQLAssembler();

    $SQLAssembler   ->addField('Id')
                    ->
    addField('Title''NewTitle')
                    ->
    addTable('tabelle1''tabelleas1')
                    ->
    addTable('tabelle2')
                    ->
    addWhere('Id''='5)
                    ->
    and
                        
    ->blockStart
                        
    ->blockStart
                            
    ->addWhere('Name''!=''name1')
                                ->
    or
                            
    ->addWhere('Name''!=''name2')
                        ->
    blockEnd
                        
    ->xor
                        
    ->blockStart
                            
    ->addWhere('Name''!=''name3')
                                ->
    or
                            
    ->addWhere('Name''!=''name4')
                        ->
    blockEnd
                        
    ->blockEnd
                    
    ->addGroupBy('Id')
                    ->
    addOrderBy('Name''asc')
                    ->
    addOrderBy('Id''desc'); 
    Ich habe mir in letzter Zeit angewöhnt das ich immer erst alle Daten sammel und dann verarbeite. In diesem Falle wäre es meiner Meinung nach "einfacher" wenn ich bei jeden Methodenaufruf ein String erweitere.

    Was ist eure Meinung nach sauberer? Erst Daten sammeln und dann verarbeiten oder sofort Daten verarbeiten?


  • #2
    Ehrlich gesagt, ich finde das mega-häßliche und sehe auch Null vorteile gegenüber einem einfachen String-Statement. Kann mir auch nur schwer vorstellen, dass sowas
    PHP-Code:
    ->or
      
    ->addWhere('Name''!=''name2'
    funktioniert. Mal davon abgesehen, dass Du bspw. Klammerebenen oder komplexe Ausdrücke damit nicht umsetzen kannst.

    Ganz ehrlich - wer soll so eine Klasse benutzen?
    --

    „Emoticons machen einen Beitrag etwas freundlicher. Deine wirken zwar fachlich richtig sein, aber meist ziemlich uninteressant.
    Wenn man nur Text sieht, haben viele junge Entwickler keine interesse, diese stumpfen Texte zu lesen.“


    --

    Kommentar


    • #3
      Ich persönlich muss sagen, dass ich es viel zu umständlich finde so ein Megakonstrukt zu benutzen, wenn man es auch viel einfacher haben kann.
      Einfache SQL-Kommandos so zu bauen wäre vllt noch ok, aber sobald JOIN und verschachtelte Bedingungen zusammenkommen muss ich mit so einer Klasse 30 Zeilen lang ein SQL-Statement zusammenbauen obwohl als normales "von-Hand-schreiben" übersichtlicher, schneller, einfacher geht.

      Also nichts für mich...

      Grüße
      Signatur:
      PHP-Code:
      $s '0048656c6c6f20576f726c64';
      while(
      $i=substr($s=substr($s,2),0,2))echo"&#x00$i;"

      Kommentar


      • #4
        Der einzige Mehrwert ist doch, dass man die Klasse unabhängig vom Backend (Datenbank o.ä.) benutzen kann...
        P of EAA: Query Object

        Allerdings hat deine Klasse imo überhaupt keinen Sinn, weil du dich viel zu wenig vom SQL Syntax löst bzw. das Statement nicht hinreichend abstrahierst...


        Aber irgendwie meine ich diese Diskussion erst neulich hier im Forum gelesen zu haben...

        Kommentar


        • #5
          Mal abgesehen davon, dass so etwas elementares wie limit gar nicht implementiert ist. @TE: Mal ehrlich, meinst Du, Du fährst besser mit diesem Konstrukt, ein Statement zusammen zu bauen, als es einfach in einen String zu schreiben? Man muss nicht aus allem ein Objekt machen, nur weil man es kann..

          Mit den selfmade-ORMs, das scheint irgendwie wieder zuzunehmen - Warum benutzt man nicht, wenn schon, ein bereits vorhandenes? Es gibt sie in zig Ausführungen..

          Kommentar


          • #6
            Was mir nicht gefällt:

            Von der IDE hinzugefügte Kommentare die nicht genützt werden.
            Entweder ausschalten oder benützen, aber so nicht

            Kommentar


            • #7
              Was meinst DU?
              --

              „Emoticons machen einen Beitrag etwas freundlicher. Deine wirken zwar fachlich richtig sein, aber meist ziemlich uninteressant.
              Wenn man nur Text sieht, haben viele junge Entwickler keine interesse, diese stumpfen Texte zu lesen.“


              --

              Kommentar


              • #8
                Die Angaben zu dem Typ von Parameter und return Werten ist doch schon fast ausreichend. Klar wäre nen Kommentar noch praktisch aber für den Editor ist es schon mal sehr nützlich wenn die return Typen bekannt sind.

                Kommentar


                • #9
                  @stayInside: was möchtest du eigentlich bezwecken? Ist ist sicher eine schöne Fingerübung eine SQL-Abstraktion in Code auszuformulieren aber wozu? Mein Ansatz wäre hier eine Ebene höher anzusiedeln, nämlich "echte" Strukturen aus der Datenbank per Parametrisierung beziehen zu können. Der Generic O/R Mapper des APF beispielsweise kann Objekte und Beziehungen per definierter API aus der Datenbank laden. Sofern Parameter mitgegeben werden müssen - z.B. die Einschränkung auf Attribute - kann das mit einem Criterion-Objekt erledigt werden. Das ist für meinen Geschmack eine Abstraktion, die dir auch wirklich nützt. Statt diversen Zeilen SQL kannst du da z.B. per

                  PHP-Code:
                  $crit = new GenericCriterionObject();
                  $crit->addOrderIndicator(...);
                  $entries $gb->loadRelatedObjects('entries',$crit); 
                  die Einträge eines Gästebuchs laden. Inhalt des generierten Statements sind 2 JOINs und diverse WHERE-Bedingungen nebst einem ORDER. Formuliere ich Criterion das nach deinem Verfahren aus, ist das sicher nicht so übersichtlich.

                  Du musst sich also immer fragen, ob das Vorgehen wirklich einen Mehrwert für dich schafft oder einfach nur nett ist.
                  Viele Grüße,
                  Dr.E.

                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                  1. Think about software design before you start to write code!
                  2. Discuss and review it together with experts!
                  3. Choose good tools (-> Adventure PHP Framework (APF))!
                  4. Write clean and reusable software only!
                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

                  Kommentar


                  • #10
                    Zitat von ByStones Beitrag anzeigen
                    Ich persönlich muss sagen, dass ich es viel zu umständlich finde so ein Megakonstrukt zu benutzen, wenn man es auch viel einfacher haben kann.
                    Einfache SQL-Kommandos so zu bauen wäre vllt noch ok, aber sobald JOIN und verschachtelte Bedingungen zusammenkommen muss ich mit so einer Klasse 30 Zeilen lang ein SQL-Statement zusammenbauen obwohl als normales "von-Hand-schreiben" übersichtlicher, schneller, einfacher geht.

                    Also nichts für mich...

                    Grüße
                    Ich sehe das genauso. Da kann man gleich den SQL-Befehl selbst schreiben. Zumal es solche (Anm.: wie ich finde bessere) Lösungen etwa mit CakePHP schon gibt. Und ich denke an der Stelle muß man ja nicht zwingend das Rad noch mal erfinden.

                    Kommentar


                    • #11
                      Zend Framework: Documentation: Zend_Db_Select - Zend Framework Manual

                      PHP-Code:
                      $where $db->quoteIdentifier("id") . " = " $db->quote($_GET["id"]);
                      $cond $db->quoteIdentifier("table.id") . " = " $db->quoteIdentifier("another_table.fk_table");

                      $db->select()
                        ->
                      from("table", array("alias_for" => "column"))
                        ->
                      joinInner("another_table"$cond, array("another_column"))
                        ->
                      where($where)
                        ->
                      order("CREATED DESC")
                        ->
                      limitPage(110
                      Bedingungen würde ich niemals abstrahieren.
                      "Mein Name ist Lohse, ich kaufe hier ein."

                      Kommentar


                      • #12
                        Zitat von Chriz Beitrag anzeigen
                        PHP-Code:
                        $where $db->quoteIdentifier("id") . " = " .  $db->quote($_GET["id"]);
                        #...
                        $db->select()
                        #...
                          
                        ->where($where)
                        #... 
                        Kriegt man das net im Zend-Framework auch einfacher?
                        PHP-Code:
                          ->where("id = ?"$_GET['id']) 
                        "My software never has bugs, it just develops random features."
                        "Real programmers don't comment. If it was hard to write, it should be hard to understand!"

                        Kommentar


                        • #13
                          Das kann sein, Problem ist, dass dann immer gequotet wird, auch wenn ein Zahlenwert übergeben wird. Eine DB im strict-Mode lässt dann das ganze Query möglicherweise abschmieren (String-Vergleich auf Zahlenspalte). Deshalb schreib ich das Query lieber selbst, auch weil ich die restlichen Bedingungen (WHERE IN, oder Join-Conditions) sowieso selbst bauen muss. Und dann mach ichs lieber strikt in einer Variante.

                          Eigentlich schreiben würde ich beim Query oben also .. " = " . (int)$_GET["id"]

                          Aber ist wie immer Geschmackssache, where("id = ?", (int)$_GET["id"]) geht soweit ich weiß ja selbst im strict-Modus, weil der Stringwert ja einen numerischen Wert darstellt.
                          "Mein Name ist Lohse, ich kaufe hier ein."

                          Kommentar


                          • #14
                            Zitat von Paul.Schramenko Beitrag anzeigen
                            Kriegt man das net im Zend-Framework auch einfacher?
                            PHP-Code:
                              ->where("id = ?"$_GET['id']) 
                            Welcher Teil ?
                            Der zugriff auf Parameter ?
                            Kann man so im Controller machen:

                            PHP-Code:
                            $this->getRequest()->getParam('id''fallbackvalue'); 
                            Ist nicht wirklich "einfacher", aber man braucht kein isset und kann einen fallback-wert eingeben.
                            robo47.net - Blog, Codeschnipsel und mehr
                            | Caching-Klassen und Opcode Caches in php | Robo47 Components - PHP Library extending Zend Framework

                            Kommentar


                            • #15
                              Ich glaube er meinte mein selbstgebautes $where-Konstrukt. Das mit dem Fallback ist gut, gibt aber keine Typsicherheit.
                              "Mein Name ist Lohse, ich kaufe hier ein."

                              Kommentar

                              Lädt...
                              X