diff --git a/.gitignore b/.gitignore
index 599468937..b7cf21913 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,3 +7,4 @@ documents/
.settings
.project
.buildpath
+bin
diff --git a/cis/private/lehre/pruefung/pruefung.js b/cis/private/lehre/pruefung/pruefung.js
index 55fb18bab..8708d574f 100644
--- a/cis/private/lehre/pruefung/pruefung.js
+++ b/cis/private/lehre/pruefung/pruefung.js
@@ -373,7 +373,7 @@ function showPruefungsDetails(prfId, lvId)
{
var p = e.pruefung;
var l = e.lehrveranstaltung
- $("#prfTyp").html(p.pruefungstyp_kurzbz);
+// $("#prfTyp").html(p.pruefungstyp_kurzbz);
$("#prfMethode").html(p.methode);
$("#prfBeschreibung").html(p.beschreibung);
if(p.einzeln === true)
@@ -689,6 +689,7 @@ function showAnmeldungen(pruefungstermin_id, lehrveranstaltung_id)
function writeAnmeldungen(data)
{
+ console.log(data);
if(data.error === 'false')
{
var terminId = data.result.anmeldungen[0].pruefungstermin_id;
@@ -755,6 +756,7 @@ function writeAnmeldungen(data)
$("#kommentar").empty();
$("#kommentarSpeichernButton").empty();
$("#raumLink").empty();
+ $("#listeDrucken").empty();
messageBox("message", data.errormsg, "red", "highlight", 1000);
}
}
@@ -1091,7 +1093,7 @@ function savePruefungstermin()
unmarkMissingFormEntry();
var studiensemester_kurzbz = $("#studiensemester").val();
var pruefungsfenster_id = $("#pruefungsfenster").val();
- var pruefungstyp_kurzbz = $("#pruefungsTyp").val();
+// var pruefungstyp_kurzbz = $("#pruefungsTyp").val();
var titel = $("#titel").val();
var beschreibung = $("#beschreibung").val();
var methode = $("#methode").val();
@@ -1168,11 +1170,11 @@ function savePruefungstermin()
error = true;
markMissingFormEntry("pruefungsfenster");
}
- if(is_null(pruefungstyp_kurzbz) || is_undefined(pruefungstyp_kurzbz) || is_empty_String(pruefungstyp_kurzbz) || (pruefungstyp_kurzbz === "undefiniert"))
- {
- error = true;
- markMissingFormEntry("pruefungsTyp");
- }
+// if(is_null(pruefungstyp_kurzbz) || is_undefined(pruefungstyp_kurzbz) || is_empty_String(pruefungstyp_kurzbz) || (pruefungstyp_kurzbz === "undefiniert"))
+// {
+// error = true;
+// markMissingFormEntry("pruefungsTyp");
+// }
if(is_null(titel) || is_undefined(titel) || is_empty_String(titel))
{
error = true;
@@ -1188,12 +1190,18 @@ function savePruefungstermin()
error = true;
markMissingFormEntry("methode");
}
-
+
if(lehrveranstaltungen.length === 0)
{
error = true;
markMissingFormEntry("lvDropdowns");
}
+
+ if(is_null(termine) || is_undefined(termine) || is_empty_String(termine))
+ {
+ error = true;
+ markMissingFormEntry("prfTermin");
+ }
if(error)
{
@@ -1209,7 +1217,7 @@ function savePruefungstermin()
method: "savePruefungstermin",
studiensemester_kurzbz: studiensemester_kurzbz,
pruefungsfenster_id: pruefungsfenster_id,
- pruefungstyp_kurzbz: pruefungstyp_kurzbz,
+// pruefungstyp_kurzbz: pruefungstyp_kurzbz,
titel: titel,
beschreibung: beschreibung,
methode: methode,
@@ -1378,7 +1386,7 @@ function loadPruefungsDetails(prfId)
$("#beschreibung").val(result.pruefung.beschreibung);
$("#studiensemester").val(result.pruefung.studiensemester_kurzbz);
$("#pruefungsfenster").val(result.pruefung.pruefungsfenster_id);
- $("#pruefungsTyp").val(result.pruefung.pruefungstyp_kurzbz);
+// $("#pruefungsTyp").val(result.pruefung.pruefungstyp_kurzbz);
$("#methode").val(result.pruefung.methode);
var i = 0;
$("#termin1").closest("tr").remove();
@@ -1491,7 +1499,7 @@ function updatePruefung(prfId)
unmarkMissingFormEntry();
var studiensemester_kurzbz = $("#studiensemester").val();
var pruefungsfenster_id = $("#pruefungsfenster").val();
- var pruefungstyp_kurzbz = $("#pruefungsTyp").val();
+// var pruefungstyp_kurzbz = $("#pruefungsTyp").val();
var titel = $("#titel").val();
var beschreibung = $("#beschreibung").val();
var methode = $("#methode").val();
@@ -1602,11 +1610,11 @@ function updatePruefung(prfId)
error = true;
markMissingFormEntry("pruefungsfenster");
}
- if(is_null(pruefungstyp_kurzbz) || is_undefined(pruefungstyp_kurzbz) || is_empty_String(pruefungstyp_kurzbz) || (pruefungstyp_kurzbz === "undefiniert"))
- {
- error = true;
- markMissingFormEntry("pruefungsTyp");
- }
+// if(is_null(pruefungstyp_kurzbz) || is_undefined(pruefungstyp_kurzbz) || is_empty_String(pruefungstyp_kurzbz) || (pruefungstyp_kurzbz === "undefiniert"))
+// {
+// error = true;
+// markMissingFormEntry("pruefungsTyp");
+// }
if(is_null(titel) || is_undefined(titel) || is_empty_String(titel))
{
error = true;
@@ -1643,7 +1651,7 @@ function updatePruefung(prfId)
pruefung_id: prfId,
studiensemester_kurzbz: studiensemester_kurzbz,
pruefungsfenster_id: pruefungsfenster_id,
- pruefungstyp_kurzbz: pruefungstyp_kurzbz,
+// pruefungstyp_kurzbz: pruefungstyp_kurzbz,
titel: titel,
beschreibung: beschreibung,
methode: methode,
@@ -1807,7 +1815,7 @@ function loadAllPruefungen()
});
tableRow+="";
tableRow += "
| Methode: |
|
diff --git a/cis/private/profile/studienplan.php b/cis/private/profile/studienplan.php
index cf9b3e306..64d85dfdb 100755
--- a/cis/private/profile/studienplan.php
+++ b/cis/private/profile/studienplan.php
@@ -431,7 +431,7 @@ function drawTree($tree, $depth)
echo $icon." ".$termine." lehrveranstaltung_id&language=$sprache','Lehrveranstaltungsinformation','width=700,height=750,resizable=yes,menuebar=no,toolbar=no,status=yes,scrollbars=yes');\">".$row_tree->kurzbz.' - '.$row_tree->bezeichnung."";
else
// Bezeichnung der Lehrveranstaltung
- echo $icon." ".$termine." ".$row_tree->kurzbz.' - '.$row_tree->bezeichnung;
+ echo $icon." ".$termine." ".$row_tree->kurzbz.' - '.$row_tree->bezeichnung.'('.$row_tree->lehrveranstaltung_id.')';
echo $bende.'';
// Semester
@@ -445,6 +445,10 @@ function drawTree($tree, $depth)
echo '';
// Note zu dieser LV vorhanden?
+
+ $lv_kompatibel = new lehrveranstaltung();
+ $kompatibleLVs = $lv_kompatibel->loadLVkompatibel($row_tree->lehrveranstaltung_id);
+
if(isset($noten_arr[$row_tree->lehrveranstaltung_id]))
{
// Positive Note fuer diese LV vorhanden?
@@ -460,6 +464,27 @@ function drawTree($tree, $depth)
else
echo ''.$p->t('studienplan/negativ').'';
}
+ //check if compatible course has grade
+ elseif(count($kompatibleLVs) > 0)
+ {
+ foreach($kompatibleLVs as $komp)
+ {
+ if(isset($noten_arr[$komp]))
+ {
+ $positiv=false;
+ foreach($noten_arr[$komp] as $note)
+ {
+ if($note_pruef_arr[$note]->positiv)
+ $positiv=true;
+ }
+
+ if($positiv)
+ echo ''.$p->t('studienplan/abgeschlossen').'';
+ else
+ echo ''.$p->t('studienplan/negativ').'';
+ }
+ }
+ }
else
{
if($abgeschlossen)
@@ -495,6 +520,19 @@ function drawTree($tree, $depth)
else
$tdinhalt .= ''.$note_pruef_arr[$noten_arr[$row_tree->lehrveranstaltung_id][$stsem]]->anmerkung.'';
}
+ elseif(count($kompatibleLVs) > 0)
+ {
+ foreach($kompatibleLVs as $komp)
+ {
+ if(isset($noten_arr[$komp][$stsem]))
+ {
+ if($note_pruef_arr[$noten_arr[$komp][$stsem]]->positiv)
+ $tdinhalt .= ''.$note_pruef_arr[$noten_arr[$komp][$stsem]]->anmerkung.'';
+ else
+ $tdinhalt .= ''.$note_pruef_arr[$noten_arr[$komp][$stsem]]->anmerkung.'';
+ }
+ }
+ }
else
{
// Angebot der LV und der Kompatiblen pruefen
diff --git a/composer.json b/composer.json
old mode 100644
new mode 100755
index 32278e8dc..a64b8607b
--- a/composer.json
+++ b/composer.json
@@ -5,5 +5,14 @@
"components/bootstrap": "3.3.5",
"michelf/php-markdown": "1.5.0"
+ },
+ "require-dev":
+ {
+ "squizlabs/php_codesniffer": "2.*",
+ "fzaninotto/faker": "1.*"
+ },
+ "config":
+ {
+ "bin-dir": "bin"
}
}
diff --git a/content/fasoverlay.js.php b/content/fasoverlay.js.php
index 7a66b2318..6c969b15a 100644
--- a/content/fasoverlay.js.php
+++ b/content/fasoverlay.js.php
@@ -1766,10 +1766,21 @@ function PrintZutrittskarte()
function PrintStudienblatt(event)
{
var tree = document.getElementById('student-prestudent-tree-rolle');
+ var ss = document.getElementById('statusbarpanel-semester').label;
+
+ var items = tree.view.rowCount;
try
{
- var studienplan_id = getTreeCellText(tree, "student-prestudent-tree-rolle-studienplan_id", 0);
+ var studienplan_id = "";
+ for (var v=0; v < items; v++)
+ {
+ var stsem = getTreeCellText(tree, 'student-prestudent-tree-rolle-studiensemester_kurzbz', v);
+ if(stsem == ss)
+ {
+ studienplan_id = getTreeCellText(tree, 'student-prestudent-tree-rolle-studienplan_id', v);
+ }
+ }
}
catch(e)
{
@@ -1838,7 +1849,7 @@ function PrintStudienblatt(event)
{
if(error>0)
alert(error+' der ausgewaehlten Personen haben keinen Account');
- action = 'content/pdfExport.php?xsl=Studienblatt&xml=studienblatt.xml.php&output='+output+'&&uid='+data;
+ action = 'content/pdfExport.php?xsl=Studienblatt&xml=studienblatt.xml.php&output='+output+'&&uid='+data+"&ss="+ss;
window.open(action,'Studienblatt','height=520,width=500,left=350,top=350,hotkeys=0,resizable=yes,status=no,scrollbars=yes,toolbar=no,location=no,menubar=no,dependent=yes');
}
else
@@ -1853,10 +1864,19 @@ function PrintStudienblatt(event)
function PrintStudienblattEnglisch(event)
{
var tree = document.getElementById('student-prestudent-tree-rolle');
+ var items = tree.view.rowCount;
try
{
- var studienplan_id = getTreeCellText(tree, "student-prestudent-tree-rolle-studienplan_id", 0);
+ var studienplan_id = "";
+ for (var v=0; v < items; v++)
+ {
+ var stsem = getTreeCellText(tree, 'student-prestudent-tree-rolle-studiensemester_kurzbz', v);
+ if(stsem == ss)
+ {
+ studienplan_id = getTreeCellText(tree, 'student-prestudent-tree-rolle-studienplan_id', v);
+ }
+ }
}
catch(e)
{
diff --git a/include/anrechnung.class.php b/include/anrechnung.class.php
index 1e4f6db1e..122e587fa 100644
--- a/include/anrechnung.class.php
+++ b/include/anrechnung.class.php
@@ -186,13 +186,25 @@ class anrechnung extends basis_db
* @param $prestudent_id
* @return true wenn ok, false im Fehlerfall
*/
- public function getAnrechnungPrestudent($prestudent_id)
+ public function getAnrechnungPrestudent($prestudent_id, $lehrveranstaltung_id=null, $lehrveranstaltung_id_kompatibel=null)
{
$qry = "SELECT anrechnung_id, prestudent_id, lehrveranstaltung_id, begruendung_id, bezeichnung AS begruendung, "
. "lehrveranstaltung_id_kompatibel, genehmigt_von , insertamum, insertvon, updateamum, updatevon "
. "FROM lehre.tbl_anrechnung "
. "JOIN lehre.tbl_anrechnung_begruendung USING (begruendung_id) "
. "WHERE prestudent_id = " . $this->db_add_param($prestudent_id);
+
+ if($lehrveranstaltung_id != NULL)
+ {
+ $qry .= " AND lehrveranstaltung_id=".$this->db_add_param($lehrveranstaltung_id);
+ }
+
+ if($lehrveranstaltung_id_kompatibel != NULL)
+ {
+ $qry .= " AND lehrveranstaltung_id_kompatibel=".$this->db_add_param($lehrveranstaltung_id_kompatibel);
+ }
+
+ $qry .= ";";
if ($this->db_query($qry))
{
diff --git a/include/lehrveranstaltung.class.php b/include/lehrveranstaltung.class.php
index 6c163e8df..1c238da44 100755
--- a/include/lehrveranstaltung.class.php
+++ b/include/lehrveranstaltung.class.php
@@ -1258,6 +1258,12 @@ class lehrveranstaltung extends basis_db
if ($obj->bezeichnung_arr['English'] == '')
$obj->bezeichnung_arr['English'] = $obj->bezeichnung_arr['German'];
+ $obj->sws = $row->sws;
+ $obj->lvs = $row->lvs;
+ $obj->alvs = $row->alvs;
+ $obj->lvps = $row->lvps;
+ $obj->las = $row->las;
+
$obj->stpllv_semester = $row->stpllv_semester;
$obj->stpllv_pflicht = $this->db_parse_bool($row->stpllv_pflicht);
$obj->stpllv_koordinator = $row->stpllv_koordinator;
@@ -1312,7 +1318,7 @@ class lehrveranstaltung extends basis_db
}
return $childs;
}
-
+
/**
* Generiert die Subtrees des Lehrveranstaltungstrees
*/
@@ -1335,7 +1341,7 @@ class lehrveranstaltung extends basis_db
{
return false;
}
-
+
}
/**
diff --git a/include/studienordnung.class.php b/include/studienordnung.class.php
index 5a341570c..7a203568f 100644
--- a/include/studienordnung.class.php
+++ b/include/studienordnung.class.php
@@ -155,9 +155,10 @@ class studienordnung extends basis_db
}
else
{
- $qry = 'SELECT sto.*, s.bezeichnung as status_bezeichnung, sem.* FROM lehre.tbl_studienordnung sto
+ $qry = 'SELECT distinct sto.*, s.bezeichnung as status_bezeichnung, sem.* FROM lehre.tbl_studienordnung sto
JOIN lehre.tbl_studienordnungstatus s USING(status_kurzbz)
- LEFT JOIN lehre.tbl_studienordnung_semester sem USING (studienordnung_id)
+ LEFT JOIN lehre.tbl_studienplan USING(studienordnung_id)
+ LEFT JOIN lehre.tbl_studienplan_semester sem USING (studienplan_id)
WHERE studiengang_kz='.$this->db_add_param($studiengang_kz, FHC_INTEGER, false);
if (!is_null($studiensemester_kurzbz))
@@ -200,7 +201,8 @@ class studienordnung extends basis_db
{
$obj->studiensemester_kurzbz = $row->studiensemester_kurzbz;
$obj->semester = $row->semester;
- $obj->studienordnung_semester_id = $row->studienordnung_semester_id;
+ //$obj->studienordnung_semester_id = $row->studienordnung_semester_id;
+ $obj->studienplan_semester_id = $row->studienplan_semester_id;
}
$this->result[] = $obj;
}
diff --git a/rdf/lehrveranstaltungszeugnis_ktu.rdf.php b/rdf/lehrveranstaltungszeugnis_ktu.rdf.php
index cc47cb5dc..b8f4020f9 100755
--- a/rdf/lehrveranstaltungszeugnis_ktu.rdf.php
+++ b/rdf/lehrveranstaltungszeugnis_ktu.rdf.php
@@ -36,6 +36,8 @@ require_once('../include/studienplan.class.php');
require_once('../include/student.class.php');
require_once('../include/prestudent.class.php');
require_once('../include/organisationseinheit.class.php');
+require_once('../include/anrechnung.class.php');
+require_once('../include/lehrform.class.php');
$datum = new datum();
$db = new basis_db();
@@ -152,6 +154,8 @@ if (isset($_REQUEST["xmlformat"]) && $_REQUEST["xmlformat"] == "xml")
$lvbezeichnung = $lehrveranstaltung->bezeichnung;
$lvstg = $lehrveranstaltung->studiengang_kz;
$lehrform_kurzbz=$lehrveranstaltung->lehrform_kurzbz;
+ $lehrform = new lehrform($lehrform_kurzbz);
+ $lehrform_bezeichnung = $lehrform->bezeichnung;
$organisationseinheit = new organisationseinheit($lehrveranstaltung->oe_kurzbz);
$lehreinheit=new lehreinheit();
@@ -309,19 +313,64 @@ if (isset($_REQUEST["xmlformat"]) && $_REQUEST["xmlformat"] == "xml")
$xml .= " ".$datum->formatDatum($benotungsdatum,'d.m.Y')."";
$xml .= " ".$datum->formatDatum($uebernahmedatum,'d.m.Y')."";
$xml .= " ".$lehrform_kurzbz."";
+ $xml .= " ".$lehrform_bezeichnung."";
$xml .= " ".($sws==0?'':number_format(sprintf('%.1F',$sws),1))."";
$xml .= " ".number_format($ects,1)."";
$xml .= " ".$leiter_titel." ".$leiter_vorname." ".$leiter_nachname.($leiter_titelpost!=''?', '.$leiter_titelpost:'')."";
$xml .= " ";
$xml .= " ";
+
$lehrveranstaltung->getLVkompatibel($lehrveranstaltung_id);
foreach($lehrveranstaltung->lehrveranstaltungen as $lv_kompatibel)
{
$xml .= "".$lv_kompatibel->bezeichnung."";
}
+
$xml .= " ";
- $return = $lehrveranstaltung->getLVFromStudienplanByLehrtyp($studienplan_id, "modul");
+ $anrechnung = new anrechnung();
+ $anrechnung->getAnrechnungPrestudent($student->prestudent_id, null, $lehrveranstaltung_id);
+
+ $xml .= "";
+ $lehrveranstaltung_id_kompatibel = "";
+ if(count($anrechnung->result) === 1)
+ {
+ $lehrveranstaltung_id_kompatibel = $anrechnung->result[0]->lehrveranstaltung_id;
+ $xml .= $anrechnung->result[0]->lehrveranstaltung_bez;
+ }
+ $xml .= "";
+
+ $lehrveranstaltung->loadLehrveranstaltungStudienplan($studienplan_id);
+
+ $studienplan_lehrveranstaltung_id = "";
+ foreach($lehrveranstaltung->lehrveranstaltungen as $lv)
+ {
+ if(($lv->lehrveranstaltung_id == $lehrveranstaltung_id) || ($lv->lehrveranstaltung_id == $lehrveranstaltung_id_kompatibel))
+ {
+ $studienplan_lehrveranstaltung_id = $lv->studienplan_lehrveranstaltung_id;
+ break;
+ }
+ }
+
+ $studienplan = new studienplan();
+ if($studienplan_lehrveranstaltung_id != "")
+ {
+ $studienplan->loadStudienplanLehrveranstaltung($studienplan_lehrveranstaltung_id);
+ $lv = new lehrveranstaltung();
+ while($lv->lehrtyp_kurzbz != "modul")
+ {
+ $lv->load($studienplan->lehrveranstaltung_id);
+ $studienplan->loadStudienplanLehrveranstaltung($studienplan->studienplan_lehrveranstaltung_id_parent);
+ }
+ $lehrveranstaltung->lehrveranstaltungen = array(0 => $lv);
+ }
+ else
+ {
+ $lehrveranstaltung->lehrveranstaltungen = array();
+ }
+
+// $return = $lehrveranstaltung->getLVFromStudienplanByLehrtyp($studienplan_id, "modul");
+
$xml .= " ";
//Variable wird zur korrekten Darstellung im Dokument benötigt
diff --git a/rdf/studienblatt.xml.php b/rdf/studienblatt.xml.php
index 3bf916d13..f057865f6 100644
--- a/rdf/studienblatt.xml.php
+++ b/rdf/studienblatt.xml.php
@@ -1,339 +1,340 @@
-
- * Karl Burkhart
- * Manfred Kindl
- */
-header("Content-type: application/xhtml+xml");
-require_once('../config/vilesci.config.inc.php');
-require_once('../include/functions.inc.php');
-require_once('../include/studiengang.class.php');
-require_once('../include/student.class.php');
-require_once('../include/prestudent.class.php');
-require_once('../include/adresse.class.php');
-require_once('../include/lehrveranstaltung.class.php');
-require_once('../include/akadgrad.class.php');
-require_once('../include/studiensemester.class.php');
-require_once('../include/nation.class.php');
-require_once('../include/studienordnung.class.php');
-require_once('../include/studienplan.class.php');
-require_once('../include/mitarbeiter.class.php');
-require_once('../include/organisationsform.class.php');
-require_once('../include/zgv.class.php');
-require_once('../include/konto.class.php');
-
-$uid_arr = (isset($_REQUEST['uid'])?$_REQUEST['uid']:null);
-
-$uid_arr = explode(";",$uid_arr);
-
-echo "\n";
-echo "\n";
-
-$uid = isset($uid_arr[1])?$uid_arr[1]:$uid_arr[0];
-
-$konto = new konto();
-$student_help = new student();
-// an 2ter stelle da im Aufruf vom FAS ;; der erste immer '' ist
-if($student_help->load($uid))
-{
- $studiengang = new studiengang();
- $studiengang->load($student_help->studiengang_kz);
- switch($studiengang->typ)
- {
- case 'b':
- $studTyp = 'Bachelor';
- $titel_kurzbz = 'BSc';
- break;
- case 'm':
- $studTyp = 'Master';
- $titel_kurzbz ='MSc';
- break;
- case 'd':
- $studTyp = 'Diplom';
- break;
- case 'l':
- $studTyp = 'Lehrgang';
- break;
- case 'k':
- $studTyp = 'Kurzstudium';
- break;
- default:
- $studTyp ='';
- $titel_kurzbz = '';
- }
- echo "\t".$studTyp."\n";
- echo "\t".$studiengang->bezeichnung."\n";
-}
-
-foreach($uid_arr as $uid)
-{
- if($uid=='')
- continue;
-
- echo "\t\n";
-
- $student = new student();
- if($student->load($uid))
- {
- $datum_aktuell = date('d.m.Y');
- $gebdatum = date('d.m.Y',strtotime($student->gebdatum));
- $prestudent = new prestudent($student->prestudent_id);
- $prestudent->getLastStatus($student->prestudent_id,null,'Student');
- $studienordnung = new studienordnung();
- $studienordnung->getStudienordnungFromStudienplan($prestudent->studienplan_id);
- $studiengang = new studiengang();
- $studiengang->load($studienordnung->studiengang_kz);
- $studienplan = new studienplan();
- $studienplan->loadStudienplan($prestudent->studienplan_id);
- $staatsbuergerschaft = new nation();
- $staatsbuergerschaft->load($student->staatsbuergerschaft);
-
-
- $svnr = ($student->svnr == '')?'Ersatzkennzeichen: '.$student->ersatzkennzeichen:$student->svnr;
-
- switch($student->geschlecht)
- {
- case 'm':
- $geschlecht = 'Männlich';
- break;
- case 'w':
- $geschlecht = 'Weiblich';
- break;
- case 'u':
- $geschlecht = 'Unbekannt';
- break;
- default:
- $geschlecht ='';
- }
-
- //Wenn Lehrgang, dann Erhalter-KZ vor die Studiengangs-Kz hängen
- if ($studienordnung->studiengang_kz<0)
- {
- $stg = new studiengang();
- $stg->load($studienordnung->studiengang_kz);
-
- $studiengang_kz = sprintf("%03s", $stg->erhalter_kz).sprintf("%04s", abs($studienordnung->studiengang_kz));
- }
- else
- $studiengang_kz = sprintf("%04s", abs($studienordnung->studiengang_kz));
-
- echo "\t\t1 \n";
- echo "\t\t".$uid."\n";
- echo "\t\t".$geschlecht."\n";
- echo "\t\t".$student->anrede."\n";
- echo "\t\t".$student->vorname." ".$student->vornamen."\n";
- echo "\t\t".$student->vornamen."\n";
- echo "\t\t".$student->nachname."\n";
- echo "\t\t".$student->titelpre."\n";
- echo "\t\t".$student->titelpost."\n";
- echo "\t\t".$gebdatum."\n";
- echo "\t\t".$student->gebort."\n";
- echo "\t\t".$staatsbuergerschaft->langtext."\n";
- echo "\t\t".$svnr."\n";
- echo "\t\t".trim($student->matrikelnr)."\n";
- echo "\t\t".$studienordnung->studiengangbezeichnung."\n";
- echo "\t\t".$studienordnung->studiengangbezeichnung_englisch."\n";
- echo "\t\t".$studienordnung->studiengangkurzbzlang."\n";
- echo "\t\t".$studiengang_kz."\n";
- echo "\t\t".$studienplan->sprache."";
- echo "\t\t".$studienordnung->ects."";
- echo "\t\t".($studienplan->regelstudiendauer!=0?$studienordnung->ects/$studienplan->regelstudiendauer:0)."";
-
- echo "\t\t".date('Y')."";
-
- echo "\t\t".$prestudent->ausbildungssemester."";
-
- $studiensemester_aktuell = new studiensemester();
- $studiensemester_aktuell->load($prestudent->studiensemester_kurzbz);
-
- echo "\t\t".$studiensemester_aktuell->bezeichnung."";
-
- // check ob Oeh-Beitrag bezahlt wurde
- $oehbeitrag = $konto->getOehBeitragGesamt($uid, $studiensemester_aktuell->studiensemester_kurzbz);
- echo "\t\t".str_replace('.', ',', $oehbeitrag)."";
-
- // check ob Quereinsteiger
- $ausbildungssemester = ($prestudent->getFirstStatus($student->prestudent_id, 'Student'))?$prestudent->ausbildungssemester:'';
- echo "\t\t".$ausbildungssemester."";
-
- $studiensemester_beginn = new studiensemester();
- $studienbeginn = ($prestudent->getFirstStatus($student->prestudent_id, 'Student'))?$prestudent->studiensemester_kurzbz:'';
- $studiensemester_beginn->load($studienbeginn);
-
- echo "\t\t".$studiensemester_beginn->bezeichnung."";
- echo "\t\t".date('d.m.Y',strtotime($studiensemester_beginn->start))."";
-
- $prestudent->getLastStatus($student->prestudent_id,null,'Student');
- $studiensemester_abschluss = new studiensemester();
- $abschluss = $studiensemester_abschluss->jump($prestudent->studiensemester_kurzbz, $studienplan->regelstudiendauer-$prestudent->ausbildungssemester);
- $studiensemester_abschluss->load($abschluss);
- echo "\t\t".$studiensemester_abschluss->bezeichnung."";
- echo "\t\t".date('d.m.Y',strtotime($studiensemester_abschluss->ende))."";
-
- $studiensemester_endedatum = new studiensemester();
- $studiensemester_endedatum->load($studiensemester_endedatum->getaktorNext(1));
-
- echo "\t\t".date('d.m.Y',strtotime($studiensemester_endedatum->ende))."";
-
- $status_aktuell = ($prestudent->getLastStatus($student->prestudent_id,null,null))?$prestudent->status_kurzbz:'';
-
- switch($status_aktuell)
- {
- case 'Student':
- $studierendenstatus_aktuell = 'Aktive/r StudentIn';
- break;
- case 'Unterbrecher':
- $studierendenstatus_aktuell = 'UnterbrecherIn';
- break;
- case 'Absolvent':
- $studierendenstatus_aktuell = 'AbsolventIn';
- break;
- case 'Diplomand':
- $studierendenstatus_aktuell = 'DiplomandIn';
- break;
- case 'Abbrecher':
- $studierendenstatus_aktuell = 'AbbrecherIn';
- break;
- default:
- $studierendenstatus_aktuell ='';
- }
-
- echo "\t\t".$studierendenstatus_aktuell."\n";
- echo "\t\t".$prestudent->zgvdatum."\n";
- $zgv = new zgv($prestudent->zgv_code);
- echo "\t\t".$zgv->zgv_kurzbz."\n";
- echo "\t\t".$studienplan->bezeichnung."\n";
- echo "\t\tanmerkung]]>\n";
-
- $titel_kurzbz = '';
- switch($studiengang->typ)
- {
- case 'b':
- $studTyp = 'Bachelor';
- $titel_kurzbz = 'BSc';
- break;
- case 'm':
- $studTyp = 'Master';
- $titel_kurzbz ='MSc';
- break;
- case 'd':
- $studTyp = 'Diplom';
- break;
- case 'l':
- $studTyp = 'Lehrgang';
- break;
- case 'k':
- $studTyp = 'Kurzstudium';
- break;
- default:
- $studTyp ='';
- $titel_kurzbz = '';
- }
-
- echo "\t\t".$titel_kurzbz."\n";
- echo "\t\t".$studTyp."\n";
- echo "\t\t".$studienplan->sprache."\n";
- echo "\t\t".$studienplan->regelstudiendauer."\n";
-
- $akadgrad = new akadgrad();
- $akadgrad->getAkadgradStudent($student->uid);
-
- echo "\t\t".$akadgrad->titel."\n";
- echo "\t\t".$akadgrad->akadgrad_kurzbz."\n";
-
- //für ao. Studierende wird die StgKz der Lehrveranstaltungen benötigt, die sie besuchen
- $lv_studiengang_kz='';
- $lv_studiengang_bezeichnung='';
- $lv_studiengang_typ='';
-
- $stg_typ=new studiengang();
- $lv=new lehrveranstaltung();
- $lv->load_lva_student($student->uid);
- if(count($lv->lehrveranstaltungen)>0)
- {
- $lv_studiengang_kz=$lv->lehrveranstaltungen[0]->studiengang_kz;
- $lv_studiengang=new studiengang();
- $lv_studiengang->load($lv_studiengang_kz);
- $lv_studiengang_bezeichnung=$lv_studiengang->bezeichnung;
- $stg_typ->getStudiengangTyp($lv_studiengang->typ);
- $lv_studiengang_typ=$stg_typ->bezeichnung;
- }
-
- echo "\t\t".sprintf('%04s', $lv_studiengang_kz)."";
- echo "\t\t$lv_studiengang_typ";
- echo "\t\t$lv_studiengang_bezeichnung";
-
- echo "\t\t".$datum_aktuell."\n";
-
- $adresse = new adresse();
- $adresse->load_pers($student->person_id);
-
- foreach($adresse->result as $row_adresse)
- {
- if($row_adresse->zustelladresse)
- {
- echo "\t\tstrasse]]>\n";
- echo "\t\t".$row_adresse->plz." ".$row_adresse->ort."\n";
- echo "\t\t".$row_adresse->nation."\n";
- break;
- }
- }
- foreach($adresse->result as $row_adresse)
- {
- if($row_adresse->heimatadresse)
- {
- echo "\t\tstrasse]]>\n";
- echo "\t\t".$row_adresse->plz." ".$row_adresse->ort."\n";
- echo "\t\t".$row_adresse->nation."\n";
- break;
- }
- }
- $prestudent = new prestudent();
- $prestudent->getLastStatus($student->prestudent_id, null, 'Student');
-
- if($prestudent->orgform_kurzbz!='')
- $orgform = $prestudent->orgform_kurzbz;
- else
- $orgform = $studienplan->orgform_kurzbz;
-
- $orgform_bez = new organisationsform();
- $orgform_bez->load($orgform);
-
- echo "\t\t".$orgform."\n";
- echo "\t\t".$orgform_bez->bezeichnung."\n";
-
- //Studiengangsleiter auslesen
- $stg_oe_obj = new studiengang($studienordnung->studiengang_kz);
- if ($studienordnung->studiengang_kz=='')
- $stgleiter = $stg_oe_obj->getLeitung($student_help->studiengang_kz);
- else
- $stgleiter = $stg_oe_obj->getLeitung($studienordnung->studiengang_kz);
- $stgl='';
- foreach ($stgleiter as $stgleiter_uid)
- {
- $stgl_ma = new mitarbeiter($stgleiter_uid);
- $stgl .= trim($stgl_ma->titelpre.' '.$stgl_ma->vorname.' '.$stgl_ma->nachname.' '.$stgl_ma->titelpost);
- }
-
- echo "\t\t$stgl\n";
- }
- echo "\t\n";
-}
-echo "";
-
+
+ * Karl Burkhart
+ * Manfred Kindl
+ */
+header("Content-type: application/xhtml+xml");
+require_once('../config/vilesci.config.inc.php');
+require_once('../include/functions.inc.php');
+require_once('../include/studiengang.class.php');
+require_once('../include/student.class.php');
+require_once('../include/prestudent.class.php');
+require_once('../include/adresse.class.php');
+require_once('../include/lehrveranstaltung.class.php');
+require_once('../include/akadgrad.class.php');
+require_once('../include/studiensemester.class.php');
+require_once('../include/nation.class.php');
+require_once('../include/studienordnung.class.php');
+require_once('../include/studienplan.class.php');
+require_once('../include/mitarbeiter.class.php');
+require_once('../include/organisationsform.class.php');
+require_once('../include/zgv.class.php');
+require_once('../include/konto.class.php');
+
+$uid_arr = (isset($_REQUEST['uid'])?$_REQUEST['uid']:null);
+$studiensemester = (isset($_REQUEST['ss'])?$_REQUEST['ss']:null);
+
+$uid_arr = explode(";",$uid_arr);
+
+echo "\n";
+echo "\n";
+
+$uid = isset($uid_arr[1])?$uid_arr[1]:$uid_arr[0];
+
+$konto = new konto();
+$student_help = new student();
+// an 2ter stelle da im Aufruf vom FAS ;; der erste immer '' ist
+if($student_help->load($uid))
+{
+ $studiengang = new studiengang();
+ $studiengang->load($student_help->studiengang_kz);
+ switch($studiengang->typ)
+ {
+ case 'b':
+ $studTyp = 'Bachelor';
+ $titel_kurzbz = 'BSc';
+ break;
+ case 'm':
+ $studTyp = 'Master';
+ $titel_kurzbz ='MSc';
+ break;
+ case 'd':
+ $studTyp = 'Diplom';
+ break;
+ case 'l':
+ $studTyp = 'Lehrgang';
+ break;
+ case 'k':
+ $studTyp = 'Kurzstudium';
+ break;
+ default:
+ $studTyp ='';
+ $titel_kurzbz = '';
+ }
+ echo "\t".$studTyp."\n";
+ echo "\t".$studiengang->bezeichnung."\n";
+}
+
+foreach($uid_arr as $uid)
+{
+ if($uid=='')
+ continue;
+
+ echo "\t\n";
+
+ $student = new student();
+ if($student->load($uid))
+ {
+ $datum_aktuell = date('d.m.Y');
+ $gebdatum = date('d.m.Y',strtotime($student->gebdatum));
+ $prestudent = new prestudent($student->prestudent_id);
+ $prestudent->getLastStatus($student->prestudent_id,$studiensemester,'Student');
+ $studienordnung = new studienordnung();
+ $studienordnung->getStudienordnungFromStudienplan($prestudent->studienplan_id);
+ $studiengang = new studiengang();
+ $studiengang->load($studienordnung->studiengang_kz);
+ $studienplan = new studienplan();
+ $studienplan->loadStudienplan($prestudent->studienplan_id);
+ $staatsbuergerschaft = new nation();
+ $staatsbuergerschaft->load($student->staatsbuergerschaft);
+
+
+ $svnr = ($student->svnr == '')?'Ersatzkennzeichen: '.$student->ersatzkennzeichen:$student->svnr;
+
+ switch($student->geschlecht)
+ {
+ case 'm':
+ $geschlecht = 'Männlich';
+ break;
+ case 'w':
+ $geschlecht = 'Weiblich';
+ break;
+ case 'u':
+ $geschlecht = 'Unbekannt';
+ break;
+ default:
+ $geschlecht ='';
+ }
+
+ //Wenn Lehrgang, dann Erhalter-KZ vor die Studiengangs-Kz hängen
+ if ($studienordnung->studiengang_kz<0)
+ {
+ $stg = new studiengang();
+ $stg->load($studienordnung->studiengang_kz);
+
+ $studiengang_kz = sprintf("%03s", $stg->erhalter_kz).sprintf("%04s", abs($studienordnung->studiengang_kz));
+ }
+ else
+ $studiengang_kz = sprintf("%04s", abs($studienordnung->studiengang_kz));
+
+ echo "\t\t1 \n";
+ echo "\t\t".$uid."\n";
+ echo "\t\t".$geschlecht."\n";
+ echo "\t\t".$student->anrede."\n";
+ echo "\t\t".$student->vorname." ".$student->vornamen."\n";
+ echo "\t\t".$student->vornamen."\n";
+ echo "\t\t".$student->nachname."\n";
+ echo "\t\t".$student->titelpre."\n";
+ echo "\t\t".$student->titelpost."\n";
+ echo "\t\t".$gebdatum."\n";
+ echo "\t\t".$student->gebort."\n";
+ echo "\t\t".$staatsbuergerschaft->langtext."\n";
+ echo "\t\t".$svnr."\n";
+ echo "\t\t".trim($student->matrikelnr)."\n";
+ echo "\t\t".$studienordnung->studiengangbezeichnung."\n";
+ echo "\t\t".$studienordnung->studiengangbezeichnung_englisch."\n";
+ echo "\t\t".$studienordnung->studiengangkurzbzlang."\n";
+ echo "\t\t".$studiengang_kz."\n";
+ echo "\t\t".$studienplan->sprache."";
+ echo "\t\t".$studienordnung->ects."";
+ echo "\t\t".($studienplan->regelstudiendauer!=0?$studienordnung->ects/$studienplan->regelstudiendauer:0)."";
+
+ echo "\t\t".date('Y')."";
+
+ echo "\t\t".$prestudent->ausbildungssemester."";
+
+ $studiensemester_aktuell = new studiensemester();
+ $studiensemester_aktuell->load($studiensemester);
+
+ echo "\t\t".$studiensemester_aktuell->bezeichnung."";
+
+ // check ob Oeh-Beitrag bezahlt wurde
+ $oehbeitrag = $konto->getOehBeitragGesamt($uid, $studiensemester_aktuell->studiensemester_kurzbz);
+ echo "\t\t".str_replace('.', ',', $oehbeitrag)."";
+
+ // check ob Quereinsteiger
+ $ausbildungssemester = ($prestudent->getFirstStatus($student->prestudent_id, 'Student'))?$prestudent->ausbildungssemester:'';
+ echo "\t\t".$ausbildungssemester."";
+
+ $studiensemester_beginn = new studiensemester();
+ $studienbeginn = ($prestudent->getFirstStatus($student->prestudent_id, 'Student'))?$prestudent->studiensemester_kurzbz:'';
+ $studiensemester_beginn->load($studienbeginn);
+
+ echo "\t\t".$studiensemester_beginn->bezeichnung."";
+ echo "\t\t".date('d.m.Y',strtotime($studiensemester_beginn->start))."";
+
+ $prestudent->getLastStatus($student->prestudent_id,$studiensemester,'Student');
+ $studiensemester_abschluss = new studiensemester();
+ $abschluss = $studiensemester_abschluss->jump($prestudent->studiensemester_kurzbz, $studienplan->regelstudiendauer-$prestudent->ausbildungssemester);
+ $studiensemester_abschluss->load($abschluss);
+ echo "\t\t".$studiensemester_abschluss->bezeichnung."";
+ echo "\t\t".date('d.m.Y',strtotime($studiensemester_abschluss->ende))."";
+
+ $studiensemester_endedatum = new studiensemester();
+ $studiensemester_endedatum->load($studiensemester_endedatum->getaktorNext(1));
+
+ echo "\t\t".date('d.m.Y',strtotime($studiensemester_endedatum->ende))."";
+
+ $status_aktuell = ($prestudent->getLastStatus($student->prestudent_id,null,null))?$prestudent->status_kurzbz:'';
+
+ switch($status_aktuell)
+ {
+ case 'Student':
+ $studierendenstatus_aktuell = 'Aktive/r StudentIn';
+ break;
+ case 'Unterbrecher':
+ $studierendenstatus_aktuell = 'UnterbrecherIn';
+ break;
+ case 'Absolvent':
+ $studierendenstatus_aktuell = 'AbsolventIn';
+ break;
+ case 'Diplomand':
+ $studierendenstatus_aktuell = 'DiplomandIn';
+ break;
+ case 'Abbrecher':
+ $studierendenstatus_aktuell = 'AbbrecherIn';
+ break;
+ default:
+ $studierendenstatus_aktuell ='';
+ }
+
+ echo "\t\t".$studierendenstatus_aktuell."\n";
+ echo "\t\t".$prestudent->zgvdatum."\n";
+ $zgv = new zgv($prestudent->zgv_code);
+ echo "\t\t".$zgv->zgv_kurzbz."\n";
+ echo "\t\t".$studienplan->bezeichnung."\n";
+ echo "\t\tanmerkung]]>\n";
+
+ $titel_kurzbz = '';
+ switch($studiengang->typ)
+ {
+ case 'b':
+ $studTyp = 'Bachelor';
+ $titel_kurzbz = 'BSc';
+ break;
+ case 'm':
+ $studTyp = 'Master';
+ $titel_kurzbz ='MSc';
+ break;
+ case 'd':
+ $studTyp = 'Diplom';
+ break;
+ case 'l':
+ $studTyp = 'Lehrgang';
+ break;
+ case 'k':
+ $studTyp = 'Kurzstudium';
+ break;
+ default:
+ $studTyp ='';
+ $titel_kurzbz = '';
+ }
+
+ echo "\t\t".$titel_kurzbz."\n";
+ echo "\t\t".$studTyp."\n";
+ echo "\t\t".$studienplan->sprache."\n";
+ echo "\t\t".$studienplan->regelstudiendauer."\n";
+
+ $akadgrad = new akadgrad();
+ $akadgrad->getAkadgradStudent($student->uid);
+
+ echo "\t\t".$akadgrad->titel."\n";
+ echo "\t\t".$akadgrad->akadgrad_kurzbz."\n";
+
+ //für ao. Studierende wird die StgKz der Lehrveranstaltungen benötigt, die sie besuchen
+ $lv_studiengang_kz='';
+ $lv_studiengang_bezeichnung='';
+ $lv_studiengang_typ='';
+
+ $stg_typ=new studiengang();
+ $lv=new lehrveranstaltung();
+ $lv->load_lva_student($student->uid);
+ if(count($lv->lehrveranstaltungen)>0)
+ {
+ $lv_studiengang_kz=$lv->lehrveranstaltungen[0]->studiengang_kz;
+ $lv_studiengang=new studiengang();
+ $lv_studiengang->load($lv_studiengang_kz);
+ $lv_studiengang_bezeichnung=$lv_studiengang->bezeichnung;
+ $stg_typ->getStudiengangTyp($lv_studiengang->typ);
+ $lv_studiengang_typ=$stg_typ->bezeichnung;
+ }
+
+ echo "\t\t".sprintf('%04s', $lv_studiengang_kz)."";
+ echo "\t\t$lv_studiengang_typ";
+ echo "\t\t$lv_studiengang_bezeichnung";
+
+ echo "\t\t".$datum_aktuell."\n";
+
+ $adresse = new adresse();
+ $adresse->load_pers($student->person_id);
+
+ foreach($adresse->result as $row_adresse)
+ {
+ if($row_adresse->zustelladresse)
+ {
+ echo "\t\tstrasse]]>\n";
+ echo "\t\t".$row_adresse->plz." ".$row_adresse->ort."\n";
+ echo "\t\t".$row_adresse->nation."\n";
+ break;
+ }
+ }
+ foreach($adresse->result as $row_adresse)
+ {
+ if($row_adresse->heimatadresse)
+ {
+ echo "\t\tstrasse]]>\n";
+ echo "\t\t".$row_adresse->plz." ".$row_adresse->ort."\n";
+ echo "\t\t".$row_adresse->nation."\n";
+ break;
+ }
+ }
+ $prestudent = new prestudent();
+ $prestudent->getLastStatus($student->prestudent_id, null, 'Student');
+
+ if($prestudent->orgform_kurzbz!='')
+ $orgform = $prestudent->orgform_kurzbz;
+ else
+ $orgform = $studienplan->orgform_kurzbz;
+
+ $orgform_bez = new organisationsform();
+ $orgform_bez->load($orgform);
+
+ echo "\t\t".$orgform."\n";
+ echo "\t\t".$orgform_bez->bezeichnung."\n";
+
+ //Studiengangsleiter auslesen
+ $stg_oe_obj = new studiengang($studienordnung->studiengang_kz);
+ if ($studienordnung->studiengang_kz=='')
+ $stgleiter = $stg_oe_obj->getLeitung($student_help->studiengang_kz);
+ else
+ $stgleiter = $stg_oe_obj->getLeitung($studienordnung->studiengang_kz);
+ $stgl='';
+ foreach ($stgleiter as $stgleiter_uid)
+ {
+ $stgl_ma = new mitarbeiter($stgleiter_uid);
+ $stgl .= trim($stgl_ma->titelpre.' '.$stgl_ma->vorname.' '.$stgl_ma->nachname.' '.$stgl_ma->titelpost);
+ }
+
+ echo "\t\t$stgl\n";
+ }
+ echo "\t\n";
+}
+echo "";
+
?>
\ No newline at end of file
diff --git a/tests/codesniffer/FHComplete/Sniffs/Commenting/DocBlockAlignmentSniff.php b/tests/codesniffer/FHComplete/Sniffs/Commenting/DocBlockAlignmentSniff.php
new file mode 100755
index 000000000..94b5a3e66
--- /dev/null
+++ b/tests/codesniffer/FHComplete/Sniffs/Commenting/DocBlockAlignmentSniff.php
@@ -0,0 +1,59 @@
+getTokens();
+ $leftWall = array(
+ T_CLASS,
+ T_NAMESPACE,
+ T_INTERFACE,
+ T_TRAIT,
+ T_USE
+ );
+ $oneIndentation = array(
+ T_FUNCTION,
+ T_VARIABLE,
+ T_CONST
+ );
+ $allTokens = array_merge($leftWall, $oneIndentation);
+ $notFlatFile = $phpcsFile->findNext(T_NAMESPACE, 0);
+ $next = $phpcsFile->findNext($allTokens, $stackPtr + 1);
+
+ if ($next && $notFlatFile) {
+ $notWalled = (in_array($tokens[$next]['code'], $leftWall) && $tokens[$stackPtr]['column'] !== 1);
+ $notIndented = (in_array($tokens[$next]['code'], $oneIndentation) && $tokens[$stackPtr]['column'] !== 5);
+ if ($notWalled || $notIndented) {
+ $phpcsFile->addError('Expected docblock to be aligned with code.', $stackPtr, 'NotAllowed');
+ }
+ }
+
+ return;
+ }
+}
diff --git a/tests/codesniffer/FHComplete/Sniffs/Commenting/FunctionCommentSniff.php b/tests/codesniffer/FHComplete/Sniffs/Commenting/FunctionCommentSniff.php
new file mode 100755
index 000000000..34ea7e796
--- /dev/null
+++ b/tests/codesniffer/FHComplete/Sniffs/Commenting/FunctionCommentSniff.php
@@ -0,0 +1,487 @@
+
+ * @author Marc McIntyre
+ * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
+ * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
+ * @link http://pear.php.net/package/PHP_CodeSniffer
+ */
+
+if (class_exists('PEAR_Sniffs_Commenting_FunctionCommentSniff', true) === false) {
+ throw new PHP_CodeSniffer_Exception('Class PEAR_Sniffs_Commenting_FunctionCommentSniff not found');
+}
+
+/**
+ * Parses and verifies the doc comments for functions.
+ *
+ * Verifies that :
+ *
+ * - A comment exists
+ * - There is a blank newline after the short description
+ * - There is a blank newline between the long and short description
+ * - There is a blank newline between the long description and tags
+ * - Parameter names represent those in the method
+ * - Parameter comments are in the correct order
+ * - Parameter comments are complete
+ * - A type hint is provided for array and custom class
+ * - Type hint matches the actual variable/class type
+ * - A blank line is present before the first and after the last parameter
+ * - A return type exists
+ * - Any throw tag must have a comment
+ * - The tag order and indentation are correct
+ *
+ *
+ * @category PHP
+ * @package PHP_CodeSniffer
+ * @author Greg Sherwood
+ * @author Marc McIntyre
+ * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
+ * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
+ * @version Release: @package_version@
+ * @link http://pear.php.net/package/PHP_CodeSniffer
+ */
+class FHComplete_Sniffs_Commenting_FunctionCommentSniff extends PEAR_Sniffs_Commenting_FunctionCommentSniff
+{
+ /**
+ * Is the comment an inheritdoc?
+ *
+ * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
+ * @param int $stackPtr The position of the current token
+ * in the stack passed in $tokens.
+ *
+ * @return boolean True if the comment is an inheritdoc
+ */
+ protected function isInheritDoc(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
+ {
+ $start = $phpcsFile->findPrevious(T_DOC_COMMENT_OPEN_TAG, $stackPtr - 1);
+ $end = $phpcsFile->findNext(T_DOC_COMMENT_CLOSE_TAG, $start);
+ $content = $phpcsFile->getTokensAsString($start, ($end - $start));
+ return preg_match('#{@inheritDoc}#', $content) === 1;
+ } // end isInheritDoc()
+
+ /**
+ * Process the return comment of this function comment.
+ *
+ * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
+ * @param int $stackPtr The position of the current token
+ * in the stack passed in $tokens.
+ * @param int $commentStart The position in the stack where the comment started.
+ *
+ * @return void
+ */
+ protected function processReturn(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $commentStart)
+ {
+ if ($this->isInheritDoc($phpcsFile, $stackPtr)) {
+ return;
+ }
+
+ $tokens = $phpcsFile->getTokens();
+
+ // Skip constructor and destructor.
+ $className = '';
+ foreach ($tokens[$stackPtr]['conditions'] as $condPtr => $condition) {
+ if ($condition === T_CLASS || $condition === T_INTERFACE) {
+ $className = $phpcsFile->getDeclarationName($condPtr);
+ $className = strtolower(ltrim($className, '_'));
+ }
+ }
+
+ $methodName = $phpcsFile->getDeclarationName($stackPtr);
+ $isSpecialMethod = ($methodName === '__construct' || $methodName === '__destruct');
+ if ($methodName !== '_') {
+ $methodName = strtolower(ltrim($methodName, '_'));
+ }
+
+ $return = null;
+ foreach ($tokens[$commentStart]['comment_tags'] as $tag) {
+ if ($tokens[$tag]['content'] === '@return') {
+ if ($return !== null) {
+ $error = 'Only 1 @return tag is allowed in a function comment';
+ $phpcsFile->addError($error, $tag, 'DuplicateReturn');
+ return;
+ }
+
+ $return = $tag;
+ }
+ }
+
+ if ($isSpecialMethod === true) {
+ return;
+ }
+
+ if ($return !== null) {
+ $content = $tokens[($return + 2)]['content'];
+ if (empty($content) === true || $tokens[($return + 2)]['code'] !== T_DOC_COMMENT_STRING) {
+ $error = 'Return type missing for @return tag in function comment';
+ $phpcsFile->addError($error, $return, 'MissingReturnType');
+ } else {
+ // Check return type (can be multiple, separated by '|').
+ $typeNames = explode('|', $content);
+ $suggestedNames = array();
+ foreach ($typeNames as $i => $typeName) {
+ if ($typeName === 'integer') {
+ $suggestedName = 'int';
+ } elseif ($typeName === 'boolean') {
+ $suggestedName = 'bool';
+ } elseif (in_array($typeName, array('int', 'bool'))) {
+ $suggestedName = $typeName;
+ } else {
+ $suggestedName = PHP_CodeSniffer::suggestType($typeName);
+ }
+ if (in_array($suggestedName, $suggestedNames) === false) {
+ $suggestedNames[] = $suggestedName;
+ }
+ }
+
+ $suggestedType = implode('|', $suggestedNames);
+ if ($content !== $suggestedType) {
+ $error = 'Function return type "%s" is invalid';
+ $error = 'Expected "%s" but found "%s" for function return type';
+ $data = array(
+ $suggestedType,
+ $content,
+ );
+ $phpcsFile->addError($error, $return, 'InvalidReturn', $data);
+ }
+
+ // If the return type is void, make sure there is
+ // no return statement in the function.
+ if ($content === 'void') {
+ if (isset($tokens[$stackPtr]['scope_closer']) === true) {
+ $endToken = $tokens[$stackPtr]['scope_closer'];
+ for ($returnToken = $stackPtr; $returnToken < $endToken; $returnToken++) {
+ if ($tokens[$returnToken]['code'] === T_CLOSURE) {
+ $returnToken = $tokens[$returnToken]['scope_closer'];
+ continue;
+ }
+
+ if ($tokens[$returnToken]['code'] === T_RETURN) {
+ break;
+ }
+ }
+
+ if ($returnToken !== $endToken) {
+ // If the function is not returning anything, just
+ // exiting, then there is no problem.
+ $semicolon = $phpcsFile->findNext(T_WHITESPACE, ($returnToken + 1), null, true);
+ if ($tokens[$semicolon]['code'] !== T_SEMICOLON) {
+ $error = 'Function return type is void, but function contains return statement';
+ $phpcsFile->addWarning($error, $return, 'InvalidReturnVoid');
+ }
+ }
+ }//end if
+ } elseif (!preg_match('/^mixed/', $content)) {
+ // If return type is not void, there needs to be a return statement
+ // somewhere in the function that returns something.
+ if (isset($tokens[$stackPtr]['scope_closer']) === true) {
+ $endToken = $tokens[$stackPtr]['scope_closer'];
+ $returnToken = $phpcsFile->findNext(T_RETURN, $stackPtr, $endToken);
+ if ($returnToken === false) {
+ $error = 'Function return type is not void, but function has no return statement';
+ $phpcsFile->addWarning($error, $return, 'InvalidNoReturn');
+ } elseif (!preg_match('/void/', $content)) {
+ $semicolon = $phpcsFile->findNext(T_WHITESPACE, ($returnToken + 1), null, true);
+ if ($tokens[$semicolon]['code'] === T_SEMICOLON) {
+ $error = 'Function return type is not void, but function is returning void here';
+ $phpcsFile->addWarning($error, $returnToken, 'InvalidReturnNotVoid');
+ }
+ }
+ }
+ }//end if
+ }//end if
+ } else {
+ $error = 'Missing @return tag in function comment';
+ $phpcsFile->addWarning($error, $tokens[$commentStart]['comment_closer'], 'MissingReturn');
+ }//end if
+
+ }//end processReturn()
+
+
+ /**
+ * Process any throw tags that this function comment has.
+ *
+ * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
+ * @param int $stackPtr The position of the current token
+ * in the stack passed in $tokens.
+ * @param int $commentStart The position in the stack where the comment started.
+ *
+ * @return void
+ */
+ protected function processThrows(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $commentStart)
+ {
+ $tokens = $phpcsFile->getTokens();
+
+ $throws = array();
+ foreach ($tokens[$commentStart]['comment_tags'] as $pos => $tag) {
+ if ($tokens[$tag]['content'] !== '@throws') {
+ continue;
+ }
+
+ $exception = null;
+ $comment = null;
+ if ($tokens[($tag + 2)]['code'] === T_DOC_COMMENT_STRING) {
+ $matches = array();
+ preg_match('/([^\s]+)(?:\s+(.*))?/', $tokens[($tag + 2)]['content'], $matches);
+ $exception = $matches[1];
+ if (isset($matches[2]) === true) {
+ $comment = $matches[2];
+ }
+ }
+
+ if ($exception === null) {
+ $error = 'Exception type and comment missing for @throws tag in function comment';
+ $phpcsFile->addWarning($error, $tag, 'InvalidThrows');
+ } elseif ($comment === null) {
+ $error = 'Comment missing for @throws tag in function comment';
+ $phpcsFile->addWarning($error, $tag, 'EmptyThrows');
+ } else {
+ // Any strings until the next tag belong to this comment.
+ if (isset($tokens[$commentStart]['comment_tags'][($pos + 1)]) === true) {
+ $end = $tokens[$commentStart]['comment_tags'][($pos + 1)];
+ } else {
+ $end = $tokens[$commentStart]['comment_closer'];
+ }
+
+ for ($i = ($tag + 3); $i < $end; $i++) {
+ if ($tokens[$i]['code'] === T_DOC_COMMENT_STRING) {
+ $comment .= ' '.$tokens[$i]['content'];
+ }
+ }
+
+ // Starts with a capital letter and ends with a fullstop.
+ $firstChar = $comment{0};
+ if (strtoupper($firstChar) !== $firstChar) {
+ $error = '@throws tag comment must start with a capital letter';
+ $phpcsFile->addWarning($error, ($tag + 2), 'ThrowsNotCapital');
+ }
+
+ $lastChar = substr($comment, -1);
+ if ($lastChar !== '.') {
+ $error = '@throws tag comment must end with a full stop';
+ $phpcsFile->addWarning($error, ($tag + 2), 'ThrowsNoFullStop');
+ }
+ }//end if
+ }//end foreach
+
+ }//end processThrows()
+
+
+ /**
+ * Process the function parameter comments.
+ *
+ * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
+ * @param int $stackPtr The position of the current token
+ * in the stack passed in $tokens.
+ * @param int $commentStart The position in the stack where the comment started.
+ *
+ * @return void
+ */
+ protected function processParams(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $commentStart)
+ {
+ if ($this->isInheritDoc($phpcsFile, $stackPtr)) {
+ return;
+ }
+
+ $tokens = $phpcsFile->getTokens();
+
+ $params = array();
+ $maxType = 0;
+ $maxVar = 0;
+ foreach ($tokens[$commentStart]['comment_tags'] as $pos => $tag) {
+ if ($tokens[$tag]['content'] !== '@param') {
+ continue;
+ }
+
+ $type = '';
+ $typeSpace = 0;
+ $var = '';
+ $varSpace = 0;
+ $comment = '';
+ $commentLines = array();
+ if ($tokens[($tag + 2)]['code'] === T_DOC_COMMENT_STRING) {
+ $matches = array();
+ preg_match('/([^$&]+)(?:((?:\$|&)[^\s]+)(?:(\s+)(.*))?)?/', $tokens[($tag + 2)]['content'], $matches);
+
+ $typeLen = strlen($matches[1]);
+ $type = trim($matches[1]);
+ $typeSpace = ($typeLen - strlen($type));
+ $typeLen = strlen($type);
+ if ($typeLen > $maxType) {
+ $maxType = $typeLen;
+ }
+
+ if (isset($matches[2]) === true) {
+ $var = $matches[2];
+ $varLen = strlen($var);
+ if ($varLen > $maxVar) {
+ $maxVar = $varLen;
+ }
+
+ if (isset($matches[4]) === true) {
+ $varSpace = strlen($matches[3]);
+ $comment = $matches[4];
+ $commentLines[] = array(
+ 'comment' => $comment,
+ 'token' => ($tag + 2),
+ 'indent' => $varSpace,
+ );
+
+ // Any strings until the next tag belong to this comment.
+ if (isset($tokens[$commentStart]['comment_tags'][($pos + 1)]) === true) {
+ $end = $tokens[$commentStart]['comment_tags'][($pos + 1)];
+ } else {
+ $end = $tokens[$commentStart]['comment_closer'];
+ }
+
+ for ($i = ($tag + 3); $i < $end; $i++) {
+ if ($tokens[$i]['code'] === T_DOC_COMMENT_STRING) {
+ $indent = 0;
+ if ($tokens[($i - 1)]['code'] === T_DOC_COMMENT_WHITESPACE) {
+ $indent = strlen($tokens[($i - 1)]['content']);
+ }
+
+ $comment .= ' '.$tokens[$i]['content'];
+ $commentLines[] = array(
+ 'comment' => $tokens[$i]['content'],
+ 'token' => $i,
+ 'indent' => $indent,
+ );
+ }
+ }
+ } else {
+ $error = 'Missing parameter comment';
+ $phpcsFile->addError($error, $tag, 'MissingParamComment');
+ $commentLines[] = array('comment' => '');
+ }//end if
+ } else {
+ $error = 'Missing parameter name';
+ $phpcsFile->addError($error, $tag, 'MissingParamName');
+ }//end if
+ } else {
+ $error = 'Missing parameter type';
+ $phpcsFile->addError($error, $tag, 'MissingParamType');
+ }//end if
+
+ $params[] = array(
+ 'tag' => $tag,
+ 'type' => $type,
+ 'var' => $var,
+ 'comment' => $comment,
+ 'commentLines' => $commentLines,
+ 'type_space' => $typeSpace,
+ 'var_space' => $varSpace,
+ );
+ }//end foreach
+
+ $realParams = $phpcsFile->getMethodParameters($stackPtr);
+ $foundParams = array();
+
+ foreach ($params as $pos => $param) {
+ // If the type is empty, the whole line is empty.
+ if ($param['type'] === '') {
+ continue;
+ }
+
+ // Check the param type value.
+ $typeNames = explode('|', $param['type']);
+ foreach ($typeNames as $typeName) {
+ if ($typeName === 'integer') {
+ $suggestedName = 'int';
+ } elseif ($typeName === 'boolean') {
+ $suggestedName = 'bool';
+ } elseif (in_array($typeName, array('int', 'bool'))) {
+ $suggestedName = $typeName;
+ } else {
+ $suggestedName = PHP_CodeSniffer::suggestType($typeName);
+ }
+
+ if ($typeName !== $suggestedName) {
+ $error = 'Expected "%s" but found "%s" for parameter type';
+ $data = array(
+ $suggestedName,
+ $typeName,
+ );
+
+ $fix = $phpcsFile->addFixableError($error, $param['tag'], 'IncorrectParamVarName', $data);
+ if ($fix === true) {
+ $content = $suggestedName;
+ $content .= str_repeat(' ', $param['type_space']);
+ $content .= $param['var'];
+ $content .= str_repeat(' ', $param['var_space']);
+ $content .= $param['commentLines'][0]['comment'];
+ $phpcsFile->fixer->replaceToken(($param['tag'] + 2), $content);
+ }
+ }
+ }//end foreach
+
+ if ($param['var'] === '') {
+ continue;
+ }
+
+ $foundParams[] = $param['var'];
+
+ // Make sure the param name is correct.
+ if (isset($realParams[$pos]) === true) {
+ $realName = $realParams[$pos]['name'];
+ if ($realName !== $param['var']) {
+ $code = 'ParamNameNoMatch';
+ $data = array(
+ $param['var'],
+ $realName,
+ );
+
+ $error = 'Doc comment for parameter %s does not match ';
+ if (strtolower($param['var']) === strtolower($realName)) {
+ $error .= 'case of ';
+ $code = 'ParamNameNoCaseMatch';
+ }
+
+ $error .= 'actual variable name %s';
+
+ $phpcsFile->addWarning($error, $param['tag'], $code, $data);
+ }
+ } elseif (substr($param['var'], -4) !== ',...') {
+ // We must have an extra parameter comment.
+ $error = 'Superfluous parameter comment';
+ $phpcsFile->addError($error, $param['tag'], 'ExtraParamComment');
+ }//end if
+
+ if ($param['comment'] === '') {
+ continue;
+ }
+
+ // Param comments must start with a capital letter and end with the full stop.
+ $firstChar = $param['comment']{0};
+ if (preg_match('|\p{Lu}|u', $firstChar) === 0) {
+ $error = 'Parameter comment must start with a capital letter';
+ $phpcsFile->addWarning($error, $param['tag'], 'ParamCommentNotCapital');
+ }
+
+ $lastChar = substr($param['comment'], -1);
+ if ($lastChar !== '.') {
+ $error = 'Parameter comment must end with a full stop';
+ $phpcsFile->addWarning($error, $param['tag'], 'ParamCommentFullStop');
+ }
+ }//end foreach
+
+ $realNames = array();
+ foreach ($realParams as $realParam) {
+ $realNames[] = $realParam['name'];
+ }
+
+ // Report missing comments.
+ $diff = array_diff($realNames, $foundParams);
+ foreach ($diff as $neededParam) {
+ $error = 'Doc comment for parameter "%s" missing';
+ $data = array($neededParam);
+ $phpcsFile->addWarning($error, $commentStart, 'MissingParamTag', $data);
+ }
+
+ }//end processParams()
+}//end class
diff --git a/tests/codesniffer/FHComplete/Sniffs/Commenting/FunctionCommentTypeSniff.php b/tests/codesniffer/FHComplete/Sniffs/Commenting/FunctionCommentTypeSniff.php
new file mode 100755
index 000000000..722661165
--- /dev/null
+++ b/tests/codesniffer/FHComplete/Sniffs/Commenting/FunctionCommentTypeSniff.php
@@ -0,0 +1,87 @@
+getTokens();
+
+ // We are only interested in function/class/interface doc block comments.
+ $nextToken = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr + 1), null, true);
+ $ignore = array(
+ T_CLASS,
+ T_INTERFACE,
+ T_FUNCTION,
+ T_PUBLIC,
+ T_PRIVATE,
+ T_PROTECTED,
+ T_STATIC,
+ T_ABSTRACT,
+ );
+
+ if (in_array($tokens[$nextToken]['code'], $ignore) === false) {
+ // Could be a file comment.
+ $prevToken = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr - 1), null, true);
+ if ($tokens[$prevToken]['code'] !== T_OPEN_TAG) {
+ return;
+ }
+ }
+
+ $types = array(
+ 'boolean' => 'bool',
+ 'integer' => 'int',
+ );
+ foreach ($types as $from => $to) {
+ $this->_check($phpcsFile, $stackPtr, $from, $to);
+ }
+ }
+
+ /**
+ * MyFHComplete_Sniffs_Commenting_DocBlockTypeSniff::_check()
+ *
+ * @param int $stackPtr
+ * @param string $from
+ * @param string $to
+ * @return void
+ */
+ protected function _check(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $from, $to)
+ {
+ $tokens = $phpcsFile->getTokens();
+ $content = $tokens[$stackPtr]['content'];
+
+ $matches = array();
+ if (preg_match('/\@(\w+)\s+([\w\\|\\\\]*?)' . $from . '\b/i', $content, $matches) === 0) {
+ return;
+ }
+
+ $error = 'Please use "' . $to . '" instead of "' . $from . '" for types in doc blocks.';
+ $phpcsFile->addWarning($error, $stackPtr, 'WrongType');
+ }
+
+}
diff --git a/tests/codesniffer/FHComplete/Sniffs/ControlStructures/ControlSignatureSniff.php b/tests/codesniffer/FHComplete/Sniffs/ControlStructures/ControlSignatureSniff.php
new file mode 100755
index 000000000..b78202cec
--- /dev/null
+++ b/tests/codesniffer/FHComplete/Sniffs/ControlStructures/ControlSignatureSniff.php
@@ -0,0 +1,58 @@
+
+ * @author Marc McIntyre
+ * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
+ * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
+ * @version Release: @package_version@
+ * @link http://pear.php.net/package/PHP_CodeSniffer
+ */
+class FHComplete_Sniffs_ControlStructures_ControlSignatureSniff extends PHP_CodeSniffer_Standards_AbstractPatternSniff
+{
+
+ /**
+ * If true, comments will be ignored if they are found in the code.
+ *
+ * @var boolean
+ */
+ public $ignoreComments = true;
+
+
+ /**
+ * Returns the patterns that this test wishes to verify.
+ *
+ * @return string[]
+ */
+ protected function getPatterns()
+ {
+ return array(
+ 'try {EOL...}\s+catch (...)EOL...{EOL...EOL...}',
+ 'do+EOL...{EOL...EOL...} while (...);EOL',
+ 'while (...)EOL...{EOL',
+ 'for (...) {EOL',
+ 'if (...)EOL...{EOL',
+ 'foreach (...)EOL...{EOL',
+ '}EOL...\s+else if (...)EOL...{EOL',
+ '}EOL...\s+elseif (...)EOL...{EOL',
+ '}EOL...\s+else+EOL...{EOL',
+ 'do+EOL...{EOL',
+ );
+
+ }//end getPatterns()
+
+
+}//end class
diff --git a/tests/codesniffer/FHComplete/Sniffs/ControlStructures/ElseIfDeclarationSniff.php b/tests/codesniffer/FHComplete/Sniffs/ControlStructures/ElseIfDeclarationSniff.php
new file mode 100755
index 000000000..1ef2f2aaf
--- /dev/null
+++ b/tests/codesniffer/FHComplete/Sniffs/ControlStructures/ElseIfDeclarationSniff.php
@@ -0,0 +1,48 @@
+getTokens();
+
+ $nextToken = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true);
+ if ($tokens[$nextToken]['code'] !== T_IF) {
+ return;
+ }
+
+ $error = 'Usage of ELSE IF not allowed; use ELSEIF instead';
+ $phpcsFile->addError($error, $stackPtr, 'NotAllowed');
+ }
+
+}
diff --git a/tests/codesniffer/FHComplete/Sniffs/ControlStructures/WhileStructuresSniff.php b/tests/codesniffer/FHComplete/Sniffs/ControlStructures/WhileStructuresSniff.php
new file mode 100755
index 000000000..421f86ba6
--- /dev/null
+++ b/tests/codesniffer/FHComplete/Sniffs/ControlStructures/WhileStructuresSniff.php
@@ -0,0 +1,56 @@
+getTokens();
+
+ $nextToken = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true);
+ if ($tokens[$nextToken]['code'] === T_OPEN_PARENTHESIS) {
+ $closer = $tokens[$nextToken]['parenthesis_closer'];
+ $diff = $closer - $stackPtr;
+ $nextToken = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + $diff + 1), null, true);
+ }
+
+ if ($tokens[$stackPtr]['code'] === T_WHILE && $tokens[$nextToken]['code'] === T_SEMICOLON) {
+ /* This while is probably part of a do-while construction, skip it .. */
+ return;
+ }
+ if ($tokens[$nextToken]['code'] !== T_OPEN_CURLY_BRACKET && $tokens[$nextToken]['code'] !== T_COLON) {
+ $error = 'Curly brackets required in a do-while or while loop';
+ $phpcsFile->addError($error, $stackPtr, 'NotAllowed');
+ }
+ }
+
+}
diff --git a/tests/codesniffer/FHComplete/Sniffs/Formatting/OneClassPerUseSniff.php b/tests/codesniffer/FHComplete/Sniffs/Formatting/OneClassPerUseSniff.php
new file mode 100755
index 000000000..2b2ee37e6
--- /dev/null
+++ b/tests/codesniffer/FHComplete/Sniffs/Formatting/OneClassPerUseSniff.php
@@ -0,0 +1,48 @@
+getTokens();
+ $i = 2; // Ignore use word and whitespace
+ $filename = $phpcsFile->getFilename();
+
+ while (in_array($tokens[$stackPtr + $i]['code'], array(T_STRING, T_NS_SEPARATOR, T_WHITESPACE, T_AS))) {
+ $i++;
+ }
+
+ if ($tokens[$stackPtr + $i]['code'] === T_COMMA) {
+ $error = 'Only one class is allowed per use';
+ $phpcsFile->addError($error, $stackPtr, 'OneClassPerUse', array());
+ }
+ }
+
+}
diff --git a/tests/codesniffer/FHComplete/Sniffs/Formatting/UseInAlphabeticalOrderSniff.php b/tests/codesniffer/FHComplete/Sniffs/Formatting/UseInAlphabeticalOrderSniff.php
new file mode 100755
index 000000000..43da15876
--- /dev/null
+++ b/tests/codesniffer/FHComplete/Sniffs/Formatting/UseInAlphabeticalOrderSniff.php
@@ -0,0 +1,142 @@
+_processed[$phpcsFile->getFilename()])) {
+ return;
+ }
+ $filename = $phpcsFile->getFilename();
+
+ $this->_uses = array();
+ $next = $stackPtr;
+
+ while ($next !== false) {
+ $this->_checkUseToken($phpcsFile, $next);
+ $next = $phpcsFile->findNext(T_USE, $next + 1);
+ }
+
+ // Prevent multiple uses in the same file from entering
+ $this->_processed[$phpcsFile->getFilename()] = true;
+
+ foreach ($this->_uses as $scope => $used) {
+ $defined = $sorted = array_keys($used);
+
+ natcasesort($sorted);
+ $sorted = array_values($sorted);
+ if ($sorted === $defined) {
+ continue;
+ }
+
+ foreach ($defined as $i => $name) {
+ if ($name !== $sorted[$i]) {
+ $error = 'Use classes must be in alphabetical order. Was expecting ' . $sorted[$i];
+ $phpcsFile->addError($error, $used[$name], 'UseInAlphabeticalOrder', array());
+ }
+ }
+ }
+ }
+
+/**
+ * Check all the use tokens in a file.
+ *
+ * @param PHP_CodeSniffer_File $phpcsFile The file to check.
+ * @param integer $stackPtr The index of the first use token.
+ * @return void
+ */
+ protected function _checkUseToken($phpcsFile, $stackPtr) {
+ // If the use token is for a closure we want to ignore it.
+ $isClosure = $this->_isClosure($phpcsFile, $stackPtr);
+ if ($isClosure) {
+ return;
+ }
+
+ $tokens = $phpcsFile->getTokens();
+
+ // Only one USE declaration allowed per statement.
+ $next = $phpcsFile->findNext(array(T_COMMA, T_SEMICOLON), ($stackPtr + 1));
+ if ($tokens[$next]['code'] === T_COMMA) {
+ $error = 'There must be one USE keyword per declaration';
+ $phpcsFile->addError($error, $stackPtr, 'MultipleDeclarations');
+ }
+
+ $content = '';
+ $end = $phpcsFile->findNext(array(T_SEMICOLON, T_OPEN_CURLY_BRACKET), $stackPtr);
+ $useTokens = array_slice($tokens, $stackPtr, $end - $stackPtr, true);
+
+ foreach ($useTokens as $index => $token) {
+ if ($token['code'] === T_STRING || $token['code'] === T_NS_SEPARATOR) {
+ $content .= $token['content'];
+ }
+ }
+
+ // Check for class scoping on use. Traits should be
+ // ordered independently.
+ $scope = 0;
+ if (!empty($token['conditions'])) {
+ $scope = key($token['conditions']);
+ }
+ $this->_uses[$scope][$content] = $stackPtr;
+ }
+
+/**
+ * Check if the current stackPtr is a use token that is for a closure.
+ *
+ * @param PHP_CodeSniffer_File $phpcsFile
+ * @param integer $stackPtr
+ * @return boolean
+ */
+ protected function _isClosure($phpcsFile, $stackPtr) {
+ return $phpcsFile->findPrevious(
+ array(T_CLOSURE),
+ ($stackPtr - 1),
+ null,
+ false,
+ null,
+ true
+ );
+ }
+
+}
diff --git a/tests/codesniffer/FHComplete/Sniffs/Functions/ClosureDeclarationSniff.php b/tests/codesniffer/FHComplete/Sniffs/Functions/ClosureDeclarationSniff.php
new file mode 100755
index 000000000..6582d3011
--- /dev/null
+++ b/tests/codesniffer/FHComplete/Sniffs/Functions/ClosureDeclarationSniff.php
@@ -0,0 +1,35 @@
+getTokens();
+ $spaces = 0;
+
+ if ($tokens[($stackPtr + 1)]['code'] === T_WHITESPACE) {
+ $spaces = strlen($tokens[($stackPtr + 1)]['content']);
+ }
+
+ if ($spaces !== 1) {
+ $error = 'Expected 1 space after closure\'s function keyword; %s found';
+ $data = array($spaces);
+ $phpcsFile->addError($error, $stackPtr, 'SpaceAfterFunction', $data);
+ }
+ }
+
+}
diff --git a/tests/codesniffer/FHComplete/Sniffs/Functions/FunctionDeclarationArgumentSpacingSniff.php b/tests/codesniffer/FHComplete/Sniffs/Functions/FunctionDeclarationArgumentSpacingSniff.php
new file mode 100755
index 000000000..260ad1c10
--- /dev/null
+++ b/tests/codesniffer/FHComplete/Sniffs/Functions/FunctionDeclarationArgumentSpacingSniff.php
@@ -0,0 +1,26 @@
+
+ * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
+ * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
+ * @link http://pear.php.net/package/PHP_CodeSniffer
+ */
+
+if (class_exists('Generic_Sniffs_NamingConventions_CamelCapsFunctionNameSniff', true) === false) {
+ throw new PHP_CodeSniffer_Exception('Class Generic_Sniffs_NamingConventions_CamelCapsFunctionNameSniff not found');
+}
+
+/**
+ * PSR1_Sniffs_Methods_CamelCapsMethodNameSniff.
+ *
+ * Ensures method names are defined using camel case.
+ *
+ * @category PHP
+ * @package PHP_CodeSniffer
+ * @author Greg Sherwood
+ * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
+ * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
+ * @version Release: @package_version@
+ * @link http://pear.php.net/package/PHP_CodeSniffer
+ */
+class FHComplete_Sniffs_NamingConventions_CamelCapsMethodNameSniff extends Generic_Sniffs_NamingConventions_CamelCapsFunctionNameSniff
+{
+
+
+ /**
+ * Processes the tokens within the scope.
+ *
+ * @param PHP_CodeSniffer_File $phpcsFile The file being processed.
+ * @param int $stackPtr The position where this token was
+ * found.
+ * @param int $currScope The position of the current scope.
+ *
+ * @return void
+ */
+ protected function processTokenWithinScope(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $currScope)
+ {
+ $methodName = $phpcsFile->getDeclarationName($stackPtr);
+ if ($methodName === null
+ || substr($methodName,-4) === '_get'
+ || substr($methodName,-5) === '_post'
+ || substr($methodName,-4) === '_put'
+ || substr($methodName,-6) === '_patch'
+ || substr($methodName,-7) === '_delete'
+ )
+ // Ignore closures.
+ return;
+
+ // Ignore magic methods.
+ if (preg_match('|^__|', $methodName) !== 0) {
+ $magicPart = strtolower(substr($methodName, 2));
+ if (isset($this->magicMethods[$magicPart]) === true
+ || isset($this->methodsDoubleUnderscore[$magicPart]) === true
+ ) {
+ return;
+ }
+ }
+
+ $testName = ltrim($methodName, '_');
+ if ($testName !== '' && PHP_CodeSniffer::isCamelCaps($testName, false, true, false) === false) {
+ $error = 'Method name "%s" is not in camel caps format';
+ $className = $phpcsFile->getDeclarationName($currScope);
+ $errorData = array($className.'::'.$methodName);
+ $phpcsFile->addError($error, $stackPtr, 'NotCamelCaps', $errorData);
+ $phpcsFile->recordMetric($stackPtr, 'CamelCase method name', 'no');
+ } else {
+ $phpcsFile->recordMetric($stackPtr, 'CamelCase method name', 'yes');
+ }
+
+ }//end processTokenWithinScope()
+
+
+ /**
+ * Processes the tokens outside the scope.
+ *
+ * @param PHP_CodeSniffer_File $phpcsFile The file being processed.
+ * @param int $stackPtr The position where this token was
+ * found.
+ *
+ * @return void
+ */
+ protected function processTokenOutsideScope(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
+ {
+
+ }//end processTokenOutsideScope()
+
+
+}//end class
diff --git a/tests/codesniffer/FHComplete/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php b/tests/codesniffer/FHComplete/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php
new file mode 100755
index 000000000..3137ea8cf
--- /dev/null
+++ b/tests/codesniffer/FHComplete/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php
@@ -0,0 +1,223 @@
+
+ * @author Marc McIntyre
+ * @copyright 2006-2012 Squiz Pty Ltd (ABN 77 084 670 600)
+ * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
+ * @version Release: 1.5.0RC3
+ * @link http://pear.php.net/package/PHP_CodeSniffer
+ */
+class FHComplete_Sniffs_NamingConventions_UpperCaseConstantNameSniff implements PHP_CodeSniffer_Sniff
+{
+
+ /**
+ * Returns an array of tokens this test wants to listen for.
+ *
+ * @return array
+ */
+ public function register()
+ {
+ return array(T_STRING);
+ }
+
+ /**
+ * Processes this test, when one of its tokens is encountered.
+ *
+ * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
+ * @param integer $stackPtr The position of the current token in the
+ * stack passed in $tokens.
+ *
+ * @return void
+ */
+ public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
+ {
+ $tokens = $phpcsFile->getTokens();
+ $constName = $tokens[$stackPtr]['content'];
+
+ // If this token is in a heredoc, ignore it.
+ if ($phpcsFile->hasCondition($stackPtr, T_START_HEREDOC) === true) {
+ return;
+ }
+
+ // Special case for PHPUnit.
+ if ($constName === 'PHPUnit_MAIN_METHOD') {
+ return;
+ }
+
+ // If the next non-whitespace token after this token
+ // is not an opening parenthesis then it is not a function call.
+ $openBracket = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true);
+ if ($tokens[$openBracket]['code'] !== T_OPEN_PARENTHESIS) {
+ $functionKeyword = $phpcsFile->findPrevious(
+ array(
+ T_WHITESPACE,
+ T_COMMA,
+ T_COMMENT,
+ T_STRING,
+ T_NS_SEPARATOR,
+ ),
+ ($stackPtr - 1),
+ null,
+ true
+ );
+
+ $declarations = array(
+ T_FUNCTION,
+ T_CLASS,
+ T_INTERFACE,
+ T_TRAIT,
+ T_IMPLEMENTS,
+ T_EXTENDS,
+ T_INSTANCEOF,
+ T_NEW,
+ T_NAMESPACE,
+ T_USE,
+ T_AS,
+ T_GOTO,
+ T_INSTEADOF,
+ T_PROTECTED,
+ T_PRIVATE,
+ T_PUBLIC
+ );
+
+ if (in_array($tokens[$functionKeyword]['code'], $declarations) === true) {
+ // This is just a declaration; no constants here.
+ return;
+ }
+
+ if ($tokens[$functionKeyword]['code'] === T_CONST) {
+ // This is a class constant.
+ if (strtoupper($constName) !== $constName) {
+ $error = 'Class constants must be uppercase; expected %s but found %s';
+ $data = array(
+ strtoupper($constName),
+ $constName,
+ );
+ $phpcsFile->addError($error, $stackPtr, 'ClassConstantNotUpperCase', $data);
+ }
+
+ return;
+ }
+
+ // Is this a class name?
+ $nextPtr = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true);
+ if ($tokens[$nextPtr]['code'] === T_DOUBLE_COLON) {
+ return;
+ }
+
+ // Is this a namespace name?
+ if ($tokens[$nextPtr]['code'] === T_NS_SEPARATOR) {
+ return;
+ }
+
+ // Is this an insteadof name?
+ if ($tokens[$nextPtr]['code'] === T_INSTEADOF) {
+ return;
+ }
+
+ // Is this an as name?
+ if ($tokens[$nextPtr]['code'] === T_AS) {
+ return;
+ }
+
+ // Is this a type hint?
+ if ($tokens[$nextPtr]['code'] === T_VARIABLE
+ || $phpcsFile->isReference($nextPtr) === true
+ ) {
+ return;
+ }
+
+ // Is this a member var name?
+ $prevPtr = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true);
+ if ($tokens[$prevPtr]['code'] === T_OBJECT_OPERATOR) {
+ return;
+ }
+
+ // Is this a variable name, in the form ${varname} ?
+ if ($tokens[$prevPtr]['code'] === T_OPEN_CURLY_BRACKET) {
+ $nextPtr = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true);
+ if ($tokens[$nextPtr]['code'] === T_CLOSE_CURLY_BRACKET) {
+ return;
+ }
+ }
+
+ // Is this a namespace name?
+ if ($tokens[$prevPtr]['code'] === T_NS_SEPARATOR) {
+ return;
+ }
+
+ // Is this an instance of declare()
+ $prevPtrDeclare = $phpcsFile->findPrevious(
+ array(T_WHITESPACE, T_OPEN_PARENTHESIS),
+ ($stackPtr - 1),
+ null,
+ true
+ );
+ if ($tokens[$prevPtrDeclare]['code'] === T_DECLARE) {
+ return;
+ }
+
+ // Is this a goto label target?
+ if ($tokens[$nextPtr]['code'] === T_COLON) {
+ if (in_array($tokens[$prevPtr]['code'], array(T_SEMICOLON, T_OPEN_CURLY_BRACKET, T_COLON), true)) {
+ return;
+ }
+ }
+
+ // This is a real constant.
+ if (strtoupper($constName) !== $constName) {
+ $error = 'Constants must be uppercase; expected %s but found %s';
+ $data = array(
+ strtoupper($constName),
+ $constName,
+ );
+ $phpcsFile->addError($error, $stackPtr, 'ConstantNotUpperCase', $data);
+ }
+
+ } elseif (strtolower($constName) === 'define' || strtolower($constName) === 'constant') {
+ /*
+ This may be a "define" or "constant" function call.
+ */
+ // Make sure this is not a method call.
+ $prev = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true);
+ if ($tokens[$prev]['code'] === T_OBJECT_OPERATOR
+ || $tokens[$prev]['code'] === T_DOUBLE_COLON
+ ) {
+ return;
+ }
+
+ // The next non-whitespace token must be the constant name.
+ $constPtr = $phpcsFile->findNext(T_WHITESPACE, ($openBracket + 1), null, true);
+ if ($tokens[$constPtr]['code'] !== T_CONSTANT_ENCAPSED_STRING) {
+ return;
+ }
+
+ $constName = $tokens[$constPtr]['content'];
+
+ // Check for constants like self::CONSTANT.
+ $prefix = '';
+ $splitPos = strpos($constName, '::');
+ if ($splitPos !== false) {
+ $prefix = substr($constName, 0, ($splitPos + 2));
+ $constName = substr($constName, ($splitPos + 2));
+ }
+
+ if (strtoupper($constName) !== $constName) {
+ $error = 'Constants must be uppercase; expected %s but found %s';
+ $data = array(
+ $prefix . strtoupper($constName),
+ $prefix . $constName,
+ );
+ $phpcsFile->addError($error, $stackPtr, 'ConstantNotUpperCase', $data);
+ }
+ }
+ }
+}
diff --git a/tests/codesniffer/FHComplete/Sniffs/NamingConventions/ValidClassBracketsSniff.php b/tests/codesniffer/FHComplete/Sniffs/NamingConventions/ValidClassBracketsSniff.php
new file mode 100755
index 000000000..a43ac59d0
--- /dev/null
+++ b/tests/codesniffer/FHComplete/Sniffs/NamingConventions/ValidClassBracketsSniff.php
@@ -0,0 +1,47 @@
+getTokens();
+
+ $found = $phpcsFile->findNext(T_OPEN_CURLY_BRACKET, $stackPtr);
+ if ($tokens[$found - 1]['code'] != T_WHITESPACE) {
+ $error = 'Expected 1 space after class declaration, found 0';
+ $phpcsFile->addError($error, $found - 1, 'InvalidSpacing', array());
+ return;
+ }
+
+ if (strlen($tokens[$found - 1]['content']) > 1 || $tokens[$found - 2]['code'] == T_WHITESPACE) {
+ $error = 'Expected 1 space after class declaration, found ' . strlen($tokens[$found - 1]['content']);
+ $phpcsFile->addError($error, $found - 1, 'InvalidSpacing', array());
+ }
+ }
+}
diff --git a/tests/codesniffer/FHComplete/Sniffs/NamingConventions/ValidFunctionNameSniff.php b/tests/codesniffer/FHComplete/Sniffs/NamingConventions/ValidFunctionNameSniff.php
new file mode 100755
index 000000000..3281d83f9
--- /dev/null
+++ b/tests/codesniffer/FHComplete/Sniffs/NamingConventions/ValidFunctionNameSniff.php
@@ -0,0 +1,138 @@
+getDeclarationName($stackPtr);
+ if ($methodName === null) {
+ // Ignore closures.
+ return;
+ }
+
+ $className = $phpcsFile->getDeclarationName($currScope);
+ $errorData = array($className . '::' . $methodName);
+
+ // PHP4 constructors are allowed to break our rules.
+ if ($methodName === $className) {
+ return;
+ }
+
+ // PHP4 destructors are allowed to break our rules.
+ if ($methodName === '_' . $className) {
+ return;
+ }
+
+ // Ignore magic methods
+ if (preg_match('/^__(' . implode('|', $this->_magicMethods) . ')$/', $methodName)) {
+ return;
+ }
+
+ $methodProps = $phpcsFile->getMethodProperties($stackPtr);
+ if ($methodProps['scope_specified'] === false) {
+ // Let another sniffer take care of that
+ return;
+ }
+
+ $isPublic = $methodProps['scope'] === 'public';
+ $isProtected = $methodProps['scope'] === 'protected';
+ $isPrivate = $methodProps['scope'] === 'private';
+ $scope = $methodProps['scope'];
+
+ if ($isPublic === true) {
+ if ($methodName[0] === '_') {
+ $error = 'Public method name "%s" must not be prefixed with underscore';
+ $phpcsFile->addError($error, $stackPtr, 'PublicWithUnderscore', $errorData);
+ return;
+ }
+ // Underscored public methods in controller are allowed to break our rules.
+ if (substr($className, -10) === 'Controller') {
+ return;
+ }
+ // Underscored public methods in shells are allowed to break our rules.
+ if (substr($className, -5) === 'Shell') {
+ return;
+ }
+ // Underscored public methods in tasks are allowed to break our rules.
+ if (substr($className, -4) === 'Task') {
+ return;
+ }
+ } elseif ($isPrivate === true) {
+ if (substr($methodName, 0, 2) !== '__') {
+ $error = 'Private method name "%s" must be prefixed with 2 underscores';
+ $phpcsFile->addError($error, $stackPtr, 'PrivateNoUnderscore', $errorData);
+ return;
+ } else {
+ $filename = $phpcsFile->getFilename();
+ if (strpos($filename, '/lib/Cake/') === true) {
+ $warning = 'Private method name "%s" in FHComplete core is discouraged';
+ $phpcsFile->addWarning($warning, $stackPtr, 'PrivateMethodInCore', $errorData);
+ }
+ }
+ } else {
+ if ($methodName[0] !== '_' || substr($methodName, 0, 2) === '__') {
+ $error = 'Protected method name "%s" must be prefixed with one underscore';
+ $phpcsFile->addError($error, $stackPtr, 'ProtectedNoUnderscore', $errorData);
+ return;
+ }
+ }
+ }
+
+/**
+ * Processes the tokens outside the scope.
+ *
+ * @param PHP_CodeSniffer_File $phpcsFile The file being processed.
+ * @param integer $stackPtr The position where this token was found.
+ * @return void
+ */
+ protected function processTokenOutsideScope(PHP_CodeSniffer_File $phpcsFile, $stackPtr) {
+ }
+
+}
diff --git a/tests/codesniffer/FHComplete/Sniffs/NamingConventions/ValidTraitNameSniff.php b/tests/codesniffer/FHComplete/Sniffs/NamingConventions/ValidTraitNameSniff.php
new file mode 100755
index 000000000..5364eab07
--- /dev/null
+++ b/tests/codesniffer/FHComplete/Sniffs/NamingConventions/ValidTraitNameSniff.php
@@ -0,0 +1,48 @@
+getTokens();
+ $traitName = $tokens[$stackPtr + 2]['content'];
+
+ if (substr($traitName, -5) !== 'Trait') {
+ $error = 'Traits must have a "Trait" suffix.';
+ $phpcsFile->addError($error, $stackPtr, 'InvalidTraitName', array());
+ }
+ }
+}
diff --git a/tests/codesniffer/FHComplete/Sniffs/NamingConventions/ValidVariableNameSniff.php b/tests/codesniffer/FHComplete/Sniffs/NamingConventions/ValidVariableNameSniff.php
new file mode 100755
index 000000000..bce627331
--- /dev/null
+++ b/tests/codesniffer/FHComplete/Sniffs/NamingConventions/ValidVariableNameSniff.php
@@ -0,0 +1,171 @@
+getTokens();
+ $varName = ltrim($tokens[$stackPtr]['content'], '$');
+
+ $phpReservedVars = array(
+ '_SERVER',
+ '_GET',
+ '_POST',
+ '_REQUEST',
+ '_SESSION',
+ '_ENV',
+ '_COOKIE',
+ '_FILES',
+ 'GLOBALS',
+ );
+
+ // If it's a php reserved var, then its ok.
+ if (in_array($varName, $phpReservedVars) === true) {
+ return;
+ }
+
+ // There is no way for us to know if the var is public or private,
+ // so we have to ignore a leading underscore if there is one and just
+ // check the main part of the variable name.
+ $originalVarName = $varName;
+ if (substr($varName, 0, 1) === '_') {
+ $objOperator = $phpcsFile->findPrevious(array(T_WHITESPACE), ($stackPtr - 1), null, true);
+ if ($tokens[$objOperator]['code'] === T_DOUBLE_COLON) {
+ // The variable lives within a class, and is referenced like
+ // this: MyClass::$_variable, so we don't know its scope.
+ $inClass = true;
+ } else {
+ $inClass = $phpcsFile->hasCondition($stackPtr, array(T_TRAIT, T_CLASS, T_INTERFACE));
+ }
+
+ if ($inClass === true) {
+ $varName = ltrim($varName, '_');
+ }
+ }
+
+ // $title_for_layout is allowed on controllers
+ $fileName = basename($phpcsFile->getFilename(), '.php');
+ if ((substr($fileName, -10) === 'Controller') && ($varName == 'title_for_layout')) {
+ return;
+ }
+
+ if ($this->_isValidVar($varName) === false) {
+ $error = 'Variable "%s" is not in valid camel caps format';
+ $data = array($originalVarName);
+ $phpcsFile->addError($error, $stackPtr, 'NotCamelCaps', $data);
+ }
+ }
+
+/**
+ * Processes class member variables.
+ *
+ * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
+ * @param integer $stackPtr The position of the current token in the
+ * stack passed in $tokens.
+ * @return void
+ */
+ protected function processMemberVar(PHP_CodeSniffer_File $phpcsFile, $stackPtr) {
+ }
+
+/**
+ * Processes the variable found within a double quoted string.
+ *
+ * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
+ * @param integer $stackPtr The position of the double quoted string.
+ * @return void
+ */
+ protected function processVariableInString(PHP_CodeSniffer_File $phpcsFile, $stackPtr) {
+ $tokens = $phpcsFile->getTokens();
+
+ $phpReservedVars = array(
+ '_SERVER',
+ '_GET',
+ '_POST',
+ '_REQUEST',
+ '_SESSION',
+ '_ENV',
+ '_COOKIE',
+ '_FILES',
+ 'GLOBALS',
+ );
+
+ if (preg_match_all('|[^\\\]\$([a-zA-Z0-9_]+)|', $tokens[$stackPtr]['content'], $matches) !== 0) {
+ foreach ($matches[1] as $varName) {
+ // If it's a php reserved var, then its ok.
+ if (in_array($varName, $phpReservedVars) === true) {
+ continue;
+ }
+
+ // There is no way for us to know if the var is public or private,
+ // so we have to ignore a leading underscore if there is one and just
+ // check the main part of the variable name.
+ $originalVarName = $varName;
+ if (substr($varName, 0, 1) === '_') {
+ if ($phpcsFile->hasCondition($stackPtr, array(T_CLASS, T_INTERFACE)) === true) {
+ $varName = substr($varName, 1);
+ }
+ }
+
+ if ($this->_isValidVar($varName) === false) {
+ $error = 'Variable "%s" is not in valid camel caps format';
+ $data = array($originalVarName);
+ $phpcsFile->addError($error, $stackPtr, 'StringVarNotCamelCaps', $data);
+ }
+ }
+ }
+ }
+
+/**
+ * Check that a variable is a valid shape.
+ *
+ * Variables in FHComplete can either be $fooBar, $FooBar, $_fooBar, or $_FooBar.
+ *
+ * @param string $string The variable to check.
+ * @param boolea $public Whether or not the variable is public.
+ * @return boolean
+ */
+ protected function _isValidVar($string, $public = true) {
+ $firstChar = '[a-zA-Z]';
+ if (!$public) {
+ $firstChar = '[_]{1,2}' . $firstChar;
+ }
+ if (preg_match("|^$firstChar|", $string) === 0) {
+ return false;
+ }
+ $firstStringCount = 1;
+ if (preg_match("|^__|", $string)) {
+ $firstStringCount = 2;
+ }
+ // Check that the name only contains legal characters.
+ $legalChars = 'a-zA-Z0-9';
+ if (preg_match("|[^$legalChars]|", substr($string, $firstStringCount)) > 0) {
+ return false;
+ }
+ return true;
+ }
+
+}
diff --git a/tests/codesniffer/FHComplete/Sniffs/PHP/DisallowShortOpenTagSniff.php b/tests/codesniffer/FHComplete/Sniffs/PHP/DisallowShortOpenTagSniff.php
new file mode 100755
index 000000000..cd3b8598e
--- /dev/null
+++ b/tests/codesniffer/FHComplete/Sniffs/PHP/DisallowShortOpenTagSniff.php
@@ -0,0 +1,53 @@
+getTokens();
+ $openTag = $tokens[$stackPtr];
+
+ if (trim($openTag['content']) === '') {
+ $error = 'Short PHP opening tag used; expected "addError($error, $stackPtr, 'Found', $data);
+ }
+ }
+}
diff --git a/tests/codesniffer/FHComplete/Sniffs/PHP/TypeCastingSniff.php b/tests/codesniffer/FHComplete/Sniffs/PHP/TypeCastingSniff.php
new file mode 100755
index 000000000..2595c4f56
--- /dev/null
+++ b/tests/codesniffer/FHComplete/Sniffs/PHP/TypeCastingSniff.php
@@ -0,0 +1,74 @@
+getTokens();
+
+ // Process !! casts
+ if ($tokens[$stackPtr]['code'] == T_BOOLEAN_NOT) {
+ $nextToken = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true);
+ if (!$nextToken) {
+ return;
+ }
+ if ($tokens[$nextToken]['code'] != T_BOOLEAN_NOT) {
+ return;
+ }
+ $error = 'Usage of !! cast is not allowed. Please use (bool) to cast.';
+ $phpcsFile->addError($error, $stackPtr, 'NotAllowed');
+
+ return;
+ }
+
+ // Only allow short forms if both short and long forms are possible
+ $matching = array(
+ '(boolean)' => '(bool)',
+ '(integer)' => '(int)',
+ );
+ $content = $tokens[$stackPtr]['content'];
+ $key = strtolower($content);
+ if (isset($matching[$key])) {
+ $error = 'Please use ' . $matching[$key] . ' instead of ' . $content . '.';
+ $phpcsFile->addError($error, $stackPtr, 'NotAllowed');
+ return;
+ }
+ if ($content !== $key) {
+ $error = 'Please use ' . $key . ' instead of ' . $content . '.';
+ $phpcsFile->addError($error, $stackPtr, 'NotAllowed');
+ return;
+ }
+ }
+}
diff --git a/tests/codesniffer/FHComplete/Sniffs/Strings/ConcatenationSpacingSniff.php b/tests/codesniffer/FHComplete/Sniffs/Strings/ConcatenationSpacingSniff.php
new file mode 100755
index 000000000..59eaaf974
--- /dev/null
+++ b/tests/codesniffer/FHComplete/Sniffs/Strings/ConcatenationSpacingSniff.php
@@ -0,0 +1,48 @@
+getTokens();
+ if ($tokens[($stackPtr - 1)]['code'] == T_WHITESPACE) {
+ $message = 'Expected 0 spaces before ., but 1 found';
+ $phpcsFile->addError($message, $stackPtr, 'FoundBefore');
+ }
+
+ if ($tokens[($stackPtr + 1)]['code'] == ' ')
+ {
+ $message = 'Expected 0 spaces after ., but 1 found';
+ $phpcsFile->addError($message, $stackPtr, 'FoundAfter');
+ }
+ }
+}
diff --git a/tests/codesniffer/FHComplete/Sniffs/WhiteSpace/CommaSpacingSniff.php b/tests/codesniffer/FHComplete/Sniffs/WhiteSpace/CommaSpacingSniff.php
new file mode 100755
index 000000000..7506abe9f
--- /dev/null
+++ b/tests/codesniffer/FHComplete/Sniffs/WhiteSpace/CommaSpacingSniff.php
@@ -0,0 +1,54 @@
+getTokens();
+
+ $next = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true);
+
+ if ($tokens[$next]['code'] !== T_WHITESPACE && ($next !== $stackPtr + 2)) {
+ // Last character in a line is ok.
+ if ($tokens[$next]['line'] === $tokens[$stackPtr]['line']) {
+ $error = 'Missing space after comma';
+ $phpcsFile->addError($error, $next);
+ }
+ }
+
+ $previous = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true);
+
+ if ($tokens[$previous]['code'] !== T_WHITESPACE && ($previous !== $stackPtr - 1)) {
+ $error = 'Space before comma, expected none, though';
+ $phpcsFile->addError($error, $next);
+ }
+ }
+}
diff --git a/tests/codesniffer/FHComplete/Sniffs/WhiteSpace/FunctionCallSpacingSniff.php b/tests/codesniffer/FHComplete/Sniffs/WhiteSpace/FunctionCallSpacingSniff.php
new file mode 100755
index 000000000..8a3cbc8e0
--- /dev/null
+++ b/tests/codesniffer/FHComplete/Sniffs/WhiteSpace/FunctionCallSpacingSniff.php
@@ -0,0 +1,53 @@
+getTokens();
+
+ // Find the next non-empty token.
+ $openBracket = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr + 1), null, true);
+
+ if ($tokens[$openBracket]['code'] !== T_OPEN_PARENTHESIS) {
+ // Not a function call.
+ return;
+ }
+
+ // Look for funcName (
+ if (($stackPtr + 1) !== $openBracket) {
+ $error = 'Space before opening parenthesis of function call not allowed';
+ $phpcsFile->addError($error, $stackPtr, 'SpaceBeforeOpenBracket');
+ }
+ }
+}
diff --git a/tests/codesniffer/FHComplete/Sniffs/WhiteSpace/FunctionClosingBraceSpaceSniff.php b/tests/codesniffer/FHComplete/Sniffs/WhiteSpace/FunctionClosingBraceSpaceSniff.php
new file mode 100755
index 000000000..83e7ac73e
--- /dev/null
+++ b/tests/codesniffer/FHComplete/Sniffs/WhiteSpace/FunctionClosingBraceSpaceSniff.php
@@ -0,0 +1,69 @@
+getTokens();
+
+ if (isset($tokens[$stackPtr]['scope_closer']) === false) {
+ // Probably an interface method.
+ return;
+ }
+
+ $closeBrace = $tokens[$stackPtr]['scope_closer'];
+ $prevContent = $phpcsFile->findPrevious(T_WHITESPACE, ($closeBrace - 1), null, true);
+
+ $braceLine = $tokens[$closeBrace]['line'];
+ $prevLine = $tokens[$prevContent]['line'];
+
+ $found = ($braceLine - $prevLine - 1);
+ if ($phpcsFile->hasCondition($stackPtr, T_FUNCTION) === true
+ || isset($tokens[$stackPtr]['nested_parenthesis']) === true
+ ) {
+ // Nested function.
+ if ($found < 0) {
+ $error = 'Closing brace of nested function must be on a new line';
+ $phpcsFile->addError($error, $closeBrace, 'ContentBeforeClose');
+ } elseif ($found > 0) {
+ $error = 'Expected 0 blank lines before closing brace of nested function; %s found';
+ $data = array($found);
+ $phpcsFile->addError($error, $closeBrace, 'SpacingBeforeNestedClose', $data);
+ }
+ } else {
+ if ($found !== 0) {
+ $error = 'Expected 0 blank lines before closing function brace; %s found';
+ $data = array($found);
+ $phpcsFile->addError($error, $closeBrace, 'SpacingBeforeClose', $data);
+ }
+ }
+ }
+}
diff --git a/tests/codesniffer/FHComplete/Sniffs/WhiteSpace/FunctionOpeningBraceSpaceSniff.php b/tests/codesniffer/FHComplete/Sniffs/WhiteSpace/FunctionOpeningBraceSpaceSniff.php
new file mode 100755
index 000000000..d202e760a
--- /dev/null
+++ b/tests/codesniffer/FHComplete/Sniffs/WhiteSpace/FunctionOpeningBraceSpaceSniff.php
@@ -0,0 +1,62 @@
+getTokens();
+
+ if (isset($tokens[$stackPtr]['scope_opener']) === false) {
+ // Probably an interface method.
+ return;
+ }
+
+ $openBrace = $tokens[$stackPtr]['scope_opener'];
+ $nextContent = $phpcsFile->findNext(T_WHITESPACE, ($openBrace + 1), null, true);
+
+ if ($nextContent === $tokens[$stackPtr]['scope_closer']) {
+ // The next bit of content is the closing brace, so this
+ // is an empty function and should have a blank line
+ // between the opening and closing braces.
+ return;
+ }
+
+ $braceLine = $tokens[$openBrace]['line'];
+ $nextLine = $tokens[$nextContent]['line'];
+
+ $found = ($nextLine - $braceLine - 1);
+ if ($found > 0) {
+ $error = 'Expected 0 blank lines after opening function brace; %s found';
+ $data = array($found);
+ $phpcsFile->addError($error, $openBrace, 'SpacingAfter', $data);
+ }
+ }
+}
diff --git a/tests/codesniffer/FHComplete/Sniffs/WhiteSpace/FunctionSpacingSniff.php b/tests/codesniffer/FHComplete/Sniffs/WhiteSpace/FunctionSpacingSniff.php
new file mode 100755
index 000000000..09f6a55b0
--- /dev/null
+++ b/tests/codesniffer/FHComplete/Sniffs/WhiteSpace/FunctionSpacingSniff.php
@@ -0,0 +1,129 @@
+getTokens();
+
+ /*
+ Check the number of blank lines
+ after the function.
+ */
+
+ if (isset($tokens[$stackPtr]['scope_closer']) === false) {
+ // Must be an interface method, so the closer is the semi-colon.
+ $closer = $phpcsFile->findNext(T_SEMICOLON, $stackPtr);
+ } else {
+ $closer = $tokens[$stackPtr]['scope_closer'];
+ }
+
+ // There needs to be 1 blank lines after the closer.
+ $nextLineToken = null;
+ for ($i = $closer; $i < $phpcsFile->numTokens; $i++) {
+ if (strpos($tokens[$i]['content'], $phpcsFile->eolChar) === false) {
+ continue;
+ } else {
+ $nextLineToken = ($i + 1);
+ break;
+ }
+ }
+
+ if ($nextLineToken === null) {
+ // Never found the next line, which means
+ // there are 0 blank lines after the function.
+ $foundLines = 0;
+ } else {
+ $nextContent = $phpcsFile->findNext(array(T_WHITESPACE), ($nextLineToken + 1), null, true);
+ if ($nextContent === false) {
+ // We are at the end of the file. That is acceptable as well.
+ $foundLines = 1;
+ } else {
+ $foundLines = ($tokens[$nextContent]['line'] - $tokens[$nextLineToken]['line']);
+ }
+ }
+
+ /*
+ Check the number of blank lines
+ before the function.
+ */
+
+ $prevLineToken = null;
+ for ($i = $stackPtr; $i > 0; $i--) {
+ if (strpos($tokens[$i]['content'], $phpcsFile->eolChar) === false) {
+ continue;
+ } else {
+ $prevLineToken = $i;
+ break;
+ }
+ }
+
+ if ($prevLineToken === null) {
+ // Never found the previous line, which means
+ // there are 0 blank lines before the function.
+ $foundLines = 0;
+ } else {
+ $prevContent = $phpcsFile->findPrevious(array(T_WHITESPACE, T_DOC_COMMENT), $prevLineToken, null, true);
+
+ // Before we throw an error, check that we are not throwing an error
+ // for another function. We don't want to error for no blank lines after
+ // the previous function and no blank lines before this one as well.
+ $currentLine = $tokens[$stackPtr]['line'];
+ $prevLine = ($tokens[$prevContent]['line'] - 1);
+ $i = ($stackPtr - 1);
+ $foundLines = 0;
+ while ($currentLine !== $prevLine && $currentLine > 1 && $i > 0) {
+ if (isset($tokens[$i]['scope_condition']) === true) {
+ $scopeCondition = $tokens[$i]['scope_condition'];
+ if ($tokens[$scopeCondition]['code'] === T_FUNCTION) {
+ // Found a previous function.
+ return;
+ }
+ } elseif ($tokens[$i]['code'] === T_FUNCTION) {
+ // Found another interface function.
+ return;
+ }
+
+ $currentLine = $tokens[$i]['line'];
+ if ($currentLine === $prevLine) {
+ break;
+ }
+
+ if ($tokens[($i - 1)]['line'] < $currentLine && $tokens[($i + 1)]['line'] > $currentLine) {
+ // This token is on a line by itself. If it is whitespace, the line is empty.
+ if ($tokens[$i]['code'] === T_WHITESPACE) {
+ $foundLines++;
+ }
+ }
+ $i--;
+ }
+ }
+ }
+}
diff --git a/tests/codesniffer/FHComplete/Sniffs/WhiteSpace/ObjectOperatorSpacingSniff.php b/tests/codesniffer/FHComplete/Sniffs/WhiteSpace/ObjectOperatorSpacingSniff.php
new file mode 100755
index 000000000..a52680736
--- /dev/null
+++ b/tests/codesniffer/FHComplete/Sniffs/WhiteSpace/ObjectOperatorSpacingSniff.php
@@ -0,0 +1,42 @@
+getTokens();
+
+ $nextType = $tokens[($stackPtr + 1)]['code'];
+ if (in_array($nextType, PHP_CodeSniffer_Tokens::$emptyTokens) === true) {
+ $error = 'Space found after object operator';
+ $phpcsFile->addError($error, $stackPtr, 'After');
+ }
+ }
+}
diff --git a/tests/codesniffer/FHComplete/Sniffs/WhiteSpace/OperatorSpacingSniff.php b/tests/codesniffer/FHComplete/Sniffs/WhiteSpace/OperatorSpacingSniff.php
new file mode 100755
index 000000000..efeef023a
--- /dev/null
+++ b/tests/codesniffer/FHComplete/Sniffs/WhiteSpace/OperatorSpacingSniff.php
@@ -0,0 +1,185 @@
+getTokens();
+
+ // Skip default values in function declarations.
+ if ($tokens[$stackPtr]['code'] === T_EQUAL
+ || $tokens[$stackPtr]['code'] === T_MINUS
+ ) {
+ if (isset($tokens[$stackPtr]['nested_parenthesis']) === true) {
+ $parenthesis = array_keys($tokens[$stackPtr]['nested_parenthesis']);
+ $bracket = array_pop($parenthesis);
+ if (isset($tokens[$bracket]['parenthesis_owner']) === true) {
+ $function = $tokens[$bracket]['parenthesis_owner'];
+ if ($tokens[$function]['code'] === T_FUNCTION) {
+ return;
+ }
+ }
+ }
+ }
+
+ if ($tokens[$stackPtr]['code'] === T_EQUAL) {
+ // Skip for '=&' case.
+ if (isset($tokens[($stackPtr + 1)]) === true && $tokens[($stackPtr + 1)]['code'] === T_BITWISE_AND) {
+ return;
+ }
+ }
+
+ if ($tokens[$stackPtr]['code'] === T_BITWISE_AND) {
+ // If its not a reference, then we expect one space either side of the
+ // bitwise operator.
+ if (!$phpcsFile->isReference($stackPtr) && !$this->isVariable($stackPtr, $tokens, $phpcsFile)) {
+ // Check there is one space before the & operator.
+ if ($tokens[($stackPtr - 1)]['code'] !== T_WHITESPACE) {
+ $error = 'Expected 1 space before "&" operator; 0 found';
+ $phpcsFile->addError($error, $stackPtr, 'NoSpaceBeforeAmp');
+ }
+
+ // Check there is one space after the & operator.
+ if ($tokens[($stackPtr + 1)]['code'] !== T_WHITESPACE) {
+ $error = 'Expected 1 space after "&" operator; 0 found';
+ $phpcsFile->addError($error, $stackPtr, 'NoSpaceAfterAmp');
+ }
+ }
+ } else {
+ if ($tokens[$stackPtr]['code'] === T_MINUS) {
+ // Skip declaration of negative value in new array format; eg. $arr = [-1].
+ if ($tokens[($stackPtr - 1)]['code'] === T_OPEN_SHORT_ARRAY) {
+ return;
+ }
+
+ // Check minus spacing, but make sure we aren't just assigning
+ // a minus value or returning one.
+ $prev = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true);
+ if ($tokens[$prev]['code'] === T_RETURN) {
+ // Just returning a negative value; eg. return -1.
+ return;
+ }
+
+ if (in_array($tokens[$prev]['code'], PHP_CodeSniffer_Tokens::$operators) === true) {
+ // Just trying to operate on a negative value; eg. ($var * -1).
+ return;
+ }
+
+ if (in_array($tokens[$prev]['code'], PHP_CodeSniffer_Tokens::$comparisonTokens) === true) {
+ // Just trying to compare a negative value; eg. ($var === -1).
+ return;
+ }
+
+ // A list of tokens that indicate that the token is not
+ // part of an arithmetic operation.
+ $invalidTokens = array(
+ T_COMMA,
+ T_OPEN_PARENTHESIS,
+ T_OPEN_SQUARE_BRACKET,
+ T_DOUBLE_ARROW,
+ T_COLON,
+ T_INLINE_THEN,
+ T_INLINE_ELSE,
+ T_CASE,
+ );
+
+ if (in_array($tokens[$prev]['code'], $invalidTokens) === true) {
+ // Just trying to use a negative value; eg. myFunction($var, -2).
+ return;
+ }
+ if (in_array($tokens[$prev]['code'], PHP_CodeSniffer_Tokens::$assignmentTokens) === true) {
+ // Just trying to assign a negative value; eg. ($var = -1).
+ return;
+ }
+ }
+
+ $operator = $tokens[$stackPtr]['content'];
+
+ if ($tokens[($stackPtr - 1)]['code'] !== T_WHITESPACE) {
+ $error = "Expected 1 space before \"$operator\"; 0 found";
+ $phpcsFile->addError($error, $stackPtr, 'NoSpaceBefore');
+ }
+
+ if ($tokens[($stackPtr + 1)]['code'] !== T_WHITESPACE) {
+ $error = "Expected 1 space after \"$operator\"; 0 found";
+ $phpcsFile->addError($error, $stackPtr, 'NoSpaceAfter');
+ }
+ }
+ }
+
+ /**
+ * Check if the current token is inside an array.
+ *
+ * @param int $stackPtr The current token offset.
+ * @param array $phpcsFile The current token list.
+ * @return bool
+ */
+ protected function isVariable($stackPtr, $tokens, $phpcsFile)
+ {
+ $tokenAfter = $phpcsFile->findNext(
+ PHP_CodeSniffer_Tokens::$emptyTokens,
+ ($stackPtr + 1),
+ null,
+ true
+ );
+ $tokenBefore = $phpcsFile->findNext(
+ PHP_CodeSniffer_Tokens::$emptyTokens,
+ ($stackPtr - 1),
+ null,
+ true
+ );
+
+ if ($tokens[$tokenAfter]['code'] === T_VARIABLE &&
+ (
+ $tokens[$tokenBefore]['code'] === T_OPEN_PARENTHESIS ||
+ $tokens[$tokenBefore]['code'] === T_COMMA ||
+ $tokens[$tokenBefore]['code'] === T_OPEN_SHORT_ARRAY
+ )
+ ) {
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/tests/codesniffer/FHComplete/Sniffs/WhiteSpace/ScopeIndentSniff.php b/tests/codesniffer/FHComplete/Sniffs/WhiteSpace/ScopeIndentSniff.php
new file mode 100755
index 000000000..b3e998ed4
--- /dev/null
+++ b/tests/codesniffer/FHComplete/Sniffs/WhiteSpace/ScopeIndentSniff.php
@@ -0,0 +1,280 @@
+getTokens();
+
+ // If this is an inline condition (ie. there is no scope opener), then
+ // return, as this is not a new scope.
+ if (isset($tokens[$stackPtr]['scope_opener']) === false) {
+ return;
+ }
+
+ if ($tokens[$stackPtr]['code'] === T_ELSE) {
+ $next = $phpcsFile->findNext(
+ PHP_CodeSniffer_Tokens::$emptyTokens,
+ ($stackPtr + 1),
+ null,
+ true
+ );
+
+ // We will handle the T_IF token in another call to process.
+ if ($tokens[$next]['code'] === T_IF) {
+ return;
+ }
+ }
+
+ // Find the first token on this line.
+ $firstToken = $stackPtr;
+ for ($i = $stackPtr; $i >= 0; $i--) {
+ // Record the first code token on the line.
+ if (in_array($tokens[$i]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === false) {
+ $firstToken = $i;
+ }
+
+ // It's the start of the line, so we've found our first php token.
+ if ($tokens[$i]['column'] === 1) {
+ break;
+ }
+ }
+
+ // Based on the conditions that surround this token, determine the
+ // indent that we expect this current content to be.
+ $expectedIndent = $this->calculateExpectedIndent($tokens, $firstToken);
+
+ $scopeOpener = $tokens[$stackPtr]['scope_opener'];
+ $scopeCloser = $tokens[$stackPtr]['scope_closer'];
+
+ // Some scopes are expected not to have indents.
+ if (in_array($tokens[$firstToken]['code'], $this->nonIndentingScopes) === false) {
+ $indent = ($expectedIndent + $this->indent);
+ } else {
+ $indent = $expectedIndent;
+ }
+
+ $newline = false;
+ $commentOpen = false;
+ $inHereDoc = false;
+
+ // Only loop over the content beween the opening and closing brace, not
+ // the braces themselves.
+ for ($i = ($scopeOpener + 1); $i < $scopeCloser; $i++) {
+ // If this token is another scope, skip it as it will be handled by
+ // another call to this sniff.
+ if (in_array($tokens[$i]['code'], PHP_CodeSniffer_Tokens::$scopeOpeners) === true) {
+ if (isset($tokens[$i]['scope_opener']) === true) {
+ $i = $tokens[$i]['scope_closer'];
+
+ // If the scope closer is followed by a semi-colon, the semi-colon is part
+ // of the closer and should also be ignored. This most commonly happens with
+ // CASE statements that end with "break;", where we don't want to stop
+ // ignoring at the break, but rather at the semi-colon.
+ $nextToken = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($i + 1), null, true);
+ if ($tokens[$nextToken]['code'] === T_SEMICOLON) {
+ $i = $nextToken;
+ }
+ } else {
+ // If this token does not have a scope_opener indice, then
+ // it's probably an inline scope, so let's skip to the next
+ // semicolon. Inline scopes include inline if's, abstract
+ // methods etc.
+ $nextToken = $phpcsFile->findNext(T_SEMICOLON, $i, $scopeCloser);
+ if ($nextToken !== false) {
+ $i = $nextToken;
+ }
+ }
+ continue;
+ }
+
+ // If this is a HEREDOC then we need to ignore it as the
+ // whitespace before the contents within the HEREDOC are
+ // considered part of the content.
+ if ($tokens[$i]['code'] === T_START_HEREDOC) {
+ $inHereDoc = true;
+ continue;
+ } elseif ($inHereDoc === true) {
+ if ($tokens[$i]['code'] === T_END_HEREDOC) {
+ $inHereDoc = false;
+ }
+ continue;
+ }
+
+ if ($tokens[$i]['column'] === 1) {
+ // We started a newline.
+ $newline = true;
+ }
+
+ if ($newline === true && $tokens[$i]['code'] !== T_WHITESPACE) {
+ // If we started a newline and we find a token that is not
+ // whitespace, then this must be the first token on the line that
+ // must be indented.
+ $newline = false;
+ $firstToken = $i;
+
+ $column = $tokens[$firstToken]['column'];
+
+ // Special case for non-PHP code.
+ if ($tokens[$firstToken]['code'] === T_INLINE_HTML) {
+ $trimmedContentLength = strlen(ltrim($tokens[$firstToken]['content']));
+ if ($trimmedContentLength === 0) {
+ continue;
+ }
+
+ $contentLength = strlen($tokens[$firstToken]['content']);
+ $column = ($contentLength - $trimmedContentLength + 1);
+ }
+
+ // If we're starting a new PHP block that has the scope closer
+ // as the next token we'll skip the remaining checks as the scope is closed.
+ if ($tokens[$firstToken]['code'] === T_OPEN_TAG &&
+ $scopeCloser == $firstToken + 1
+ ) {
+ continue;
+ }
+
+ // Check to see if this constant string spans multiple lines.
+ // If so, then make sure that the strings on lines other than the
+ // first line are indented appropriately, based on their whitespace.
+ if (in_array($tokens[$firstToken]['code'], PHP_CodeSniffer_Tokens::$stringTokens) === true) {
+ if (in_array($tokens[($firstToken - 1)]['code'], PHP_CodeSniffer_Tokens::$stringTokens) === true) {
+ // If we find a string that directly follows another string
+ // then its just a string that spans multiple lines, so we
+ // don't need to check for indenting.
+ continue;
+ }
+ }
+
+ // This is a special condition for T_DOC_COMMENT and C-style
+ // comments, which contain whitespace between each line.
+ $comments = array(
+ T_COMMENT,
+ T_DOC_COMMENT
+ );
+
+ $isDocComment = false;
+ if (in_array($tokens[$firstToken]['code'], $comments) === true) {
+ $content = trim($tokens[$firstToken]['content']);
+ if (preg_match('|^/\*|', $content) !== 0) {
+ // Check to see if the end of the comment is on the same line
+ // as the start of the comment. If it is, then we don't
+ // have to worry about opening a comment.
+ if (preg_match('|\*/$|', $content) === 0) {
+ // We don't have to calculate the column for the
+ // start of the comment as there is a whitespace
+ // token before it.
+ $commentOpen = true;
+ $isDocComment = (substr($content, 0, 3) === '/**');
+ }
+ } elseif ($commentOpen === true) {
+ if ($content === '') {
+ // We are in a comment, but this line has nothing on it
+ // so let's skip it.
+ continue;
+ }
+
+ $contentLength = strlen($tokens[$firstToken]['content']);
+ $trimmedContentLength = strlen(ltrim($tokens[$firstToken]['content']));
+
+ $column = ($contentLength - $trimmedContentLength + 1);
+ if (preg_match('|\*/$|', $content) !== 0) {
+ $commentOpen = false;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Calculates the expected indent of a token.
+ *
+ * @param array $tokens The stack of tokens for this file.
+ * @param int $stackPtr The position of the token to get indent for.
+ * @return int
+ */
+ protected function calculateExpectedIndent(array $tokens, $stackPtr)
+ {
+ $conditionStack = array();
+
+ // Empty conditions array (top level structure).
+ if (empty($tokens[$stackPtr]['conditions']) === true) {
+ if (isset($tokens[$stackPtr]['nested_parenthesis']) === true
+ && empty($tokens[$stackPtr]['nested_parenthesis']) === false
+ ) {
+ // Wrapped in parenthesis means it is probably in a
+ // function call (like a closure) so we have to assume indent
+ // is correct here and someone else will check it more
+ // carefully in another sniff.
+ return $tokens[$stackPtr]['column'];
+ } else {
+ return 1;
+ }
+ }
+
+ $tokenConditions = $tokens[$stackPtr]['conditions'];
+ foreach ($tokenConditions as $id => $condition) {
+ // If it's an indenting scope ie. it's not in our array of
+ // scopes that don't indent, add it to our condition stack.
+ if (in_array($condition, $this->nonIndentingScopes) === false) {
+ $conditionStack[$id] = $condition;
+ }
+ }
+ return ((count($conditionStack) * $this->indent) + 1);
+ }
+}
diff --git a/tests/codesniffer/FHComplete/Sniffs/WhiteSpace/TabAndSpaceSniff.php b/tests/codesniffer/FHComplete/Sniffs/WhiteSpace/TabAndSpaceSniff.php
new file mode 100755
index 000000000..0c2593aa1
--- /dev/null
+++ b/tests/codesniffer/FHComplete/Sniffs/WhiteSpace/TabAndSpaceSniff.php
@@ -0,0 +1,63 @@
+getTokens();
+
+ $line = $tokens[$stackPtr]['line'];
+ if ($stackPtr > 0 && $tokens[($stackPtr - 1)]['line'] !== $line) {
+ return;
+ }
+
+ if (strpos($tokens[$stackPtr]['content'], " \t") !== false) {
+ $error = 'Space and tab found';
+ $phpcsFile->addError($error, $stackPtr);
+ }
+ if (strpos($tokens[$stackPtr]['content'], "\t ") !== false) {
+ $error = 'Tab and space found';
+ $phpcsFile->addError($error, $stackPtr);
+ }
+ }
+}
diff --git a/tests/codesniffer/FHComplete/ruleset.xml b/tests/codesniffer/FHComplete/ruleset.xml
new file mode 100755
index 000000000..6673d18fe
--- /dev/null
+++ b/tests/codesniffer/FHComplete/ruleset.xml
@@ -0,0 +1,92 @@
+
+
+ FHComplete's coding standard
+
+ \.git
+ */Config/*.ini.php
+ /*/tmp/
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ */tests/*
+
+
+ */tests/*
+
+
+
+
+
diff --git a/tests/codesniffer/FHComplete/tests/FHCompletePHPStandardTest.php b/tests/codesniffer/FHComplete/tests/FHCompletePHPStandardTest.php
new file mode 100755
index 000000000..8c933aa95
--- /dev/null
+++ b/tests/codesniffer/FHComplete/tests/FHCompletePHPStandardTest.php
@@ -0,0 +1,67 @@
+helper)) {
+ $this->helper = new TestHelper();
+ }
+ }
+
+/**
+ * testFiles
+ *
+ * Run simple syntax checks, if the filename ends with pass.php - expect it to pass
+ */
+ public static function testProvider() {
+ $tests = array();
+
+ $standard = dirname(dirname(__FILE__));
+
+ $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator(dirname(__FILE__) . '/files'));
+ foreach ($iterator as $dir) {
+ if ($dir->isDir()) {
+ continue;
+ }
+
+ $file = $dir->getPathname();
+ $expectPass = (substr($file, -8) === 'pass.php');
+ $tests[] = array(
+ $file,
+ $standard,
+ $expectPass
+ );
+ }
+ return $tests;
+ }
+
+/**
+ * _testFile
+ *
+ * @dataProvider testProvider
+ *
+ * @param string $file
+ * @param string $standard
+ * @param boolean $expectPass
+ */
+ public function testFile($file, $standard, $expectPass) {
+ $outputStr = $this->helper->runPhpCs($file);
+ if ($expectPass) {
+ $this->assertNotRegExp(
+ "/FOUND \d+ ERROR/",
+ $outputStr,
+ basename($file) . ' - expected to pass with no errors, some were reported. '
+ );
+ } else {
+ $this->assertRegExp(
+ "/FOUND \d+ ERROR/",
+ $outputStr,
+ basename($file) . ' - expected failures, none reported. '
+ );
+ }
+ }
+
+}
diff --git a/tests/codesniffer/FHComplete/tests/TestHelper.php b/tests/codesniffer/FHComplete/tests/TestHelper.php
new file mode 100755
index 000000000..4d86b5fe4
--- /dev/null
+++ b/tests/codesniffer/FHComplete/tests/TestHelper.php
@@ -0,0 +1,54 @@
+_phpcs = new PHP_CodeSniffer_CLI();
+ }
+
+/**
+ * Run PHPCS on a file.
+ *
+ * @param string $file to run.
+ * @return string The output from phpcs.
+ */
+ public function runPhpCs($file) {
+ $defaults = $this->_phpcs->getDefaults();
+ $standard = dirname(__FILE__) . '/ruleset.xml';
+ if (
+ defined('PHP_CodeSniffer::VERSION') &&
+ version_compare(PHP_CodeSniffer::VERSION, '1.5.0') != -1
+ ) {
+ $standard = array($standard);
+ }
+ $options = array(
+ 'encoding' => 'utf-8',
+ 'files' => array($file),
+ 'standard' => $standard,
+ 'showSources' => true,
+ ) + $defaults;
+
+ // New PHPCS has a strange issue where the method arguments
+ // are not stored on the instance causing weird errors.
+ $reflection = new ReflectionProperty($this->_phpcs, 'values');
+ $reflection->setAccessible(true);
+ $reflection->setValue($this->_phpcs, $options);
+
+ ob_start();
+ $this->_phpcs->process($options);
+ $result = ob_get_contents();
+ ob_end_clean();
+ return $result;
+ }
+
+}
diff --git a/tests/codesniffer/FHComplete/tests/bootstrap.php b/tests/codesniffer/FHComplete/tests/bootstrap.php
new file mode 100755
index 000000000..b6ef51c7c
--- /dev/null
+++ b/tests/codesniffer/FHComplete/tests/bootstrap.php
@@ -0,0 +1,2 @@
+ 100) {
+ echo 'i > 100';
+}
+
+while (false) {
+ echo 'false';
+}
+
+do {
+ echo 'dowhile test';
+} while (false);
diff --git a/tests/codesniffer/FHComplete/tests/files/control_structure_dowhile.php b/tests/codesniffer/FHComplete/tests/files/control_structure_dowhile.php
new file mode 100755
index 000000000..54b2190d4
--- /dev/null
+++ b/tests/codesniffer/FHComplete/tests/files/control_structure_dowhile.php
@@ -0,0 +1,6 @@
+something ('testing');
+fail_whale ();
diff --git a/tests/codesniffer/FHComplete/tests/files/mixing_indent.php b/tests/codesniffer/FHComplete/tests/files/mixing_indent.php
new file mode 100755
index 000000000..0400dd514
--- /dev/null
+++ b/tests/codesniffer/FHComplete/tests/files/mixing_indent.php
@@ -0,0 +1,6 @@
+ 'after 2 tabs'
+ );
+}
diff --git a/tests/codesniffer/FHComplete/tests/files/multiple_use.php b/tests/codesniffer/FHComplete/tests/files/multiple_use.php
new file mode 100755
index 000000000..b239a6419
--- /dev/null
+++ b/tests/codesniffer/FHComplete/tests/files/multiple_use.php
@@ -0,0 +1,6 @@
+
+
+
+echo "this should fail";
diff --git a/tests/codesniffer/FHComplete/tests/files/short_open_tags_pass.php b/tests/codesniffer/FHComplete/tests/files/short_open_tags_pass.php
new file mode 100755
index 000000000..0bdfd43fb
--- /dev/null
+++ b/tests/codesniffer/FHComplete/tests/files/short_open_tags_pass.php
@@ -0,0 +1,6 @@
+
+
+= "this should pass";
diff --git a/tests/codesniffer/FHComplete/tests/files/space_tab.php b/tests/codesniffer/FHComplete/tests/files/space_tab.php
new file mode 100755
index 000000000..132eca1a5
--- /dev/null
+++ b/tests/codesniffer/FHComplete/tests/files/space_tab.php
@@ -0,0 +1,2 @@
+passingPublic = 'changed';
+ $this->underscored = 'has value now';
+ $this->doubleUnderscore = 'not recommended';
+ }
+
+ /**
+ * [setStatics description]
+ *
+ * @return void
+ */
+ public static function setStatics()
+ {
+ self::$publicStatic = true;
+ self::$protectedStatic = true;
+ self::$privateStatic = true;
+ }
+}
diff --git a/tests/codesniffer/FHComplete/tests/files/whitespace_comma.php b/tests/codesniffer/FHComplete/tests/files/whitespace_comma.php
new file mode 100755
index 000000000..78e43d5f0
--- /dev/null
+++ b/tests/codesniffer/FHComplete/tests/files/whitespace_comma.php
@@ -0,0 +1,2 @@
+
+
+ FH-Complete coding standard
+
+
+
+
+ 0
+
+
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
|