request_url_withoutHTTP=,canonical_url_withHTTP=,canonical_url_withoutHTTP=,request_url_withoutHTTP_realspaces=. MySQL (Seite 1 von 2) « Tags « Blog « Bernhard Häussner
Bernhard Häussner
Tags: Artikel mit dem Tag «MySQL» durchstöbern

My MySQL API onion for PHP

26.07.2009, 17:42
MySQL Onion

MySQL Onion

A huge part of web applications is usually the interaction with the SQL database. This is why I want as little work as possible connecting, escaping values, getting the right tables an so on in PHP. But it should stay simple and allow modular approaches. Therefor I'm using some nested APIs for doing queries easily:

PDO

The very fist thing I am using is PDO. It can handle many RDBMS, but I am most of the times using MySQL or SQLite. By using PDO as an API for the following layers I can make sure most of the code will work for many RDBMSs. PDO even simplifies transactions and prepared statements. Here's some sample PHP code using PDO:

$pdo=new PDO('mysql:host='.$host.';dbname='.$db, $user, $passwort);

$pdo->exec('UPDATE test SET foo="bar" WHERE id=4');

$satement=$pdo->prepare('SELECT * FROM blogeintraege WHERE id=:id');
$satement->bindValue(':id',3,PDO::PARAM_INT);
$satement->execute();
$data=$satement->fetchAll();

PDO Simplifier

The next layer is a class that will hold a MySQL database Connection (a PDO Object) and offer some simple functions for doing e.g. a simple prepared statement. Instead of binding each values manually, you can throw an array in.

It also includes a cache, if you want to run statements more than once. It can append a prefix to all queried tables and checks dynamically inserted tables for validity to avoid SQL-injections and MySQL errors. It is used like that:

$res=$db->sql("SELECT * FROM blogeintraege");
$res=$db->sql(
  "SELECT * FROM #test WHERE id=:id",
  array('id'=>$id),array('id'=>PDO::PARAM_INT),
  array('test'=>'blogeintraege'),
  array('limits'=>array(0,$l),'buffered'=>false)
);

For one array element this does not look too tiny, but the more values are bound, the more useful it gets. And it is very useful if you already have your values in an array, like $_GET.

Note that nearly everything is optional. The table array can contain more tables, for example you can have an array of tables for different languages, if they are in different tables. The bind-types don't need to be specified too. You can even leave out everything except the query as shown in the fist line of code. The Result will by default be returned as a nice array (the GROUP_CONCAT fields are array'ed too) but you can use all other PDO fetch types.

This layer follows a rather functional approve, so I needed another layer for accessing the central sql()-Function in an OOP manner. This should avoid some runtime errors and you can modify the SQL in a modular system.

Statement builder

So I created a wrapper object, that holds a pointer to the database and will construct the parameters for sql(). This comes in handy as more and more optional parameters are added.

The PDO Simplifier has a method to build such statement-objects called sqlO(). This is how the wrapper is used:

$db->sqlO('INSERT INTO blogtaglinks SET ##,type=3')
   ->setSet(array('ID_tag'=>$lasttagid,'ID_entry'=>$id))
   ->exec();
$res=$db->sqlO("SELECT * FROM #test WHERE id=:id")
        ->setData(array('id'=>$id))
        ->setDataTypes(array('id'=>PDO::PARAM_INT))
        ->setTables('test'=>'blogeintraege'),
        ->setLimits(0,$l)
        ->setBuffered(false)
        ->exec();
);

As you can see, it is a little more code, but the code is pretty self-explanatory and now one can build the sets and the other parameters as arrays and then include them easily in the statements.

A bit different: Zend Framework's $db->select() approach

A next step would be to build queries with a single API. This is a feature implemented by the Zend Framework, where you can build your SQL with some API functions and it will even work across various databases:

select = $db->select()
  ->from('blogeintraege',array('id','Titel'))
  ->where('id < ?', $id)
  ->order('id DESC')
  ->limit(0,10);

Well doesn't that look nice?

Kommentare: keine

MySQL-Queries sparen mit GROUP_CONCAT

22.06.2009, 20:10
Ein MySQL-Query mit GROUP_CONCAT

Ein MySQL-Query mit GROUP_CONCAT

Fast jede (Web-)Anwendung, die eine Datenbank wie MySQL benutzt, muss irgendwie das Problem lösen, zu einem Artikel mehrere Tags, zu einem Eintrag mehrere Kommentare, zu einem Wort mehrere Synonyme zu finden, die sich in einer weiteren Tabelle befinden. Jedes Mal, wenn mehrere Zeilen Abgefragt werden sollten, die wieder mehrere untergeordnete Zeilen haben, bedeutet das meistens für jedes Element einen weiteren Query zu starten, oder eine zweite Abfrage mit einer weiteren Liste zu starten, oder eine riesige Reihe Datensätze abzufragen und der Anwendung das Gruppieren zu überlassen. Mit GROUP_CONCAT (Dokumentation) lässt sich in MySQL (fast) alles in ein SQL-Query zusammenfassen.

Einführung

Nehmen wir eine einfache Datenbankstuktur an, wie die eines Blogs. Es gibt blogeintraege mit einem Titel, blogtags mit einem Namen. Dann gibt es noch eine Tabelle, die beides verbindet, z.B. blogtaglinks. Jeder Datensatz hat natürlich eine eindeutige ID. Wenn man jetzt alle Blogeinträge auflisten will, könnte man das wie folgt machen:

SELECT Titel FROM blogeintraege

Um die Anzahl der Verbundenen Tags herauszufinden, wäre ein solcher Join üblich:

SELECT Titel, COUNT(distinct(t.ID))
FROM blogeintraege b, blogtags t, blogtaglinks l
WHERE b.ID = l.ID_entry and t.ID = l.ID_tag
GROUP BY b.ID
+-------------------------+-----------------------+
| Titel                   | COUNT(distinct(t.ID)) |
+-------------------------+-----------------------+
| Hello World!            |                     2 |
| The CMS                 |                     2 |
| To be Released Later... |                     1 |
+-------------------------+-----------------------+
3 rows in set (0.01 sec)

Hier werden jeweils alle Spalten, die den selben Blogeintrag repräsentieren gruppiert und dann aus diesen Gruppen die Anzahl der verschiedenen Tags abgefragt. Dabei ist COUNT die Gruppenfunktion, die die nun versteckten, „weg-gruppierten“, Datensätze verarbeitet - hier zählt.

Die GROUP_CONCAT-Funktion

MySQL und andere RDBMSs kennen für Zahlen einige Funktionen, die Summe, Durchschnitt etc. gruppierter Zahlen berechnen können. MySQL kennt darüber hinaus die GROUP_CONCAT()-Funktion, welche die „versteckten“ Werte (also auch CHAR) in einer Spalte zusammen zu hängen. Mit dieser Funktion wäre es also möglich, die Tags direkt aufzulisten:

SELECT Titel, GROUP_CONCAT(distinct(t.name))
FROM blogeintraege b, blogtags t, blogtaglinks l
WHERE b.ID = l.ID_entry and t.ID = l.ID_tag
GROUP BY b.ID
+-------------------------+---------------------------------+
| Titel                   | GROUP_CONCAT(distinct(t.name))  |
+-------------------------+---------------------------------+
| Hello World!            | Projekt: Mein Blog,Persönliches |
| The CMS                 | PHP,Projekt: Mein Blog          |
| To be Released Later... | Projekt: Mein Blog              |
+-------------------------+---------------------------------+
3 rows in set (0.00 sec)

Jetzt wird anstatt der Anzahl der Tags eine Komma-getrennte Liste der Tags angezeigt. Das ist insofern ein recht großer Fortschritt, da wir nicht nochmal eine zweite Abfrage machen müssen, die uns jeweils die Namen der Tags heraus sucht.

Weiter Ausbauen

Jetzt wird es Zeit ein bisschen zu Optimieren. In diesem Beispiel macht es wenig Sinn, aber theoretisch könnten zwei Tags den gleichen Namen haben. In diesem Fall würde uns MySQL aber den Namen nur einmal anzeigen, da distinct() doppelte Werte aussortiert. Wir würden also weniger Tags bekommen, als ein COUNT(distinct(t.ID)) anzeigt. Das können wir lösen, indem wir die distinct()-Funktion auf die IDs der Tags anwenden:

SELECT Titel, GROUP_CONCAT(distinct(t.ID),'-', t.name)
FROM blogeintraege b, blogtags t, blogtaglinks l
WHERE b.ID = l.ID_entry and t.ID = l.ID_tag
GROUP BY b.ID

Das würde uns für jeden Blogeintrag eine Liste erstellen, wie 42-Webbrowser,28-Productivity,27-Design. Die eigentlich überflüssigen IDs werden später noch entfernt, z.B. mit PHP.

Wenn wir zusätzlich noch die Erstellungsdaten z.B. der letzten drei Kommentare abfragen wollen, zeigt sich, warum wir distinct() verwenden müssen: Sonst wird jeder Tag so oft angezeigt, je nach dem, wie viele Kommentare ein Eintrag hat. Wenn wir also noch eine Tabelle benutzen, wie blogkommentare mit creation_time, und uns jeweils die letzten Erstellungszeiten anzeigen lassen wollen, benutzen wir:

SELECT Titel, GROUP_CONCAT(distinct(t.ID),'-', t.name), 
GROUP_CONCAT(distinct(c.ID),'-',c.creation_time ORDER BY creation_time DESC)
FROM blogeintraege b, blogtags t, blogtaglinks l, blogkommentare c
WHERE b.ID = l.ID_entry and t.ID = l.ID_tag and c.entry_id = b.id
GROUP BY b.ID

Jetzt haben wir noch eine weitere Spalte mit einem Wert, wie 34-2008-10-20 18:28:41,33-2008-10-19 23:22:37. Doch je mehr Spalten wir abfragen, desto unübersichtlicher werden die Listen. Außerdem hängt ja immer noch die ungewollte, aber doch notwendige id davor.

Verarbeitung mit PHP

Diese minderen kosmetischen Makel lassen sich dann in der Anwendung noch beheben. Hier zeige ich, wie ich mit PHP die Listen in Arrays lade und sortiere:

function arrayifyGrpConcats($q,$resultset) {
  $regexp='/\\bgroup_concat\\((.*?) separator \'(?<sep>.*?)\'\\) +as +(?<name>\w+)\\b/i';
  if ( preg_match_all($regexp,$q,$matches,PREG_SET_ORDER) ) {
    foreach ($matches as $grpCoClause) {
      if (isset($grpCoClause["name"],$grpCoClause["sep"])) {
        $name=$grpCoClause["name"];
        if (strpos($name,'_',1)===false) {
          $foldername=$name;
          $subname=false;
        } else {
          $foldername=substr($name,0,strpos($name,'_',1));
          $subname=substr($name,strpos($name,'_',1)+1);
        }
        $s=$grpCoClause["sep"];
        foreach ($resultset as $id=>$row) {
          $val=$row[$name];
          unset($resultset[$id][$name]);
          if ($subname) {
            if (!isset($resultset[$id][$foldername])) {
              $resultset[$id][$foldername]=array();
            }
            $vals=explode($s,$val);
            for ($i=0, $len=count($vals);$i<$len;$i++) {
              if (!isset($resultset[$id][$foldername][$i])) {
                $resultset[$id][$foldername][$i]=array();
              }
              $resultset[$id][$foldername][$i][$subname]=preg_replace('/\\d+-/','',$vals[$i],1);
            }
          } else {
             $resultset[$id][$foldername]=explode($s,$val);
          }
        }
      }
    }
  }
  return $resultset;
}

Diese Funktion kann direkt nach der Abfrage auf die Ergebnisse angewendet werden. Dazu übergibt man ihr das Result als durchnummeriertes Array mit je einem assoziativen Unterarray (Dictionary) pro Datensatz, der als Schlüssel die Spaltennamen und als Werte den jeweiligen Spaltenwert enthält. Die Funktion sucht dann im Query nach GROUP_CONCAT-Aufrufen der From group_concat(... separator ',') as iwas. Das Trennsymbol wird explizit angegeben, damit es hier keine Missverständnisse gibt.

Man sollte bedenken, dass MySQL mit dem Separator im Wert nichts macht. Wie man im SQL sieht habe ich das Problem mit dem Trennzeichen im Wert „gelöst“, indem ich es aus dem Kommentartext einfach gelöscht habe. Eine ausgefeiltere Methode habe ich bei stackoverflow gefunden.

Als Alias nach as kann man fast alles angeben. Die Funktion wird diesen Namen als Spaltennamen im Result-Array verwenden.

Als kleines Extra habe ich noch eingebaut, dass die Funktion optional mehrere Spalten zusammen nimmt, wenn sie ein Alias der Form gruppe_name erkennt: Sie wird dann im Resultset-Array unter gruppe ein nummeriertes Array anlegen, das ein assoziatives Arrays enthält mit den verschieden name. Wenn wir also zu einem Kommentar nicht nur das Datum, sondern auch den Autor wissen wollen, könnten wir group_by... as comm_time, group_by... as comm_name verwenden, um die Daten für jeden Kommentar zusammen zu halten.

Im Endeffekt kann das dann so aussehen:

SELECT b.id, b.Titel AS Titel,
group_concat(DISTINCT t.ID,'-', t.name separator ', ') as tags_Name, 
group_concat(DISTINCT t.id separator ', ') as tags_id, 
group_concat(DISTINCT c.ID,'-',c.creation_time separator ', ') as comm_time, 
group_concat(DISTINCT c.ID,'-',REPLACE(LEFT(c.Text,20),',','') 
     separator ', ') as comm_text 
FROM blogeintraege b, blogtaglinks l, blogtags t, blogkommentare c
WHERE b.ID = l.ID_entry and t.ID = l.ID_tag and c.entry_id=b.id
GROUP BY b.ID LIMIT 1,2

Was uns dann dieses Ergebnis liefert: (print_r)

Array
(
    [0] => Array
        (
            [id] => 2
            [Titel] => The CMS
            [tags] => Array
                (
                    [0] => Array
                        (
                            [Name] => PHP
                            [id] => 3
                        )

                    [1] => Array
                        (
                            [Name] => Projekt: Mein Blog
                            [id] => 2
                        )

                )

            [comm] => Array
                (
                    [0] => Array
                        (
                            [time] => 2008-10-19 23:22:37
                            [name] => Bernhard H.
                            [text] => Also das Kommentarsy
                        )

                    [1] => Array
                        (
                            [time] => 2008-10-20 18:28:41
                            [name] => Bernhard H.
                            [text] => So ich hab es jetz 
                        )

                )

        )

    [1] => Array
        (
            [id] => 10
            [Titel] => To be Released Later...
            [tags] => Array
                (
                    [0] => Array
                        (
                            [Name] => Projekt: Mein Blog
                            [id] => 2
                        )

                )

            [comm] => Array
                (
                    [0] => Array
                        (
                            [time] => 2008-10-20 19:48:50
                            [name] => Bernhard H.
                            [text] => Cool das klappt auc
                        )

                )

        )

)

Ich hoffe mit dieser Methode in Zukunft Datenbankabfragen zu vermindern und damit die Geschwindigkeit der Anwendungen weiter zu erhöhen. Zwei kleine Sachen noch:

SELECT @@group_concat_max_len

Dieser Wert ist die maximale Länger der mit GROUP_CONCAT gebildeten Spaltenwerte und lieget meist bei 1024. Außerdem kann es nötig sein den Spaltenwerte von BLOB zu konvertieren: CAST(... as CHAR).

Kommentare: keine

Umstellung auf PHP Data Objects mit Prepared Statements

10.01.2009, 09:52
PDO and Prepared Statements

PDO and Prepared Statements

Da ich die letzte Zeit offline war (und bald eine rund 15x schnellere Internet-Verbindung habe) konnte ich am Computer recht wenig machen. Deshalb habe ich ein bisschen an dieser Webseite gebastelt und die Datenbank-Verbindung auf PHP Data Objects (PDO) umgestellt. Diese unterstützen Prepared Statements, wo eine SQL-Abfrage schon geparsed werden kann, bevor konkrete Werte eingesetzt wurden, was sowohl der Sicherheit (keine SQL-Injections möglich) als auch dem Reccourcen-Verbrauch (Unveränderliches wird geparsed und gespeichert) zugute kommt.

Ich konnte mit der Umstellung auch gleich meine interne Datenverbindung zu den Views von einem Gemisch aus MySQL-Resultsets und Arrays auf nur Arrays umstellen, sodass die Views jetzt nicht mehr Umgeschrieben werden müssen, falls der PHP-Controller auch die Daten ändern will, wie zum Beispiel bei der Suche, wo die Reihenfolge der Ergebnisse von PHP berechnet wird. Da die MySQL-Abfragen dennoch optimiert sind, werden diese Arrays auch nicht zu groß.

Die Umsetzung der PDOs war nicht ganz einfach, zumal die (unvollständige) Datenbankabstraktion mehr oder weniger abwärtskompatibel sein sollte aber zusätzlich einiges an Automatik beinhalten sollte. So cacht sie jetzt nur SELECT-Abfragen, und gibt je nach Abfrage-Art (SELECT, INSERT, UPDATE) das Resultset, die Insert-ID oder die Anzahl der upgedateten Datensätze zurück. Sie verwaltet selbst die Prepared Statements, sodass nichts doppelt präpariert wird, überlässt mir damit also die Fütterung mit beliebigem SQL und kümmert sich um den Rest.

Da die PDOs auch eine relativ einfache Umsetzung von Transactions mitliefern, überlege ich mir, ob ich auch noch diese automatisch laufen lasse, jedoch habe ich noch kaum Erfahrung mit Transactions, weshalb ich damit erst nicht etwas beschäftigen muss (Rollbacks, SELECTs etc.).

Kommentare: keine

MySQL von außen via SSH-Tunnel (und KDE GUI)

28.12.2008, 17:04
Lokaler MySQL-Client 
    |
    |
(verschlüsselte SSH-Verbindung)
    |
    v
MySQL-Server

Als Web-Administrator braucht man oft Zugang zu einem MySQL-Server. Das kann man mit phpMyAdmin machen, doch das ist kaum so sicher und weniger komfortabel wie remote-Zugriff über einen SSH-Tunnel.

Was kann der SSH-Tunnel und wie geht das?

En SSH-Tunnel macht, dass, wenn auf den eigenen Rechner von einem Port zugegriffen wird, dann die Packete über die verschlüsselte SSH-Verbindung von dem Verbundenen Rechner (Gateway) aus wieder an einen Rechner weitergeleitet werden. Der Befehl sieht so aus:

ssh -L lokalerport:zielrechner:zielport sshgatewaylogin@gateway

Siehe auch das Diagramm:

Irgendwer 
    |
    |
(Lokaler Port)
    |
    v
Mein Computer
    |
    |
(verschlüsselte SSH-Verbindung)
    |
    v
Gateway, eingeloggt als SSH-Gateway-Login
    |
    |
(Zielport)
    |
    v
Zielrechner

Im Fall MySQL greife nur ich über irgendeinen Port auf meinen Computer zu. Der Gateway-Rechner und Zielrechner sind der MySQL-Server und der greift auf sich selbst zu und zwar über den MySQL-Port (Standard: 3066). Dann sieht das ungefähr so aus:

ssh -L 7777:127.0.0.1:3306 me@mysqlserver -N -f

In Verbindung mit MySQL am besten immer 127.0.0.1 verwenden, das vermeidet Ärger. Das praktische ist nun, dass man MySQL-Clients auf den eigenen Rechner nun mit der Datenbank auf dem Server verwenden kann. Solche Clients sind z.B. der MySQL-Abfrage-Browser oder der MySQL-Administrator oder sogar ein PHP-Skript, das auf dem eigenen Rechner läuft. Man kann damit also nicht nur die Datenbank mit einem schönen GUI verwalten, sondern auch PHP-Skripte, Templates o.ä. auf dem eigenen Rechner testen, nur eben mit der Datenbank auf dem Server. Das ist besonders praktisch, wenn man in einem nicht-lokalen Team zusammenarbeitet, da dann alle auf eine zentrale (Development-)Datenbank zugreifen und nicht jeder ständig seine Datenbank synchronisieren muss. (Außerdem muss nicht jeder einen MySQL-Server installieren. )

Wie man das verwendet ist auf tsunamihost.ch sehr gut beschrieben, für Windows und unixoide Systeme. Es findet sich sogar ein kleines Script für init.d um den Tunnel bei jedem Systemstart zu aktivieren.

(Update 2010-11-21) Um zum Beispiel ein MySQL-Dump über den SSH-Tunnel auf einen entfernten Datenbankserver aufzuspielen genügt dann dieser Befehl:

cat local_path/to/dump.sql | \
   mysql -u db_user -p -P 7777 -h 127.0.0.1 db_schema

Es ist hier wichtig als Host 127.0.0.1 anzugeben, da sonst eine lokale Socket-Verbindung genutzt wird. Und natürlich den Port, über den der Tunnel läuft. (/Update)

Ich will mir keine Befehle und Ports merken und habe KDE

Dann habe ich noch ein kleines Script im Angebot: Es lässt sich z.B. im Startmenü verknüpfen und wenn man es anklickt öffnet sich ein Dialog, der fragt, ob der MySQL-Tunnel benötigt wird. Ein klick auf „Ja“ und der Tunnel wird gestartet bzw. läuft weiter oder ein Klick auf "Nein" und der Tunnel wird, sollte er laufen, gestoppt. Einfacher geht es nicht, oder? Das Sktipt braucht KDE, da es kdialog verwendet und steht hier zum Download bereit:

Kurz die Konfiguration bearbeiten und in den Ordner ~/bin verschieben und der Tunnel kann jederzeit gestartet werden.

Da das Tunnel Aufbauen von meiner Server Management Software YaSvenT erledigt wird, benutze ich inzischen das Sktipt allerdings fast nicht mehr

Kommentare: keine

Kate - mein geliebter Editor

27.10.2008, 22:54

Man hat als (Web-)Developer ja immer ein bisschen das Problem sich eine geeignete Arbeitsumgebung zu schaffen, weil es einfach nicht „die“ IDE gibt. Als Ruby on Rails Benutzer hat man die Wahl zwar sehr leicht, wenn man sehr ausgefallen ist und Java verwendet, führt fast nichts an Eclipse vorbei, doch ich bleibe lieber bei PHP. Und da ist der Markt irgendwie sehr unübersichtlich:

Natürlich zählen Subversion, CVS, vi, Apache und MySQL ganz gut zur Entwicklungsumgebung, aber ich will hier eher auf das Programm eingehen, das man am häufigsten braucht: Den Code-Editor.

Um PHP zu entwickeln kann man natürlich auf die - meist rudimentären - Möglichkeiten des ein oder anderen HTML-Editors zurückgreifen. Nur ist für mich ein HTML-Editor nicht mehr so aktuell, da ich HTML irgendwie fast im Schlaf beherrsche. Ich will nicht mehr unbedingt die Buttons für Überschriften usw. , oder gar einen WYSIWYG-Editor. Denn heutzutage braucht man für das Layout fast nur divs und den Content kann man ja dann wieder mit dem HTML-Editor oder im CMS basteln... wenn man will.

Dann gibt es natürlich auch diverse spezielle PHP-Editoren mit nettem Syntax-Highlighting und erweiterten Ersetzungs-Features. Diese sind teilweise mit Datei-Outlining, Projektverwaltung und ähnlichem Schickschnack voll gepackt, dass sie schon fast überladen wirken. Die Spitze des Eisbergs bildet hier wohl das hochwertige Programm UltraEdit, das auch gleich noch FTP-Client, SQL-Tools und viele weitere Features oben drauf setzt.

Jedoch sind diese PHP-Editoren kaum noch zu gebrauchen, wenn man etwas anderes als PHP, HTML usw. machen will. Hier kommt dann Kate ins Spiel. Der erweiterte KDE-Editor kann die Syntax von fast allen denkbaren Programmier- und Auszeichnungssprachen, farblich hervorheben. Darunter HTML, XML, PHP, SQL (sogar MySQL/PostgreSQL-spezifisch), Apache-Konfiguration, CSS, JavaScript, und ausgefallenes wie MediaWiki. Hinter Kate steckt also ein sehr allgemeiner Ansatz. Damit kommt einher, dass man leider auf direkte Implementierung für FTP-Client, Dokument-Outline oder anderes sehr PHP-spezifisches verzichten muss.

Doch das wird eigentlich recht schnell mit der Terminal-Funktion ausgehebelt. Über diese lassen sich dann letztendlich auch SVN oder CVS und eigentlich alle Kommandozeilenprogramme benutzten. Das Terminal cd"ed auch automatisch in den Ordner der gerade offenen Datei.

Das Terminal ist aber nur ein Beispiel, wie sich Kate perfekt in KDE bzw. „Linux“ integriert. Man kann auch Datei-übergreifend suchen und in einer Sidebar in Ordnern browsen. Achja, diese „Ordner“ beinhalten natürlich auch FTP, Webdav, Zip- und komprimierte Tar-Archive, sowie weitere Protokolle. Eben alle Protokolle, die z.B. Konqueror durch die KIO-Slaves auch kann. Dank SFTP kann man sogar auf Servern arbeiten, wo man nur ssh-Zugriff hat, das bedeutet nie wieder Putty- oder CLI-Herumirren.

Natürlich hat Kate auch sonst fast alle Funktion, die man sich so wünschen kann. In Tabs oder der Sidebar können mehrere Dokumente offen sein, an denen man parallel arbeiten kann und die alle gleichzeitig gespeichert werden können. Die offenen Dokumente werden dann in der Sitzung gespeichert. Auch Rechtschreibprüfung, auto-Vervollständigung, automatische Einrückung (mehrere Stile), und Ersetzen mit regulären Ausdrücken gehören zum Editor.

Besonders hilfreich ist auch immer die Integration mit Klipper. Klipper ist unter KDE ein Hilfsprogramm für die Zwischenablage. Es merkt sich automatisch den letzten markierten Text, der dann mit mittlerer Maustaste eingefügt werden kann. So ist sehr schnelles Copypaste möglich. Besonders nützlich kommt dann auch die History-Funktion von Kipper: Über eine Einfügen-Taste in der Symbolleiste kann man ein Menü öffnen und von dort aus den letzten markierten Texten wählen. Wenn man also im Internet oder in der Dokumentation recherchiert, markiert man einfach hin und wieder Funktionen oder Codesnippets die vielleicht nützlich sein könnten. Dann kann man sie später, dank Klipper, wieder aus dem Menü wählen und schnell in den eigenen Code einfügen. Das hilft enorm weiter, wenn man viel mit APIs arbeitet, oder mit altem Code, oder die Dokumentation braucht, oder, oder, oder... eigentlich immer.

In Kate habe ich irgendwie meinen perfekten Editor gefunden. Nicht so überladen, allgemein brauchbar. Nur manchmal fehlt eben noch ein bisschen das Eclipse-Feeling:

Als kleiner Ausblick: Ich habe eigentlich noch keinen PHP-Editor gefunden, der Ordentlich auto-Vervollständigen betreibt. Von Eclipse kennt man das ja, dass man fast immer das Vorgeschlagen bekommt, was man eigentlich wollte. Nut mit PHP hat das noch keiner so recht hin bekommen. Die Sichtweite ist irgendwie immer falsch, includes und autoload fast unerreichbar. Die Anzeige der Dakumentation in der Vervollständigung bei Eclipse habe ich auch immer sehr geschätzt. Wie auch immer, man muss immer seine Klassen und Funktionsaufrufe im Kopf haben, was bei großen Projekten mit vielen Includes sehr schnell zum Problem werden kann. Auch das „refractoring“, hier das Projektübergreifende Umbenennen von Variablen, Funktionen etc. kommt manchmal sehr praktisch zur Hand - in Eclipse. Bei Eclipse kann man auch mit klick auf die Variablen/Klassen zu ihrer Deklaration kommen, was sehr viel herum Suchen erspart. Für PHP gibt es derartige „globale Tools“ irgendwie noch kaum. Naja, man kann ja Erweiterungen für Kate schreiben, außerdem ist es OSS.

PS: Wenn ich die Funktion für Bilder im CMS habe, füge ich auch noch ein paar Screenshots ein...

Edit: Die Bilderfunktion ist jetzt da!

Kommentare: 3 Einträge
[ Seite 1 2 ] Nächste Seite »
 
Χρόνογραφ
© 2008-2017 by Bernhard Häussner - Impressum - Login
Kurz-Link zur Homepage: http://1.co.de/