This commit is contained in:
patrik2020 2022-10-15 06:47:55 +02:00
commit 58b498821d
1881 changed files with 22196 additions and 29540 deletions

View File

@ -3551,7 +3551,7 @@ class SurveyAdmin
// VSEBINA POSAMEZNEGA TABA PRI MOJIH ANKETAH
echo '<div id="moje_ankete_edit" class="page_'.$_GET['a'].' subpage_'.$_GET['t'].' '.(isset($_GET['b']) ? 'subpage_b_'.$_GET['b'] : '').' '.($SLCount == 0 ? 'page_ustvari_anketo' : '').' '.($SLCount > 0 && $has_folders ? 'moje_ankete_folders' : '').' '.$this->layout_width.' '.$this->layout_menu.'">';
echo '<div id="moje_ankete_edit" class="page_'.$_GET['a'].' subpage_'.$_GET['t'].' '.(isset($_GET['b']) ? 'subpage_b_'.$_GET['b'] : '').' '.($SLCount == 0 ? 'page_ustvari_anketo' : '').' '.$this->layout_width.' '.$this->layout_menu.'">';
// izpis pregledovanja
if ((!isset($_GET['a']) && !isset($_GET['anketa'])) || ($_GET['a'] == 'pregledovanje')) {

View File

@ -237,8 +237,10 @@ class SurveyList {
$userAccess = UserAccess::getInstance($global_user_id);
$detect = New Mobile_Detect();
if($userAccess->checkUserAccess('my_survey_folders') && !$detect->isMobile() && !$detect->isTablet())
if($userAccess->checkUserAccess('my_survey_folders') && !$detect->isMobile() && !$detect->isTablet()){
UserSetting::getInstance()->Init($global_user_id);
$show_folders = UserSetting::getInstance()->getUserSetting('survey_list_folders');
}
if($show_folders == '1')
return true;
@ -1757,7 +1759,8 @@ class SurveyList {
echo '<input id="searchMySurvey" type="text" value="" placeholder="'.$lang['s_search_mySurvey'].'" name="search" />';
echo ' <button class="medium white-black" onclick="$(\'#1kasmysurvey\').submit(); return false;">';
echo $lang['s_search2'];
//echo $lang['s_search2'];
echo ' <span class="faicon search"></span>';
echo ' </button>';
echo '</form>';

View File

@ -37,6 +37,10 @@ class SurveyListFolders extends SurveyList{
echo ' </div>';
echo '</div>';
// JS za drag/drop
echo '<script type="text/javascript">mySurvey_folder_init();</script>';
}
@ -48,7 +52,33 @@ class SurveyListFolders extends SurveyList{
echo '<div class="title">'.$lang['srv_mySurvey_your_folders'].'</div>';
// Izpisemo seznam folder s seznamom childov v rootu
echo '<ul id="folder_list_0" class="folder_list">';
$this->displayFolderList(0);
echo '</ul>';
// Prikazemo se skrit div za dodaten popup (rename, add - title)
echo '<div id="mySurvey_additional_popup" class="divPopUp"></div>';
// Klik izven "Vec" - zapremo okno
echo '<script>
$(document).mouseup(function(e){
var container = $(".folder_item_settings, .dots_ver");
if (!container.is(e.target) && container.has(e.target).length === 0){
$(".folder_item_settings").addClass("displayNone");
$(".dots_ver_folder").removeClass("active");
}
var container2 = $(".item_settings, .dots_ver");
if (!container.is(e.target) && container.has(e.target).length === 0){
$(".item_settings").addClass("displayNone");
$(".dots_ver_item").removeClass("active");
}
});
initHideLibraryArrows();
</script>';
}
// Izpisemo seznam folderjev za posameznega parenta
@ -56,10 +86,10 @@ class SurveyListFolders extends SurveyList{
global $global_user_id;
// Izpisemo folder box
$this->displayFolder($folder_id);
$folder_open = $this->displayFolder($folder_id);
// Izpisemo se vse subfolderje
echo '<ul id="folder_list_'.$folder_id.'" class="folder_list">';
echo '<ul id="folder_list_'.$folder_id.'" class="folder_list" '.($folder_open ? '' : 'style="display:none;"').'">';
$sqlChildren = sisplet_query("SELECT id FROM srv_mysurvey_folder WHERE usr_id='".$global_user_id."' AND parent='".$folder_id."' ORDER BY naslov ASC");
while($rowChildren = mysqli_fetch_array($sqlChildren)){
@ -72,10 +102,29 @@ class SurveyListFolders extends SurveyList{
// Izpisemo posamezen folder
private function displayFolder($folder_id){
global $lang;
global $global_user_id;
// Ce gre za root folder dobimo stevilo anket brez folderja
if($folder_id == '0'){
// Prestejemo ankete, ki niso v nobenem notranjem folderju - so v rootu
// Poiscemo vse ankete v custom folderjih
$sql = sisplet_query("SELECT ank_id FROM srv_mysurvey_anketa WHERE usr_id='$global_user_id'");
// Vrnemo razliko v stevilu anket (odstejemo ankete v custom folderjih)
$survey_count = count($this->surveys_ids);
if(mysqli_num_rows($sql) > 0)
$survey_count -= mysqli_num_rows($sql);
$this->current_folder['survey_count'] = $survey_count;
// Preverimo, ce ni noben drug folder aktiviran - potem je aktiviran root
$sql = sisplet_query("SELECT COUNT(id) AS active_count FROM srv_mysurvey_folder WHERE active='1' AND usr_id='".$global_user_id."'");
$row = mysqli_fetch_array($sql);
$folder_active = ($row['active_count'] == 0) ? 'active' : '';
$folder_open = 'open';
}
// Ce ne gre za root folder dobimo podatke o folderju
else{
@ -93,28 +142,101 @@ class SurveyListFolders extends SurveyList{
$row = mysqli_fetch_array($sql);
$survey_count = $row['survey_count'];
// Nastavimo, ce je to trenutno odprt folder
if($row['active'] == '1')
$this->current_folder = $row;
$folder_active = ($row['active'] == '1') ? 'active' : '';
$folder_open = ($row['open'] == '1') ? 'open' : '';
}
// Izrisemo folder box
echo '<div id="folder_item_'.$folder_id.'" class="folder_item" onClick="mysurvey_folder_activate(\''.$folder_id.'\');">';
echo '<span class="faicon arrow"></span>';
echo '<span class="faicon folder"></span>';
// Ce je root
if($folder_id == '0'){
echo $lang['srv_mySurvey_all_surveys'];
echo '<li id="folder_item_'.$folder_id.'" class="folder_item '.$folder_open.' '.$folder_active.' mySurvey_droppable" folder_id="'.$folder_id.'" onClick="mySurvey_folder_activate(\''.$folder_id.'\');">';
echo '<span class="faicon folder"></span>';
echo '<div class="folder_item_title">'.$lang['srv_mySurvey_all_surveys'].'</div>';
echo '<span class="folder_item_child_count">'.$survey_count.'</span>';
// Urejanje folderja
// Tri pikice za prikaz urejanja folderja
echo ' <span class="faicon dots_ver dots_ver_folder" onClick="mySurvey_folder_show_edit(this);"></span>';
// Skrit div za urejanje folderja
echo ' <div class="folder_item_settings displayNone">';
echo ' <ul>';
echo ' <li onClick="mySurvey_folder_add_popup(\''.$folder_id.'\');">'.$lang['srv_mySurvey_create_subfolder'].'</li>';
echo ' </ul>';
echo ' </div>';
}
else{
echo $row['naslov'];
echo '<span class="survey_count">'.$row['survey_count'].'</span>';
echo '<li id="folder_item_'.$folder_id.'" class="folder_item '.$folder_open.' '.$folder_active.' mySurvey_draggable mySurvey_droppable" folder_id="'.$folder_id.'" onClick="mySurvey_folder_activate(\''.$folder_id.'\');">';
echo '<span class="faicon arrow" onClick="mySurvey_folder_toggle(\''.$folder_id.'\');"></span>';
echo '<span class="faicon folder"></span>';
echo '<div class="folder_item_title">'.$row['naslov'].'</div>';
echo '<span class="folder_item_child_count">'.$survey_count.'</span>';
// Urejanje folderja
// Tri pikice za prikaz urejanja folderja
echo ' <span class="faicon dots_ver dots_ver_folder" onClick="mySurvey_folder_show_edit(this);"></span>';
// Skrit div za urejanje folderja
echo ' <div class="folder_item_settings displayNone">';
echo ' <ul>';
echo ' <li onClick="mySurvey_folder_add_popup(\''.$folder_id.'\');">'.$lang['srv_mySurvey_create_subfolder'].'</li>';
echo ' <li onClick="mySurvey_folder_rename_popup(\''.$folder_id.'\', \''.$row['naslov'].'\');">'.$lang['srv_mySurvey_rename_folder'].'</li>';
echo ' <li onClick="mySurvey_folder_delete(\''.$folder_id.'\');">'.$lang['srv_mySurvey_delete_folder'].'</li>';
echo ' </ul>';
echo ' </div>';
}
echo '</li>';
// Vrnemo, ce je folder odprt ali ne
if($folder_open == 'open')
return true;
else
return false;
}
// Dodaten popup za ime direktorija pri dodajanju
private function displayAddFolderPopup($folder_id){
global $lang;
echo '<h2>'.$lang['srv_library_folder_name'].'</h2>';
echo '<div>';
echo ' <input type="text" id="mySurvey_folder_name" class="large">';
echo '</div>';
echo '<div class="button_holder">';
echo ' <button class="medium white-blue" onClick="mySurvey_folder_close_popup();">'.$lang['edit1338'].'</button>';
echo ' <button class="medium blue" onClick="mySurvey_folder_add(\''.$folder_id.'\');">'.$lang['srv_mySurvey_create_subfolder'].'</button>';
echo '</div>';
}
// Dodaten popup za ime direktorija pri preimenovanju
private function displayRenameFolderPopup($folder_id, $folder_name){
global $lang;
echo '<h2>'.$lang['srv_library_folder_name'].'</h2>';
echo '<div>';
echo ' <input type="text" id="mySurvey_folder_name" class="large" value="'.$folder_name.'">';
echo '</div>';
echo '<div class="button_holder">';
echo ' <button class="medium white-blue" onClick="mySurvey_folder_close_popup();">'.$lang['edit1338'].'</button>';
echo ' <button class="medium blue" onClick="mySurvey_folder_rename(\''.$folder_id.'\');">'.$lang['srv_mySurvey_rename_folder'].'</button>';
echo '</div>';
}
@ -145,6 +267,16 @@ class SurveyListFolders extends SurveyList{
echo '</div>';
# koliko imamo strani
$this->max_pages = (int)$this->rec_per_page > 0 ? ceil($this->current_folder['survey_count'] / $this->rec_per_page) : 1;
# katera je trenutna stran
if (isset($_GET['pageno']) && (int)$_GET['pageno'] > 0) {
# izbrana stran ne more biti večja, kot pa imamo vseh strani
$this->pageno = min((int)$_GET['pageno'], $this->max_pages);
}
// Izris seznama anket
echo '<div class="div_sl_new folders">';
$this->displayNewSurveyList();
@ -190,12 +322,6 @@ class SurveyListFolders extends SurveyList{
$this->displayFolderSwitch();
//echo '</div>';
// Okno za search po mojeih anketah
echo ' <div id="searchMySurveys">';
$this->displaySearch();
echo ' </div>';
/*
// Gumb za filtriranje
//echo '<div id="filterButton">';
$this->displayFilterButton();
@ -205,11 +331,102 @@ class SurveyListFolders extends SurveyList{
echo ' <div id="sortButton">';
$this->displaySortButton();
echo ' </div>';
*/
// Okno za search po mojeih anketah
echo ' <div id="searchMySurveys">';
$this->displaySearch();
echo ' </div>';
echo '</div>';
}
// Prikazemo gumb za sortiranje seznama anket
protected function displaySortButton(){
global $lang, $site_url;
echo '<span class="faicon sort"></span>';
echo '<div id="sortSettings">';
echo '<ul>';
if($this->sorttype == 2){
$sort = 1;
$img_src = 'sort_ascending';
}
else{
$sort = 2;
$img_src = 'sort_descending';
}
echo '<li '.($this->sortby == 1 ? ' class="active"' : '').'><a href="#" onClick="surveyList_goTo(\'1\',\''.($this->sortby != 1 ? '1' : $sort).'\')">'.$lang['sort_by_title'].' <span class="faicon '.($this->sortby != 1 ? 'sort_unsorted' : $img_src).'"></span></a></li>';
echo '<li '.($this->sortby == 6 ? ' class="active"' : '').'><a href="#" onClick="surveyList_goTo(\'6\',\''.($this->sortby != 6 ? '1' : $sort).'\')">'.$lang['sort_by_qcount'].' <span class="faicon '.($this->sortby != 6 ? 'sort_unsorted' : $img_src).'"></span></a></li>';
echo '<li '.($this->sortby == 5 ? ' class="active"' : '').'><a href="#" onClick="surveyList_goTo(\'5\',\''.($this->sortby != 5 ? '1' : $sort).'\')">'.$lang['sort_by_answercount'].' <span class="faicon '.($this->sortby != 5 ? 'sort_unsorted' : $img_src).'"></span></a></li>';
echo '<li '.($this->sortby == 16 ? ' class="active"' : '').'><a href="#" onClick="surveyList_goTo(\'16\',\''.($this->sortby != 16 ? '1' : $sort).'\')">'.$lang['sort_by_insert'].' <span class="faicon '.($this->sortby != 16 ? 'sort_unsorted' : $img_src).'"></span></a></li>';
echo '<li '.($this->sortby == 14 ? ' class="active"' : '').'><a href="#" onClick="surveyList_goTo(\'14\',\''.($this->sortby != 14 ? '1' : $sort).'\')">'.$lang['sort_by_edit'].' <span class="faicon '.($this->sortby != 14 ? 'sort_unsorted' : $img_src).'"></span></a></li>';
echo '<li '.($this->sortby == 18 ? ' class="active"' : '').'><a href="#" onClick="surveyList_goTo(\'18\',\''.($this->sortby != 18 ? '1' : $sort).'\')">Status <span class="faicon '.($this->sortby != 18 ? 'sort_unsorted' : $img_src).'"></span></a></li>';
echo '<li '.($this->sortby == 7 ? ' class="active"' : '').'><a href="#" onClick="surveyList_goTo(\'7\',\''.($this->sortby != 7 ? '1' : $sort).'\')"><li '.($this->sortby == 7 ? ' class="active"' : '').'>'.$lang['sort_by_author'].' <span class="faicon '.($this->sortby != 7 ? 'sort_unsorted' : $img_src).'"></span></a></li>';
echo '<li '.($this->sortby == 11 ? ' class="active"' : '').' style="border:0;"><a href="#" onClick="surveyList_goTo(\'11\',\''.($this->sortby != 11 ? '1' : $sort).'\')">'.$lang['sort_by_editor'].' <span class="faicon '.($this->sortby != 11 ? 'sort_unsorted' : $img_src).'"></span></a></li>';
echo '</ul>';
echo '</div>';
}
// Prikazemo gumb za filtriranje seznama anket
protected function displayFilterButton(){
global $lang, $site_url, $admin_languages;
echo '<div id="filterButton" '.(($this->user_id || $this->lang_id != 0 || $this->gdpr != 0) ? 'class="active"' : '').'>';
echo '<span class="faicon filter"></span>';
echo '<div id="filterSettings">';
echo '<ul>';
# filter po uporabniku
echo '<li>';
echo '<span class="filter_title">'.$lang['srv_list_author'].'</span>';
// Ce preklapljamo v searchu moramo refreshati celo stran (druga js funkcija)
$reload = ($this->isSearch == 1) ? '_reload' : '';
echo '<span class="filter_line"><input type="radio" name="filter_mySurveys" id="filter_mySurveys_0" value="0" '.(!$this->user_id ? 'checked="checked"' : '').' onclick="surveyList_user'.$reload.'(\'clr\',\'0\');"> <label for="filter_mySurveys_0">'.$lang['srv_list_all_surveys'].'</label></span>';
echo '<span class="filter_line"><input type="radio" name="filter_mySurveys" id="filter_mySurveys_1" value="1" '.($this->user_id ? 'checked="checked"' : '').' onclick="surveyList_user'.$reload.'(\'uid\',\''.$this->g_uid.'\');"> <label for="filter_mySurveys_1">'.$lang['srv_list_my_surveys'].'</label></span>';
echo '</li>';
# filter po jeziku
echo '<li>';
echo '<span class="filter_title">'.$lang['srv_sl_set_language'].'</span>';
echo '<span class="filter_line"><input type="radio" name="filter_language" id="filter_language_0" value="0" '.((int)$this->lang_id == 0 ? 'checked="checked"' : '').' onclick="surveyList_language'.$reload.'(\'0\');"> <label for="filter_language_0">'.$lang['srv_sl_set_language_all'].'</label></span>';
echo '<span class="filter_line"><input type="radio" name="filter_language" id="filter_language_1" value="1" '.((int)$this->lang_id == 1 ? 'checked="checked"' : '').' onclick="surveyList_language'.$reload.'(\'1\');"> <label for="filter_language_1">'.$admin_languages['1'].'</label></span>';
echo '<span class="filter_line"><input type="radio" name="filter_language" id="filter_language_2" value="2" '.((int)$this->lang_id == 2 ? 'checked="checked"' : '').' onclick="surveyList_language'.$reload.'(\'2\');"> <label for="filter_language_2">'.$admin_languages['2'].'</label></span>';
echo '</li>';
# filter po GDPR anketah
echo '<li>';
echo '<span class="filter_title">'.$lang['srv_gdpr'].'</span>';
echo '<span class="filter_line"><input type="radio" name="filter_gdpr" id="filter_gdpr_0" value="0" '.((int)$this->gdpr == 0 ? 'checked="checked"' : '').' onclick="surveyList_gdpr'.$reload.'(\'0\');"> <label for="filter_gdpr_0">'.$lang['srv_list_all_surveys'].'</label></span>';
echo '<span class="filter_line"><input type="radio" name="filter_gdpr" id="filter_gdpr_1" value="1" '.((int)$this->gdpr == 1 ? 'checked="checked"' : '').' onclick="surveyList_gdpr'.$reload.'(\'1\');"> <label for="filter_gdpr_1">'.$lang['srv_list_gdpr_gdpr'].'</label></span>';
echo '</li>';
echo '</ul>';
echo '</div>';
echo '</div>';
}
// Izpisemo footer
private function displayFooter(){
global $lang;
@ -752,10 +969,23 @@ class SurveyListFolders extends SurveyList{
// Nastavimo current folder
if($folder_id == '0'){
// Prestejemo ankete, ki niso v nobenem notranjem folderju - so v rootu
// Poiscemo vse ankete v custom folderjih
$sql = sisplet_query("SELECT ank_id FROM srv_mysurvey_anketa WHERE usr_id='$global_user_id'");
// Vrnemo razliko v stevilu anket (odstejemo ankete v custom folderjih)
$survey_count = count($this->surveys_ids);
if(mysqli_num_rows($sql) > 0)
$survey_count -= mysqli_num_rows($sql);
$this->current_folder = array(
'id' => 0,
'naslov' => $lang['srv_mySurvey_all_surveys']
);
$this->current_folder['survey_count'] = $survey_count;
}
else{
// Dobimo podatke folderja
@ -777,160 +1007,177 @@ class SurveyListFolders extends SurveyList{
// Na novo prikazemo desno stran
$this->displayRightContent();
// JS za drag/drop
echo '<script type="text/javascript">mySurvey_folder_init();</script>';
}
// Razsirimo/skrcimo folder
if($_GET['a'] == 'mysurvey_folder_toggle'){
/*switch ($_GET['a']) {
case 'survey_dropped':
case 'folder_dropped':
case 'folder_create':
case 'folder_delete':
case 'folder_toggle':
case 'folder_rename':
case 'folder_copy':
$this->updateMySurveyFolders();
break;
default:
print_r($_POST);
print_r($_GET);
break;
}*/
}
// ajax, ki poskrbi za vse update glelde razvrscanja mojih anket v folderje
/*private function updateMySurveyFolders(){
global $global_user_id, $site_url, $lang;
// Prenesli smo anketo v drug folder
if($_GET['a'] == 'survey_dropped'){
$parent = isset($_POST['parent']) ? $_POST['parent'] : '0';
$drag_survey = isset($_POST['drag_survey']) ? $_POST['drag_survey'] : '0';
// Ce smo spustili v root folder samo pobrisemo anketo
if($parent == '0'){
$sql = sisplet_query("DELETE FROM srv_mysurvey_anketa WHERE ank_id='".$drag_survey."' AND usr_id='$global_user_id'");
}
else{
// Razpremo parent folder
$sql = sisplet_query("UPDATE srv_mysurvey_folder SET open='1' WHERE id='".$parent."' AND usr_id='$global_user_id'");
$sql = sisplet_query("INSERT INTO srv_mysurvey_anketa (ank_id, usr_id, folder) VALUES ('".$drag_survey."', '".$global_user_id."', '".$parent."') ON DUPLICATE KEY UPDATE folder='".$parent."'");
}
}
// Prenesli smo celoten folder v drug folder
elseif($_GET['a'] == 'folder_dropped'){
$parent = isset($_POST['parent']) ? $_POST['parent'] : '0';
$drag_folder = isset($_POST['drag_folder']) ? $_POST['drag_folder'] : '0';
// Preverimo da nismo slucajno prenesli v child folder - ne pustimo, ker drugace se zadeva porusi
$sql = sisplet_query("SELECT * FROM srv_mysurvey_folder WHERE id='".$parent."' AND parent='".$drag_folder."' AND usr_id='$global_user_id'");
if(mysqli_num_rows($sql) == 0){
// Razpremo parent folder
$sql = sisplet_query("UPDATE srv_mysurvey_folder SET open='1' WHERE id='".$parent."' AND usr_id='$global_user_id'");
$sql = sisplet_query("UPDATE srv_mysurvey_folder SET parent='".$parent."' WHERE id='".$drag_folder."' AND usr_id='$global_user_id'");
}
}
// prikazemo/skrijemo ankete znotraj folderja
elseif($_GET['a'] == 'folder_toggle'){
$folder = isset($_POST['folder']) ? $_POST['folder'] : '0';
$folder_id = isset($_POST['folder_id']) ? $_POST['folder_id'] : '0';
$open = isset($_POST['open']) ? $_POST['open'] : '0';
$sql = sisplet_query("UPDATE srv_mysurvey_folder SET open='".$open."' WHERE id='".$folder."' AND usr_id='$global_user_id'");
// Nastavimo izbran folder na odprtega
$sql = sisplet_query("UPDATE srv_mysurvey_folder SET open='".$open."' WHERE usr_id='".$global_user_id."' AND id='".$folder_id."'");
}
// Ustvarili smo nov folder
elseif($_GET['a'] == 'folder_create'){
$parent = isset($_POST['parent']) ? $_POST['parent'] : '0';
// Pokazemo popup za poimenovanje novega subfolderja
if($_GET['a'] == 'mysurvey_folder_add_popup'){
$folder_id = $_POST['folder_id'];
$this->displayAddFolderPopup($folder_id);
}
// Ustvarimo nov subfolder
if($_GET['a'] == 'mysurvey_folder_add'){
$folder_id = $_POST['folder_id'];
$folder_name = $_POST['folder_name'];
// Razpremo parent folder
$sql = sisplet_query("UPDATE srv_mysurvey_folder SET open='1' WHERE id='".$parent."' AND usr_id='$global_user_id'");
$sql = sisplet_query("UPDATE srv_mysurvey_folder SET open='1' WHERE id='".$folder_id."' AND usr_id='$global_user_id'");
$sql = sisplet_query("INSERT INTO srv_mysurvey_folder (usr_id, parent, naslov) VALUES ('".$global_user_id."','".$parent."', '".$lang['srv_mySurvey_new_folder']."')");
$sql = sisplet_query("INSERT INTO srv_mysurvey_folder (usr_id, parent, naslov) VALUES ('".$global_user_id."','".$folder_id."', '".$folder_name."')");
$new_folder_id = mysqli_insert_id($GLOBALS['connect_db']);
$SL = new SurveyList();
$SL->getSurveys();
$this->displayLeftContent();
echo '<input type="hidden" id="new_added_folder" value="'.$new_folder_id.'">';
// JS za drag/drop
echo '<script type="text/javascript">mySurvey_folder_init();</script>';
}
// Pokazemo popup za preimenovanje folderja
if($_GET['a'] == 'mysurvey_folder_rename_popup'){
$folder_id = $_POST['folder_id'];
$folder_name = $_POST['folder_name'];
$this->displayRenameFolderPopup($folder_id, $folder_name);
}
// Preimenujemo folder
if($_GET['a'] == 'mysurvey_folder_rename'){
$folder_id = isset($_POST['folder_id']) ? $_POST['folder_id'] : '0';
$folder_name = isset($_POST['folder_name']) ? $_POST['folder_name'] : '';
$folder_name = strip_tags($folder_name);
$sql = sisplet_query("UPDATE srv_mysurvey_folder SET naslov='".$folder_name."' WHERE id='".$folder_id."' AND usr_id='".$global_user_id."'");
$this->displayLeftContent();
// JS za drag/drop
echo '<script type="text/javascript">mySurvey_folder_init();</script>';
}
// Pobrisemo folder
if($_GET['a'] == 'mysurvey_folder_delete'){
$folder_id = isset($_POST['folder_id']) ? $_POST['folder_id'] : 0;
if($folder_id > 0){
// Dobimo parent folderja
$sqlParent = sisplet_query("SELECT parent, active FROM srv_mysurvey_folder WHERE id='".$folder_id."' AND usr_id='".$global_user_id."'");
$rowParent = mysqli_fetch_array($sqlParent);
// Ce je parent root, pobrisemo ankete ki so bile znotraj folderja
if($rowParent['parent'] == '0'){
$sql = sisplet_query("DELETE FROM srv_mysurvey_anketa WHERE folder='".$folder_id."' AND usr_id='".$global_user_id."'");
}
// Drugace jih prestavimo v parenta
else{
$sql = sisplet_query("UPDATE srv_mysurvey_anketa SET folder='".$rowParent['parent']."' WHERE folder='".$folder_id."' AND usr_id='".$global_user_id."'");
// Ce je bil active, nastavimo parenta za active
if($rowParent['active'] == '1'){
$sql2 = sisplet_query("UPDATE srv_mysurvey_folder SET active='1' WHERE id='".$rowParent['parent']."' AND usr_id='".$global_user_id."'");
}
}
// Nastavimo subfolderjem novega parenta
$sql3 = sisplet_query("UPDATE srv_mysurvey_folder SET parent='".$rowParent['parent']."' WHERE parent='".$folder_id."' AND usr_id='".$global_user_id."'");
// Na koncu se pobrisemo prazen folder
$sql4 = sisplet_query("DELETE FROM srv_mysurvey_folder WHERE id='".$folder_id."' AND usr_id='".$global_user_id."'");
}
$this->getSurveys();
}
// Pobrisali smo obstojec folder
elseif($_GET['a'] == 'folder_delete'){
$folder = isset($_POST['folder']) ? $_POST['folder'] : '0';
//Pobrisemo ankete ki so bile znotraj folderja
$sql = sisplet_query("DELETE FROM srv_mysurvey_anketa WHERE folder='".$folder."' AND usr_id='$global_user_id'");
// Drop folderja
if($_GET['a'] == 'mysurvey_folder_drop'){
// Na koncu se pobrisemo prazen folder
$sql = sisplet_query("DELETE FROM srv_mysurvey_folder WHERE id='".$folder."' AND usr_id='$global_user_id'");
$drag_folder_id = isset($_POST['drag_folder_id']) ? $_POST['drag_folder_id'] : 0;
$parent_folder_id = isset($_POST['parent_folder_id']) ? $_POST['parent_folder_id'] : 0;
// Rekurzivno pobrisemo vse poddirektorije z anketami - TODO!!!
if($drag_folder_id > 0){
// Preverimo, ce nismo droppali folder v svojega childa - tega nikoli ne pustimo, ker potem vse izgine
if(!$this->checkFolderIsChild($parent_folder_id, $drag_folder_id)){
// Nastavimo folderju novega parenta
$sql = sisplet_query("UPDATE srv_mysurvey_folder SET parent='".$parent_folder_id."' WHERE id='".$drag_folder_id."' AND usr_id='".$global_user_id."'");
// Parenta razpremo
$sql = sisplet_query("UPDATE srv_mysurvey_folder SET open='1' WHERE id='".$parent_folder_id."' AND usr_id='".$global_user_id."'");
}
}
$this->getSurveys();
}
// Preimenovali smo obstojec folder
elseif($_GET['a'] == 'folder_rename'){
$folder = isset($_POST['folder']) ? $_POST['folder'] : '0';
$text = isset($_POST['text']) ? $_POST['text'] : '';
$text = strip_tags($text);
// Drop ankete
if($_GET['a'] == 'mysurvey_survey_drop'){
$sql = sisplet_query("UPDATE srv_mysurvey_folder SET naslov='".$text."' WHERE id='".$folder."' AND usr_id='$global_user_id'");
$drag_survey_id = isset($_POST['drag_survey_id']) ? $_POST['drag_survey_id'] : 0;
$parent_folder_id = isset($_POST['parent_folder_id']) ? $_POST['parent_folder_id'] : 0;
if($drag_survey_id > 0){
// Ce prestavimo v root, samo pobrisemo anketo iz srv_mysurvey_anketa
if($parent_folder_id == '0'){
$sql = sisplet_query("DELETE FROM srv_mysurvey_anketa WHERE ank_id='".$drag_survey_id."' AND usr_id='".$global_user_id."'");
}
// Prestavimo anketo v subfolder
else{
$sql = sisplet_query("INSERT INTO srv_mysurvey_anketa
(ank_id, usr_id, folder)
VALUES
('".$drag_survey_id."', '".$global_user_id."', '".$parent_folder_id."')
ON DUPLICATE KEY UPDATE
folder='".$parent_folder_id."'");
}
}
$this->getSurveys();
}
}
// Kopiramo obstojec folder z vsemi anketami
elseif($_GET['a'] == 'folder_copy'){
// Rekurzivno preverimo, ce je nek folder child drugega folderja
private function checkFolderIsChild($folder_id, $parent_folder_id){
$folder = isset($_POST['folder']) ? $_POST['folder'] : '0';
if($folder > 0)
$this->copyMySurveyFolder($folder);
}
}
// Ce je parent 0, je root in koncamo - folder ni child
if($folder_id == '0')
return false;
// Kopiramo obstojec folder z vsemi folderji in anketami (rekurzivno)
private function copyMySurveyFolder($folder_id, $parent=0){
global $global_user_id;
$sql = sisplet_query("SELECT parent FROM srv_mysurvey_folder WHERE id='".$folder_id."'");
$row = mysqli_fetch_array($sql);
$sql = sisplet_query("SELECT * FROM srv_mysurvey_folder WHERE id='".$folder_id."' AND usr_id='".$global_user_id."'");
if(mysqli_num_rows($sql) == 0)
return;
if($row['parent'] == $parent_folder_id){
return true;
}
else{
return $this->checkFolderIsChild($row['parent'], $parent_folder_id);
}
}
$row = mysqli_fetch_array($sql);
// Najprej ustvarimo kopijo folderja
if($parent == 0)
$sql2 = sisplet_query("INSERT INTO srv_mysurvey_folder (usr_id, parent, naslov, open) VALUES ('".$global_user_id."', '".$row['parent']."', '".$row['naslov']."_copy', '1')");
else
$sql2 = sisplet_query("INSERT INTO srv_mysurvey_folder (usr_id, parent, naslov, open) VALUES ('".$global_user_id."', '".$parent."', '".$row['naslov']."_copy', '1')");
$new_folder_id = mysqli_insert_id($GLOBALS['connect_db']);
// Loop cez ankete v folderju
$sqlA = sisplet_query("SELECT * FROM srv_mysurvey_anketa WHERE folder='".$folder_id."'");
while($rowA = mysqli_fetch_array($sqlA)){
// Kopiramo anketo
$sas = new SurveyAdminSettings();
$ank_id = $sas->anketa_copy($rowA['ank_id']);
// Kopirano anketo vstavimo v nov folder
$sql2 = sisplet_query("INSERT INTO srv_mysurvey_anketa (ank_id, usr_id, folder) VALUES ('".$ank_id."', '".$global_user_id."', '".$new_folder_id."')");
}
// Na koncu rekurzivno kopiramo se vse notranje folderje
$sqlF = sisplet_query("SELECT id FROM srv_mysurvey_folder WHERE parent='".$folder_id."' AND usr_id='".$global_user_id."'");
while($rowF = mysqli_fetch_array($sqlF)){
$this->copyMySurveyFolder($rowF['id'], $new_folder_id);
}
return;
}*/
}
?>

View File

@ -176,12 +176,23 @@
/**************** BODY ****************/
// za css - barve ozadja
if (isset($_GET['anketa']))
if(isset($_GET['anketa'])){
$cssBodyClass = 'body_anketa';
else if (isset($_GET['a']) && $_GET['a'] == 'knjiznica' )
}
elseif(isset($_GET['a']) && $_GET['a'] == 'knjiznica'){
$cssBodyClass = 'body_library';
else
$cssBodyClass = 'body_folders';
}
elseif(!isset($_GET['a']) || $_GET['a'] == 'pregledovanje'){
// Pogled s folderji
if(SurveyList::hasFolders()){
$cssBodyClass = 'body_mySurveys_folders';
}
// Klasicne moje ankete
else{
$cssBodyClass = 'body_mySurveys';
}
}
// Class za jezik
$langBodyClass = ($lang['id'] != "1") ? 'eng' : 'slo';

View File

@ -74,12 +74,77 @@ function switchFolder(show){
var show_folders = 1;
$('#survey_list').load('ajax.php?a=surveyList_folders', {show_folders:show_folders}, function(){
$('#moje_ankete_edit').toggleClass('moje_ankete_folders');
$('body').toggleClass('body_mySurveys_folders');
$('body').toggleClass('body_mySurveys');
});
}
// inicializiramo drag/drop anket in folderjev
function mySurvey_folder_init() {
$('#survey_list .mySurvey_droppable').droppable({
accept: '#survey_list .mySurvey_draggable',
hoverClass: 'folderhover',
tolerance: 'pointer',
drop: function (e, ui) {
// Drop folderja
if($(ui.draggable).hasClass('folder_item')){
var drag_folder_id = $(ui.draggable).attr('folder_id');
var parent_folder_id = $(this).attr('folder_id');
$('#survey_list').load('ajax.php?t=surveyListFolders&a=mysurvey_folder_drop', {parent_folder_id: parent_folder_id, drag_folder_id: drag_folder_id});
}
// Drop ankete
if($(ui.draggable).hasClass('anketa_list')){
var drag_survey_id = $(ui.draggable).attr('anketa_id');
var parent_folder_id = $(this).attr('folder_id');
$('#survey_list').load('ajax.php?t=surveyListFolders&a=mysurvey_survey_drop', {parent_folder_id: parent_folder_id, drag_survey_id: drag_survey_id});
}
}
});
$('#survey_list .mySurvey_draggable').draggable({
revert: 'invalid',
opacitiy: '0.9',
helper: 'clone',
cursor: 'move',
cursorAt: { left: 20 },
start: function(e, ui){
$(ui.helper).addClass('mySurvey_draggable_helper');
}
});
}
// Razpremo/skrcimo folder
function mySurvey_folder_toggle(folder_id){
if($('#folder_item_'+folder_id).hasClass('open'))
var open = 0;
else
var open = 1;
$.post('ajax.php?t=surveyListFolders&a=mysurvey_folder_toggle', {folder_id: folder_id, open: open}, function(){
if($('#folder_item_'+folder_id).hasClass('open')){
$('#folder_item_'+folder_id).removeClass('open');
$('#folder_list_'+folder_id).slideUp();
}
else{
$('#folder_item_'+folder_id).addClass('open');
$('#folder_list_'+folder_id).slideDown();
}
});
event.stopPropagation();
}
// Aktiviramo folder
function mysurvey_folder_activate(folder_id){
function mySurvey_folder_activate(folder_id){
$('#right_content').load('ajax.php?t=surveyListFolders&a=mysurvey_folder_activate', {folder_id: folder_id}, function(){
@ -91,50 +156,79 @@ function mysurvey_folder_activate(folder_id){
});
}
// Prikazemo opcije za urejanje folderja
function mySurvey_folder_show_edit(element){
// inicializiramo drag/drop anket in folderjev
function surveyList_folder_init() {
if($(element).parent().find('.folder_item_settings').hasClass('displayNone')){
$('.folder_item_settings').addClass('displayNone');
$('.dots_ver_folder').removeClass('active');
$(element).parent().find('.folder_item_settings').removeClass('displayNone');
$(element).addClass('active');
}
else{
$('.folder_item_settings').addClass('displayNone');
$('.dots_ver_folder').removeClass('active');
$(element).parent().find('.folder_item_settings').addClass('displayNone');
$(element).removeClass('active');
}
$('#survey_list div.droppable').droppable({
accept: '.mySurvey_draggable',
hoverClass: 'folderhover',
tolerance: 'pointer',
drop: function (e, ui) {
// Drop folderja
if($(ui.draggable).hasClass('folder_title')){
var drag_folder = $(ui.draggable).attr('folder_id');
var parent = $(this).attr('folder_id');
$.post('ajax.php?t=surveyList&a=folder_dropped', {parent: parent, drag_folder: drag_folder}, function(){
window.location.reload();
});
}
// Drop ankete
if($(ui.draggable).hasClass('anketa_list')){
var drag_survey = $(ui.draggable).attr('anketa_id');
var parent = $(this).attr('folder_id');
$.post('ajax.php?t=surveyList&a=survey_dropped', {parent: parent, drag_survey: drag_survey}, function(){
window.location.reload();
});
}
}
});
$('.mySurvey_draggable').draggable({
revert: 'invalid',
opacitiy: '0.7',
helper: 'clone',
cursor: 'move',
cursorAt: { left: 20 },
start: function(e, ui){
$(ui.helper).addClass('mySurvey_draggable_helper');
}
});
event.stopPropagation();
}
// Zaprtje dodatnega popupa
function mySurvey_folder_close_popup(){
$('#fade').fadeOut('slow');
$("#mySurvey_additional_popup").fadeOut().html();
}
// Ime novega folderja
function mySurvey_folder_add_popup(parent_folder_id){
$('#fade').fadeTo('slow', 1);
$("#mySurvey_additional_popup").fadeIn();
$("#mySurvey_additional_popup").load('ajax.php?t=surveyListFolders&a=mysurvey_folder_add_popup', {folder_id: parent_folder_id});
}
// Dodamo nov folder
function mySurvey_folder_add(parent_folder_id){
var folder_name = $("#mySurvey_folder_name").val();
$("#left_content").load('ajax.php?t=surveyListFolders&a=mysurvey_folder_add', {folder_id: parent_folder_id, folder_name: folder_name}, function(){
mySurvey_folder_close_popup();
});
}
// Ime obstojecega folderja
function mySurvey_folder_rename_popup(folder_id, folder_name){
$('#fade').fadeTo('slow', 1);
$("#mySurvey_additional_popup").fadeIn();
$("#mySurvey_additional_popup").load('ajax.php?t=surveyListFolders&a=mysurvey_folder_rename_popup', {folder_id: folder_id, folder_name: folder_name});
}
// Preimenujemo obstojeci folder
function mySurvey_folder_rename(folder_id){
var folder_name = $("#mySurvey_folder_name").val();
$("#left_content").load('ajax.php?t=surveyListFolders&a=mysurvey_folder_rename', {folder_id: folder_id, folder_name: folder_name}, function(){
mySurvey_folder_close_popup();
});
}
// Pobrisemo obstojeci folder
function mySurvey_folder_delete(folder_id){
$("#survey_list").load('ajax.php?t=surveyListFolders&a=mysurvey_folder_delete', {folder_id: folder_id});
}
/*
// prikazemo/skrijemo ankete v folderju
function toggle_folder (folder) {
@ -159,41 +253,7 @@ function toggle_folder (folder) {
});
}
// Pobrisemo folder
function delete_folder (folder) {
$.post('ajax.php?t=surveyList&a=folder_delete', {folder: folder}, function(){
window.location.reload();
});
}
// Ustvarimo folder
function create_folder (parent) {
$('#survey_list').load('ajax.php?t=surveyList&a=folder_create', {parent: parent}, function(){
var added_folder_id = $('#new_added_folder').val();
edit_title_folder(added_folder_id);
});
}
// Urejamo ime folderja
function edit_title_folder (folder) {
var text = $('#folder_title_text_'+folder).text();
$('#folder_title_text_'+folder).html('<input type="text" name="folder_title_edit" folder="'+folder+'" id="folder_title_edit_'+folder+'" class="folder_title_edit" value="'+text+'" onBlur="rename_folder(\''+folder+'\'); return false;" />');
$('#folder_title_edit_'+folder).select();
}
// Preimenujemo folder
function rename_folder(folder){
var text = $('#folder_title_edit_'+folder).val();
$.post('ajax.php?t=surveyList&a=folder_rename', {folder: folder, text: text}, function(){
$('#folder_title_text_'+folder).html('<a href="#" onClick="edit_title_folder(\''+folder+'\'); return false;">'+text+'</a>');
});
}
// Kopiramo folder
function copy_folder(folder){
@ -202,7 +262,7 @@ function copy_folder(folder){
});
}
*/

File diff suppressed because it is too large Load Diff

View File

@ -57,12 +57,13 @@ return array(
'Drupal\\Component\\' => array($baseDir . '/web/core/lib/Drupal/Component'),
'Doctrine\\Persistence\\' => array($vendorDir . '/doctrine/persistence/lib/Doctrine/Persistence'),
'Doctrine\\Inflector\\' => array($vendorDir . '/doctrine/inflector/lib/Doctrine/Inflector'),
'Doctrine\\Deprecations\\' => array($vendorDir . '/doctrine/deprecations/lib/Doctrine/Deprecations'),
'Doctrine\\Common\\Lexer\\' => array($vendorDir . '/doctrine/lexer/lib/Doctrine/Common/Lexer'),
'Doctrine\\Common\\Inflector\\' => array($vendorDir . '/doctrine/inflector/lib/Doctrine/Common/Inflector'),
'Doctrine\\Common\\Collections\\' => array($vendorDir . '/doctrine/collections/lib/Doctrine/Common/Collections'),
'Doctrine\\Common\\Cache\\' => array($vendorDir . '/doctrine/cache/lib/Doctrine/Common/Cache'),
'Doctrine\\Common\\Annotations\\' => array($vendorDir . '/doctrine/annotations/lib/Doctrine/Common/Annotations'),
'Doctrine\\Common\\' => array($vendorDir . '/doctrine/common/lib/Doctrine/Common', $vendorDir . '/doctrine/event-manager/lib/Doctrine/Common', $vendorDir . '/doctrine/persistence/lib/Doctrine/Common', $vendorDir . '/doctrine/reflection/lib/Doctrine/Common'),
'Doctrine\\Common\\' => array($vendorDir . '/doctrine/common/lib/Doctrine/Common', $vendorDir . '/doctrine/persistence/lib/Doctrine/Common', $vendorDir . '/doctrine/reflection/lib/Doctrine/Common', $vendorDir . '/doctrine/event-manager/lib/Doctrine/Common'),
'Composer\\Semver\\' => array($vendorDir . '/composer/semver/src'),
'Composer\\Installers\\' => array($vendorDir . '/composer/installers/src/Composer/Installers'),
'Asm89\\Stack\\' => array($vendorDir . '/asm89/stack-cors/src/Asm89/Stack'),

View File

@ -116,6 +116,7 @@ class ComposerStaticInitd428c8960f3d72900807e718545d9f8d
'Drupal\\Component\\' => 17,
'Doctrine\\Persistence\\' => 21,
'Doctrine\\Inflector\\' => 19,
'Doctrine\\Deprecations\\' => 22,
'Doctrine\\Common\\Lexer\\' => 22,
'Doctrine\\Common\\Inflector\\' => 26,
'Doctrine\\Common\\Collections\\' => 28,
@ -340,6 +341,10 @@ class ComposerStaticInitd428c8960f3d72900807e718545d9f8d
array (
0 => __DIR__ . '/..' . '/doctrine/inflector/lib/Doctrine/Inflector',
),
'Doctrine\\Deprecations\\' =>
array (
0 => __DIR__ . '/..' . '/doctrine/deprecations/lib/Doctrine/Deprecations',
),
'Doctrine\\Common\\Lexer\\' =>
array (
0 => __DIR__ . '/..' . '/doctrine/lexer/lib/Doctrine/Common/Lexer',
@ -363,9 +368,9 @@ class ComposerStaticInitd428c8960f3d72900807e718545d9f8d
'Doctrine\\Common\\' =>
array (
0 => __DIR__ . '/..' . '/doctrine/common/lib/Doctrine/Common',
1 => __DIR__ . '/..' . '/doctrine/event-manager/lib/Doctrine/Common',
2 => __DIR__ . '/..' . '/doctrine/persistence/lib/Doctrine/Common',
3 => __DIR__ . '/..' . '/doctrine/reflection/lib/Doctrine/Common',
1 => __DIR__ . '/..' . '/doctrine/persistence/lib/Doctrine/Common',
2 => __DIR__ . '/..' . '/doctrine/reflection/lib/Doctrine/Common',
3 => __DIR__ . '/..' . '/doctrine/event-manager/lib/Doctrine/Common',
),
'Composer\\Semver\\' =>
array (

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -10,17 +10,23 @@
"slug": "latest",
"upcoming": true
},
{
"name": "1.8",
"branchName": "1.8.x",
"slug": "1.8",
"upcoming": true
},
{
"name": "1.7",
"branchName": "1.7.x",
"slug": "1.7",
"upcoming": true
"current": true
},
{
"name": "1.6",
"branchName": "1.6.x",
"slug": "1.6",
"current": true
"maintained": false
}
]
}

View File

@ -6,16 +6,6 @@ Before we can merge your Pull-Request here are some guidelines that you need to
These guidelines exist not to annoy you, but to keep the code base clean,
unified and future proof.
## We only accept PRs to "master"
Our branching strategy is "everything to master first", even
bugfixes and we then merge them into the stable branches. You should only
open pull requests against the master branch. Otherwise we cannot accept the PR.
There is one exception to the rule, when we merged a bug into some stable branches
we do occasionally accept pull requests that merge the same bug fix into earlier
branches.
## Coding Standard
We use the [Doctrine Coding Standard](https://github.com/doctrine/coding-standard).

View File

@ -1,92 +1,6 @@
# Doctrine Collections
[![Build Status](https://github.com/doctrine/collections/workflows/Continuous%20Integration/badge.svg)](https://github.com/doctrine/collections/actions)
[![Code Coverage](https://codecov.io/gh/doctrine/collections/branch/master/graph/badge.svg)](https://codecov.io/gh/doctrine/collections/branch/master)
[![Code Coverage](https://codecov.io/gh/doctrine/collections/branch/2.0.x/graph/badge.svg)](https://codecov.io/gh/doctrine/collections/branch/2.0.x)
Collections Abstraction library
## Changelog
### v1.6.1
This release, combined with the release of [`doctrine/collections` `v1.6.1`](https://github.com/doctrine/collections/releases/tag/v1.6.1),
fixes an issue where parsing annotations was not possible
for classes within `doctrine/collections`.
Specifically, `v1.6.0` introduced Psalm-specific annotations
such as (for example) `@template` and `@template-implements`,
which were both incorrectly recognized as `@template`.
`@template` has therefore been removed, and instead we use
the prefixed `@psalm-template`, which is no longer parsed
by `doctrine/collections` `v1.6.1`
Total issues resolved: **1**
- [186: Use `@psalm-template` annotation to avoid clashes](https://github.com/doctrine/collections/pull/186) thanks to @muglug
### v1.6.0
This release bumps the minimum required PHP version to 7.1.3.
Following improvements were introduced:
* `ArrayCollection#filter()` now allows filtering by key, value or both.
* When using the `ClosureExpressionVisitor` over objects with a defined
accessor and property, the accessor is prioritised.
* Updated testing tools and coding standards, autoloading, which also
led to marginal performance improvements
* Introduced generic type docblock declarations from [psalm](https://github.com/vimeo/psalm),
which should allow users to declare `/** @var Collection<KeyType, ValueType> */`
in their code, and leverage the type propagation deriving from that.
Total issues resolved: **16**
- [127: Use PSR-4](https://github.com/doctrine/collections/pull/127) thanks to @Nyholm
- [129: Remove space in method declaration](https://github.com/doctrine/collections/pull/129) thanks to @bounoable
- [130: Update build to add PHPCS and PHPStan](https://github.com/doctrine/collections/pull/130) thanks to @lcobucci
- [131: ClosureExpressionVisitor &gt; Don't duplicate the accessor when the field already starts with it](https://github.com/doctrine/collections/pull/131) thanks to @ruudk
- [139: Apply Doctrine CS 2.1](https://github.com/doctrine/collections/pull/139) thanks to @Majkl578
- [142: CS 4.0, version composer.lock, merge stages](https://github.com/doctrine/collections/pull/142) thanks to @Majkl578
- [144: Update to PHPUnit 7](https://github.com/doctrine/collections/pull/144) thanks to @carusogabriel
- [146: Update changelog for v1.4.0 and v1.5.0](https://github.com/doctrine/collections/pull/146) thanks to @GromNaN
- [154: Update index.rst](https://github.com/doctrine/collections/pull/154) thanks to @chraiet
- [158: Extract Selectable method into own documentation section](https://github.com/doctrine/collections/pull/158) thanks to @SenseException
- [160: Update homepage](https://github.com/doctrine/collections/pull/160) thanks to @Majkl578
- [165: Allow `ArrayCollection#filter()` to filter by key, value or both](https://github.com/doctrine/collections/issues/165) thanks to @0x13a
- [167: Allow `ArrayCollection#filter()` to filter by key and also value](https://github.com/doctrine/collections/pull/167) thanks to @0x13a
- [175: CI: Test against PHP 7.4snapshot instead of nightly (8.0)](https://github.com/doctrine/collections/pull/175) thanks to @Majkl578
- [177: Generify collections using Psalm](https://github.com/doctrine/collections/pull/177) thanks to @nschoellhorn
- [178: Updated doctrine/coding-standard to 6.0](https://github.com/doctrine/collections/pull/178) thanks to @patrickjahns
### v1.5.0
* [Require PHP 7.1+](https://github.com/doctrine/collections/pull/105)
* [Drop HHVM support](https://github.com/doctrine/collections/pull/118)
### v1.4.0
* [Require PHP 5.6+](https://github.com/doctrine/collections/pull/105)
* [Add `ArrayCollection::createFrom()`](https://github.com/doctrine/collections/pull/91)
* [Support non-camel-case naming](https://github.com/doctrine/collections/pull/57)
* [Comparison `START_WITH`, `END_WITH`](https://github.com/doctrine/collections/pull/78)
* [Comparison `MEMBER_OF`](https://github.com/doctrine/collections/pull/66)
* [Add Contributing guide](https://github.com/doctrine/collections/pull/103)
### v1.3.0
* [Explicit casting of first and max results in criteria API](https://github.com/doctrine/collections/pull/26)
* [Keep keys when using `ArrayCollection#matching()` with sorting](https://github.com/doctrine/collections/pull/49)
* [Made `AbstractLazyCollection#$initialized` protected for extensibility](https://github.com/doctrine/collections/pull/52)
### v1.2.0
* Add a new ``AbstractLazyCollection``
### v1.1.0
* Deprecated ``Comparison::IS``, because it's only there for SQL semantics.
These are fixed in the ORM instead.
* Add ``Comparison::CONTAINS`` to perform partial string matches:
$criteria->andWhere($criteria->expr()->contains('property', 'Foo'));

View File

@ -1,37 +1,61 @@
{
"name": "doctrine/collections",
"type": "library",
"description": "PHP Doctrine Collections library that adds additional functionality on top of PHP arrays.",
"license": "MIT",
"type": "library",
"keywords": [
"php",
"collections",
"array",
"iterators"
],
"homepage": "https://www.doctrine-project.org/projects/collections.html",
"license": "MIT",
"authors": [
{"name": "Guilherme Blanco", "email": "guilhermeblanco@gmail.com"},
{"name": "Roman Borschel", "email": "roman@code-factory.org"},
{"name": "Benjamin Eberlei", "email": "kontakt@beberlei.de"},
{"name": "Jonathan Wage", "email": "jonwage@gmail.com"},
{"name": "Johannes Schmitt", "email": "schmittjoh@gmail.com"}
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com"
}
],
"homepage": "https://www.doctrine-project.org/projects/collections.html",
"require": {
"php": "^7.1.3 || ^8.0"
"php": "^7.1.3 || ^8.0",
"doctrine/deprecations": "^0.5.3 || ^1"
},
"require-dev": {
"doctrine/coding-standard": "^9.0 || ^10.0",
"phpstan/phpstan": "^1.4.8",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.1.5",
"doctrine/coding-standard": "^9.0",
"phpstan/phpstan": "^0.12",
"vimeo/psalm": "^4.2.1"
"vimeo/psalm": "^4.22"
},
"autoload": {
"psr-4": { "Doctrine\\Common\\Collections\\": "lib/Doctrine/Common/Collections" }
"psr-4": {
"Doctrine\\Common\\Collections\\": "lib/Doctrine/Common/Collections"
}
},
"autoload-dev": {
"psr-4": {
"Doctrine\\Tests\\": "tests/Doctrine/Tests"
}
},
"config": {
"allow-plugins": {
"composer/package-versions-deprecated": true,
"dealerdirect/phpcodesniffer-composer-installer": true
}
}
}

View File

@ -32,6 +32,11 @@ explicitly retrieve an iterator though ``getIterator()`` which can then be
used to iterate over the collection. You can not rely on the internal iterator
of the collection being at a certain position unless you explicitly positioned it before.
Methods that do not alter the collection or have template types
appearing in invariant or contravariant positions are not directly
defined in ``Doctrine\Common\Collections\Collection``, but are inherited
from the ``Doctrine\Common\Collections\ReadableCollection`` interface.
The methods available on the interface are:
add

View File

@ -3,6 +3,7 @@
namespace Doctrine\Common\Collections;
use Closure;
use LogicException;
use ReturnTypeWillChange;
use Traversable;
@ -18,8 +19,8 @@ abstract class AbstractLazyCollection implements Collection
/**
* The backed collection to use
*
* @psalm-var Collection<TKey,T>
* @var Collection<mixed>
* @psalm-var Collection<TKey,T>|null
* @var Collection<mixed>|null
*/
protected $collection;
@ -60,6 +61,8 @@ abstract class AbstractLazyCollection implements Collection
/**
* {@inheritDoc}
*
* @template TMaybeContained
*/
public function contains($element)
{
@ -259,6 +262,8 @@ abstract class AbstractLazyCollection implements Collection
/**
* {@inheritDoc}
*
* @template TMaybeContained
*/
public function indexOf($element)
{
@ -292,9 +297,7 @@ abstract class AbstractLazyCollection implements Collection
}
/**
* {@inheritDoc}
*
* @psalm-param TKey $offset
* @param TKey $offset
*
* @return bool
*/
@ -307,10 +310,7 @@ abstract class AbstractLazyCollection implements Collection
}
/**
* {@inheritDoc}
*
* @param int|string $offset
* @psalm-param TKey $offset
* @param TKey $offset
*
* @return mixed
*/
@ -323,10 +323,8 @@ abstract class AbstractLazyCollection implements Collection
}
/**
* {@inheritDoc}
*
* @param mixed $value
* @psalm-param TKey $offset
* @param TKey|null $offset
* @param T $value
*
* @return void
*/
@ -338,9 +336,7 @@ abstract class AbstractLazyCollection implements Collection
}
/**
* {@inheritDoc}
*
* @psalm-param TKey $offset
* @param TKey $offset
*
* @return void
*/
@ -355,6 +351,8 @@ abstract class AbstractLazyCollection implements Collection
* Is the lazy collection already initialized?
*
* @return bool
*
* @psalm-assert-if-true Collection<TKey,T> $this->collection
*/
public function isInitialized()
{
@ -365,6 +363,8 @@ abstract class AbstractLazyCollection implements Collection
* Initialize the collection
*
* @return void
*
* @psalm-assert Collection<TKey,T> $this->collection
*/
protected function initialize()
{
@ -374,6 +374,10 @@ abstract class AbstractLazyCollection implements Collection
$this->doInitialize();
$this->initialized = true;
if ($this->collection === null) {
throw new LogicException('You must initialize the collection property in the doInitialize() method.');
}
}
/**

View File

@ -165,9 +165,7 @@ class ArrayCollection implements Collection, Selectable
/**
* Required by interface ArrayAccess.
*
* {@inheritDoc}
*
* @psalm-param TKey $offset
* @param TKey $offset
*
* @return bool
*/
@ -180,9 +178,7 @@ class ArrayCollection implements Collection, Selectable
/**
* Required by interface ArrayAccess.
*
* {@inheritDoc}
*
* @psalm-param TKey $offset
* @param TKey $offset
*
* @return mixed
*/
@ -195,7 +191,8 @@ class ArrayCollection implements Collection, Selectable
/**
* Required by interface ArrayAccess.
*
* {@inheritDoc}
* @param TKey|null $offset
* @param T $value
*
* @return void
*/
@ -214,9 +211,7 @@ class ArrayCollection implements Collection, Selectable
/**
* Required by interface ArrayAccess.
*
* {@inheritDoc}
*
* @psalm-param TKey $offset
* @param TKey $offset
*
* @return void
*/
@ -236,6 +231,8 @@ class ArrayCollection implements Collection, Selectable
/**
* {@inheritDoc}
*
* @template TMaybeContained
*/
public function contains($element)
{
@ -258,6 +255,12 @@ class ArrayCollection implements Collection, Selectable
/**
* {@inheritDoc}
*
* @psalm-param TMaybeContained $element
*
* @psalm-return (TMaybeContained is T ? TKey|false : false)
*
* @template TMaybeContained
*/
public function indexOf($element)
{
@ -345,7 +348,7 @@ class ArrayCollection implements Collection, Selectable
/**
* {@inheritDoc}
*
* @psalm-param Closure(T=):U $func
* @psalm-param Closure(T):U $func
*
* @return static
* @psalm-return static<TKey, U>

View File

@ -4,8 +4,6 @@ namespace Doctrine\Common\Collections;
use ArrayAccess;
use Closure;
use Countable;
use IteratorAggregate;
/**
* The missing (SPL) Collection/Array/OrderedMap interface.
@ -26,10 +24,10 @@ use IteratorAggregate;
*
* @psalm-template TKey of array-key
* @psalm-template T
* @template-extends IteratorAggregate<TKey, T>
* @template-extends ArrayAccess<TKey|null, T>
* @template-extends ReadableCollection<TKey, T>
* @template-extends ArrayAccess<TKey, T>
*/
interface Collection extends Countable, IteratorAggregate, ArrayAccess
interface Collection extends ReadableCollection, ArrayAccess
{
/**
* Adds an element at the end of the collection.
@ -48,24 +46,6 @@ interface Collection extends Countable, IteratorAggregate, ArrayAccess
*/
public function clear();
/**
* Checks whether an element is contained in the collection.
* This is an O(n) operation, where n is the size of the collection.
*
* @param mixed $element The element to search for.
* @psalm-param T $element
*
* @return bool TRUE if the collection contains the element, FALSE otherwise.
*/
public function contains($element);
/**
* Checks whether the collection is empty (contains no elements).
*
* @return bool TRUE if the collection is empty, FALSE otherwise.
*/
public function isEmpty();
/**
* Removes the element at the specified index from the collection.
*
@ -87,46 +67,6 @@ interface Collection extends Countable, IteratorAggregate, ArrayAccess
*/
public function removeElement($element);
/**
* Checks whether the collection contains an element with the specified key/index.
*
* @param string|int $key The key/index to check for.
* @psalm-param TKey $key
*
* @return bool TRUE if the collection contains an element with the specified key/index,
* FALSE otherwise.
*/
public function containsKey($key);
/**
* Gets the element at the specified key/index.
*
* @param string|int $key The key/index of the element to retrieve.
* @psalm-param TKey $key
*
* @return mixed
* @psalm-return T|null
*/
public function get($key);
/**
* Gets all keys/indices of the collection.
*
* @return int[]|string[] The keys/indices of the collection, in the order of the corresponding
* elements in the collection.
* @psalm-return TKey[]
*/
public function getKeys();
/**
* Gets all values of the collection.
*
* @return mixed[] The values of all elements in the collection, in the
* order they appear in the collection.
* @psalm-return T[]
*/
public function getValues();
/**
* Sets an element in the collection at the specified key/index.
*
@ -140,69 +80,7 @@ interface Collection extends Countable, IteratorAggregate, ArrayAccess
public function set($key, $value);
/**
* Gets a native PHP array representation of the collection.
*
* @return mixed[]
* @psalm-return array<TKey,T>
*/
public function toArray();
/**
* Sets the internal iterator to the first element in the collection and returns this element.
*
* @return mixed
* @psalm-return T|false
*/
public function first();
/**
* Sets the internal iterator to the last element in the collection and returns this element.
*
* @return mixed
* @psalm-return T|false
*/
public function last();
/**
* Gets the key/index of the element at the current iterator position.
*
* @return int|string|null
* @psalm-return TKey|null
*/
public function key();
/**
* Gets the element of the collection at the current iterator position.
*
* @return mixed
* @psalm-return T|false
*/
public function current();
/**
* Moves the internal iterator position to the next element and returns this element.
*
* @return mixed
* @psalm-return T|false
*/
public function next();
/**
* Tests for the existence of an element that satisfies the given predicate.
*
* @param Closure $p The predicate.
* @psalm-param Closure(TKey=, T=):bool $p
*
* @return bool TRUE if the predicate is TRUE for at least one element, FALSE otherwise.
*/
public function exists(Closure $p);
/**
* Returns all the elements of this collection that satisfy the predicate p.
* The order of the elements is preserved.
*
* @param Closure $p The predicate used for filtering.
* @psalm-param Closure(T=):bool $p
* {@inheritdoc}
*
* @return Collection<mixed> A collection with the results of the filter operation.
* @psalm-return Collection<TKey, T>
@ -210,67 +88,12 @@ interface Collection extends Countable, IteratorAggregate, ArrayAccess
public function filter(Closure $p);
/**
* Tests whether the given predicate p holds for all elements of this collection.
* {@inheritdoc}
*
* @param Closure $p The predicate.
* @psalm-param Closure(TKey=, T=):bool $p
*
* @return bool TRUE, if the predicate yields TRUE for all elements, FALSE otherwise.
*/
public function forAll(Closure $p);
/**
* Applies the given function to each element in the collection and returns
* a new collection with the elements returned by the function.
*
* @psalm-param Closure(T=):U $func
*
* @return Collection<mixed>
* @psalm-return Collection<TKey, U>
*
* @psalm-template U
*/
public function map(Closure $func);
/**
* Partitions this collection in two collections according to a predicate.
* Keys are preserved in the resulting collections.
*
* @param Closure $p The predicate on which to partition.
* @psalm-param Closure(TKey=, T=):bool $p
*
* @return Collection<mixed> An array with two elements. The first element contains the collection
* @return Collection<mixed>[] An array with two elements. The first element contains the collection
* of elements where the predicate returned TRUE, the second element
* contains the collection of elements where the predicate returned FALSE.
* @psalm-return array{0: Collection<TKey, T>, 1: Collection<TKey, T>}
*/
public function partition(Closure $p);
/**
* Gets the index/key of a given element. The comparison of two elements is strict,
* that means not only the value but also the type must match.
* For objects this means reference equality.
*
* @param mixed $element The element to search for.
* @psalm-param T $element
*
* @return int|string|bool The key/index of the element or FALSE if the element was not found.
* @psalm-return TKey|false
*/
public function indexOf($element);
/**
* Extracts a slice of $length elements starting at position $offset from the Collection.
*
* If $length is null it returns all elements from $offset to the end of the Collection.
* Keys have to be preserved by this method. Calling this method will only return the
* selected slice and NOT change the elements contained in the collection slice is called on.
*
* @param int $offset The offset to start from.
* @param int|null $length The maximum number of elements to return, or null for no limit.
*
* @return mixed[]
* @psalm-return array<TKey,T>
*/
public function slice($offset, $length = null);
}

View File

@ -4,8 +4,10 @@ namespace Doctrine\Common\Collections;
use Doctrine\Common\Collections\Expr\CompositeExpression;
use Doctrine\Common\Collections\Expr\Expression;
use Doctrine\Deprecations\Deprecation;
use function array_map;
use function func_num_args;
use function strtoupper;
/**
@ -69,6 +71,15 @@ class Criteria
{
$this->expression = $expression;
if ($firstResult === null && func_num_args() > 2) {
Deprecation::trigger(
'doctrine/collections',
'https://github.com/doctrine/collections/pull/311',
'Passing null as $firstResult to the constructor of %s is deprecated. Pass 0 instead or omit the argument.',
self::class
);
}
$this->setFirstResult($firstResult);
$this->setMaxResults($maxResults);
@ -82,7 +93,7 @@ class Criteria
/**
* Sets the where expression to evaluate when this Criteria is searched for.
*
* @return Criteria
* @return $this
*/
public function where(Expression $expression)
{
@ -95,7 +106,7 @@ class Criteria
* Appends the where expression to evaluate when this Criteria is searched for
* using an AND with previous expression.
*
* @return Criteria
* @return $this
*/
public function andWhere(Expression $expression)
{
@ -115,7 +126,7 @@ class Criteria
* Appends the where expression to evaluate when this Criteria is searched for
* using an OR with previous expression.
*
* @return Criteria
* @return $this
*/
public function orWhere(Expression $expression)
{
@ -161,7 +172,7 @@ class Criteria
*
* @param string[] $orderings
*
* @return Criteria
* @return $this
*/
public function orderBy(array $orderings)
{
@ -190,10 +201,19 @@ class Criteria
*
* @param int|null $firstResult The value to set.
*
* @return Criteria
* @return $this
*/
public function setFirstResult($firstResult)
{
if ($firstResult === null) {
Deprecation::triggerIfCalledFromOutside(
'doctrine/collections',
'https://github.com/doctrine/collections/pull/311',
'Passing null to %s() is deprecated, pass 0 instead.',
__METHOD__
);
}
$this->firstResult = $firstResult;
return $this;
@ -214,7 +234,7 @@ class Criteria
*
* @param int|null $maxResults The value to set.
*
* @return Criteria
* @return $this
*/
public function setMaxResults($maxResults)
{

View File

@ -6,6 +6,7 @@ use ArrayAccess;
use Closure;
use RuntimeException;
use function explode;
use function in_array;
use function is_array;
use function is_scalar;
@ -38,11 +39,18 @@ class ClosureExpressionVisitor extends ExpressionVisitor
*/
public static function getObjectFieldValue($object, $field)
{
if (strpos($field, '.') !== false) {
[$field, $subField] = explode('.', $field, 2);
$object = self::getObjectFieldValue($object, $field);
return self::getObjectFieldValue($object, $subField);
}
if (is_array($object)) {
return $object[$field];
}
$accessors = ['get', 'is'];
$accessors = ['get', 'is', ''];
foreach ($accessors as $accessor) {
$accessor .= $field;
@ -231,9 +239,7 @@ class ClosureExpressionVisitor extends ExpressionVisitor
}
}
/**
* @param callable[] $expressions
*/
/** @param callable[] $expressions */
private function andExpressions(array $expressions): callable
{
return static function ($object) use ($expressions): bool {
@ -247,9 +253,7 @@ class ClosureExpressionVisitor extends ExpressionVisitor
};
}
/**
* @param callable[] $expressions
*/
/** @param callable[] $expressions */
private function orExpressions(array $expressions): callable
{
return static function ($object) use ($expressions): bool {

View File

@ -46,25 +46,19 @@ class Comparison implements Expression
$this->value = $value;
}
/**
* @return string
*/
/** @return string */
public function getField()
{
return $this->field;
}
/**
* @return Value
*/
/** @return Value */
public function getValue()
{
return $this->value;
}
/**
* @return string
*/
/** @return string */
public function getOperator()
{
return $this->op;

View File

@ -51,9 +51,7 @@ class CompositeExpression implements Expression
return $this->expressions;
}
/**
* @return string
*/
/** @return string */
public function getType()
{
return $this->type;

View File

@ -7,8 +7,6 @@ namespace Doctrine\Common\Collections\Expr;
*/
interface Expression
{
/**
* @return mixed
*/
/** @return mixed */
public function visit(ExpressionVisitor $visitor);
}

View File

@ -7,17 +7,13 @@ class Value implements Expression
/** @var mixed */
private $value;
/**
* @param mixed $value
*/
/** @param mixed $value */
public function __construct($value)
{
$this->value = $value;
}
/**
* @return mixed
*/
/** @return mixed */
public function getValue()
{
return $this->value;

View File

@ -0,0 +1,213 @@
<?php
namespace Doctrine\Common\Collections;
use Closure;
use Countable;
use IteratorAggregate;
/**
* @psalm-template TKey of array-key
* @template-covariant T
* @template-extends IteratorAggregate<TKey, T>
*/
interface ReadableCollection extends Countable, IteratorAggregate
{
/**
* Checks whether an element is contained in the collection.
* This is an O(n) operation, where n is the size of the collection.
*
* @param mixed $element The element to search for.
* @psalm-param TMaybeContained $element
*
* @return bool TRUE if the collection contains the element, FALSE otherwise.
* @psalm-return (TMaybeContained is T ? bool : false)
*
* @template TMaybeContained
*/
public function contains($element);
/**
* Checks whether the collection is empty (contains no elements).
*
* @return bool TRUE if the collection is empty, FALSE otherwise.
*/
public function isEmpty();
/**
* Checks whether the collection contains an element with the specified key/index.
*
* @param string|int $key The key/index to check for.
* @psalm-param TKey $key
*
* @return bool TRUE if the collection contains an element with the specified key/index,
* FALSE otherwise.
*/
public function containsKey($key);
/**
* Gets the element at the specified key/index.
*
* @param string|int $key The key/index of the element to retrieve.
* @psalm-param TKey $key
*
* @return mixed
* @psalm-return T|null
*/
public function get($key);
/**
* Gets all keys/indices of the collection.
*
* @return int[]|string[] The keys/indices of the collection, in the order of the corresponding
* elements in the collection.
* @psalm-return list<TKey>
*/
public function getKeys();
/**
* Gets all values of the collection.
*
* @return mixed[] The values of all elements in the collection, in the
* order they appear in the collection.
* @psalm-return list<T>
*/
public function getValues();
/**
* Gets a native PHP array representation of the collection.
*
* @return mixed[]
* @psalm-return array<TKey,T>
*/
public function toArray();
/**
* Sets the internal iterator to the first element in the collection and returns this element.
*
* @return mixed
* @psalm-return T|false
*/
public function first();
/**
* Sets the internal iterator to the last element in the collection and returns this element.
*
* @return mixed
* @psalm-return T|false
*/
public function last();
/**
* Gets the key/index of the element at the current iterator position.
*
* @return int|string|null
* @psalm-return TKey|null
*/
public function key();
/**
* Gets the element of the collection at the current iterator position.
*
* @return mixed
* @psalm-return T|false
*/
public function current();
/**
* Moves the internal iterator position to the next element and returns this element.
*
* @return mixed
* @psalm-return T|false
*/
public function next();
/**
* Extracts a slice of $length elements starting at position $offset from the Collection.
*
* If $length is null it returns all elements from $offset to the end of the Collection.
* Keys have to be preserved by this method. Calling this method will only return the
* selected slice and NOT change the elements contained in the collection slice is called on.
*
* @param int $offset The offset to start from.
* @param int|null $length The maximum number of elements to return, or null for no limit.
*
* @return mixed[]
* @psalm-return array<TKey,T>
*/
public function slice($offset, $length = null);
/**
* Tests for the existence of an element that satisfies the given predicate.
*
* @param Closure $p The predicate.
* @psalm-param Closure(TKey, T):bool $p
*
* @return bool TRUE if the predicate is TRUE for at least one element, FALSE otherwise.
*/
public function exists(Closure $p);
/**
* Returns all the elements of this collection that satisfy the predicate p.
* The order of the elements is preserved.
*
* @param Closure $p The predicate used for filtering.
* @psalm-param Closure(T):bool $p
*
* @return ReadableCollection<mixed> A collection with the results of the filter operation.
* @psalm-return ReadableCollection<TKey, T>
*/
public function filter(Closure $p);
/**
* Applies the given function to each element in the collection and returns
* a new collection with the elements returned by the function.
*
* @psalm-param Closure(T):U $func
*
* @return Collection<mixed>
* @psalm-return Collection<TKey, U>
*
* @psalm-template U
*/
public function map(Closure $func);
/**
* Partitions this collection in two collections according to a predicate.
* Keys are preserved in the resulting collections.
*
* @param Closure $p The predicate on which to partition.
* @psalm-param Closure(TKey, T):bool $p
*
* @return ReadableCollection<mixed>[] An array with two elements. The first element contains the collection
* of elements where the predicate returned TRUE, the second element
* contains the collection of elements where the predicate returned FALSE.
* @psalm-return array{0: ReadableCollection<TKey, T>, 1: ReadableCollection<TKey, T>}
*/
public function partition(Closure $p);
/**
* Tests whether the given predicate p holds for all elements of this collection.
*
* @param Closure $p The predicate.
* @psalm-param Closure(TKey, T):bool $p
*
* @return bool TRUE, if the predicate yields TRUE for all elements, FALSE otherwise.
*/
public function forAll(Closure $p);
/**
* Gets the index/key of a given element. The comparison of two elements is strict,
* that means not only the value but also the type must match.
* For objects this means reference equality.
*
* @param mixed $element The element to search for.
* @psalm-param TMaybeContained $element
*
* @return int|string|bool The key/index of the element or FALSE if the element was not found.
* @psalm-return (TMaybeContained is T ? TKey|false : false)
*
* @template TMaybeContained
*/
public function indexOf($element);
}

View File

@ -23,8 +23,8 @@ interface Selectable
* Selects all elements from a selectable that match the expression and
* returns a new collection containing these elements.
*
* @return Collection<mixed>
* @psalm-return Collection<TKey,T>
* @return Collection<mixed>&Selectable<mixed>
* @psalm-return Collection<TKey,T>&Selectable<TKey,T>
*/
public function matching(Criteria $criteria);
}

View File

@ -1,17 +0,0 @@
parameters:
level: 3
paths:
- lib
ignoreErrors:
# Making classes final as suggested would be a BC-break
-
message: '~Unsafe usage of new static\(\)\.~'
paths:
- 'lib/Doctrine/Common/Collections/ArrayCollection.php'
- 'lib/Doctrine/Common/Collections/Criteria.php'
-
message: '~Array \(array\<TKey of \(int\|string\), T\>\) does not accept key int\.~'
path: 'lib/Doctrine/Common/Collections/ArrayCollection.php'
# This class is new in PHP 8.1 and PHPStan does not know it yet.
- '/Attribute class ReturnTypeWillChange does not exist./'

View File

@ -1,65 +0,0 @@
<?xml version="1.0"?>
<psalm
totallyTyped="false"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
>
<projectFiles>
<directory name="lib" />
<ignoreFiles>
<directory name="vendor" />
<directory name="lib/Doctrine/Common/Collections/Expr"/>
</ignoreFiles>
</projectFiles>
<issueHandlers>
<LessSpecificReturnType errorLevel="info" />
<!-- level 3 issues - slightly lazy code writing, but provably low false-negatives -->
<DeprecatedMethod errorLevel="info" />
<DeprecatedProperty errorLevel="info" />
<DeprecatedClass errorLevel="info" />
<DeprecatedConstant errorLevel="info" />
<DeprecatedInterface errorLevel="info" />
<DeprecatedTrait errorLevel="info" />
<InternalMethod errorLevel="info" />
<InternalProperty errorLevel="info" />
<InternalClass errorLevel="info" />
<MissingClosureReturnType errorLevel="info" />
<MissingReturnType errorLevel="info" />
<MissingPropertyType errorLevel="info" />
<InvalidDocblock errorLevel="info" />
<PropertyNotSetInConstructor errorLevel="info" />
<MissingConstructor errorLevel="info" />
<MissingClosureParamType errorLevel="info" />
<MissingParamType errorLevel="info" />
<RedundantCondition errorLevel="info" />
<DocblockTypeContradiction errorLevel="info" />
<RedundantConditionGivenDocblockType errorLevel="info" />
<UnresolvableInclude errorLevel="info" />
<RawObjectIteration errorLevel="info" />
<InvalidStringClass errorLevel="info" />
<UnsafeGenericInstantiation>
<errorLevel type="suppress">
<file name="lib/Doctrine/Common/Collections/ArrayCollection.php"/>
</errorLevel>
</UnsafeGenericInstantiation>
<UndefinedAttributeClass>
<errorLevel type="suppress">
<!-- This class is new in PHP 8.1 and Psalm does not know it yet. -->
<referencedClass name="ReturnTypeWillChange"/>
</errorLevel>
</UndefinedAttributeClass>
</issueHandlers>
</psalm>

View File

@ -0,0 +1,19 @@
Copyright (c) 2020-2021 Doctrine Project
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,154 @@
# Doctrine Deprecations
A small (side-effect free by default) layer on top of
`trigger_error(E_USER_DEPRECATED)` or PSR-3 logging.
- no side-effects by default, making it a perfect fit for libraries that don't know how the error handler works they operate under
- options to avoid having to rely on error handlers global state by using PSR-3 logging
- deduplicate deprecation messages to avoid excessive triggering and reduce overhead
We recommend to collect Deprecations using a PSR logger instead of relying on
the global error handler.
## Usage from consumer perspective:
Enable Doctrine deprecations to be sent to a PSR3 logger:
```php
\Doctrine\Deprecations\Deprecation::enableWithPsrLogger($logger);
```
Enable Doctrine deprecations to be sent as `@trigger_error($message, E_USER_DEPRECATED)`
messages.
```php
\Doctrine\Deprecations\Deprecation::enableWithTriggerError();
```
If you only want to enable deprecation tracking, without logging or calling `trigger_error` then call:
```php
\Doctrine\Deprecations\Deprecation::enableTrackingDeprecations();
```
Tracking is enabled with all three modes and provides access to all triggered
deprecations and their individual count:
```php
$deprecations = \Doctrine\Deprecations\Deprecation::getTriggeredDeprecations();
foreach ($deprecations as $identifier => $count) {
echo $identifier . " was triggered " . $count . " times\n";
}
```
### Suppressing Specific Deprecations
Disable triggering about specific deprecations:
```php
\Doctrine\Deprecations\Deprecation::ignoreDeprecations("https://link/to/deprecations-description-identifier");
```
Disable all deprecations from a package
```php
\Doctrine\Deprecations\Deprecation::ignorePackage("doctrine/orm");
```
### Other Operations
When used within PHPUnit or other tools that could collect multiple instances of the same deprecations
the deduplication can be disabled:
```php
\Doctrine\Deprecations\Deprecation::withoutDeduplication();
```
Disable deprecation tracking again:
```php
\Doctrine\Deprecations\Deprecation::disable();
```
## Usage from a library/producer perspective:
When you want to unconditionally trigger a deprecation even when called
from the library itself then the `trigger` method is the way to go:
```php
\Doctrine\Deprecations\Deprecation::trigger(
"doctrine/orm",
"https://link/to/deprecations-description",
"message"
);
```
If variable arguments are provided at the end, they are used with `sprintf` on
the message.
```php
\Doctrine\Deprecations\Deprecation::trigger(
"doctrine/orm",
"https://github.com/doctrine/orm/issue/1234",
"message %s %d",
"foo",
1234
);
```
When you want to trigger a deprecation only when it is called by a function
outside of the current package, but not trigger when the package itself is the cause,
then use:
```php
\Doctrine\Deprecations\Deprecation::triggerIfCalledFromOutside(
"doctrine/orm",
"https://link/to/deprecations-description",
"message"
);
```
Based on the issue link each deprecation message is only triggered once per
request.
A limited stacktrace is included in the deprecation message to find the
offending location.
Note: A producer/library should never call `Deprecation::enableWith` methods
and leave the decision how to handle deprecations to application and
frameworks.
## Usage in PHPUnit tests
There is a `VerifyDeprecations` trait that you can use to make assertions on
the occurrence of deprecations within a test.
```php
use Doctrine\Deprecations\PHPUnit\VerifyDeprecations;
class MyTest extends TestCase
{
use VerifyDeprecations;
public function testSomethingDeprecation()
{
$this->expectDeprecationWithIdentifier('https://github.com/doctrine/orm/issue/1234');
triggerTheCodeWithDeprecation();
}
public function testSomethingDeprecationFixed()
{
$this->expectNoDeprecationWithIdentifier('https://github.com/doctrine/orm/issue/1234');
triggerTheCodeWithoutDeprecation();
}
}
```
## What is a deprecation identifier?
An identifier for deprecations is just a link to any resource, most often a
Github Issue or Pull Request explaining the deprecation and potentially its
alternative.

View File

@ -0,0 +1,32 @@
{
"name": "doctrine/deprecations",
"type": "library",
"description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.",
"homepage": "https://www.doctrine-project.org/",
"license": "MIT",
"require": {
"php": "^7.1|^8.0"
},
"require-dev": {
"phpunit/phpunit": "^7.5|^8.5|^9.5",
"psr/log": "^1|^2|^3",
"doctrine/coding-standard": "^9"
},
"suggest": {
"psr/log": "Allows logging deprecations via PSR-3 logger implementation"
},
"autoload": {
"psr-4": {"Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations"}
},
"autoload-dev": {
"psr-4": {
"DeprecationTests\\": "test_fixtures/src",
"Doctrine\\Foo\\": "test_fixtures/vendor/doctrine/foo"
}
},
"config": {
"allow-plugins": {
"dealerdirect/phpcodesniffer-composer-installer": true
}
}
}

View File

@ -0,0 +1,266 @@
<?php
declare(strict_types=1);
namespace Doctrine\Deprecations;
use Psr\Log\LoggerInterface;
use function array_key_exists;
use function array_reduce;
use function debug_backtrace;
use function sprintf;
use function strpos;
use function strrpos;
use function substr;
use function trigger_error;
use const DEBUG_BACKTRACE_IGNORE_ARGS;
use const DIRECTORY_SEPARATOR;
use const E_USER_DEPRECATED;
/**
* Manages Deprecation logging in different ways.
*
* By default triggered exceptions are not logged.
*
* To enable different deprecation logging mechanisms you can call the
* following methods:
*
* - Minimal collection of deprecations via getTriggeredDeprecations()
* \Doctrine\Deprecations\Deprecation::enableTrackingDeprecations();
*
* - Uses @trigger_error with E_USER_DEPRECATED
* \Doctrine\Deprecations\Deprecation::enableWithTriggerError();
*
* - Sends deprecation messages via a PSR-3 logger
* \Doctrine\Deprecations\Deprecation::enableWithPsrLogger($logger);
*
* Packages that trigger deprecations should use the `trigger()` or
* `triggerIfCalledFromOutside()` methods.
*/
class Deprecation
{
private const TYPE_NONE = 0;
private const TYPE_TRACK_DEPRECATIONS = 1;
private const TYPE_TRIGGER_ERROR = 2;
private const TYPE_PSR_LOGGER = 4;
/** @var int */
private static $type = self::TYPE_NONE;
/** @var LoggerInterface|null */
private static $logger;
/** @var array<string,bool> */
private static $ignoredPackages = [];
/** @var array<string,int> */
private static $ignoredLinks = [];
/** @var bool */
private static $deduplication = true;
/**
* Trigger a deprecation for the given package and identfier.
*
* The link should point to a Github issue or Wiki entry detailing the
* deprecation. It is additionally used to de-duplicate the trigger of the
* same deprecation during a request.
*
* @param mixed $args
*/
public static function trigger(string $package, string $link, string $message, ...$args): void
{
if (self::$type === self::TYPE_NONE) {
return;
}
if (array_key_exists($link, self::$ignoredLinks)) {
self::$ignoredLinks[$link]++;
} else {
self::$ignoredLinks[$link] = 1;
}
if (self::$deduplication === true && self::$ignoredLinks[$link] > 1) {
return;
}
if (isset(self::$ignoredPackages[$package])) {
return;
}
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
$message = sprintf($message, ...$args);
self::delegateTriggerToBackend($message, $backtrace, $link, $package);
}
/**
* Trigger a deprecation for the given package and identifier when called from outside.
*
* "Outside" means we assume that $package is currently installed as a
* dependency and the caller is not a file in that package. When $package
* is installed as a root package then deprecations triggered from the
* tests folder are also considered "outside".
*
* This deprecation method assumes that you are using Composer to install
* the dependency and are using the default /vendor/ folder and not a
* Composer plugin to change the install location. The assumption is also
* that $package is the exact composer packge name.
*
* Compared to {@link trigger()} this method causes some overhead when
* deprecation tracking is enabled even during deduplication, because it
* needs to call {@link debug_backtrace()}
*
* @param mixed $args
*/
public static function triggerIfCalledFromOutside(string $package, string $link, string $message, ...$args): void
{
if (self::$type === self::TYPE_NONE) {
return;
}
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
// first check that the caller is not from a tests folder, in which case we always let deprecations pass
if (strpos($backtrace[1]['file'], DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR) === false) {
$path = DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . $package . DIRECTORY_SEPARATOR;
if (strpos($backtrace[0]['file'], $path) === false) {
return;
}
if (strpos($backtrace[1]['file'], $path) !== false) {
return;
}
}
if (array_key_exists($link, self::$ignoredLinks)) {
self::$ignoredLinks[$link]++;
} else {
self::$ignoredLinks[$link] = 1;
}
if (self::$deduplication === true && self::$ignoredLinks[$link] > 1) {
return;
}
if (isset(self::$ignoredPackages[$package])) {
return;
}
$message = sprintf($message, ...$args);
self::delegateTriggerToBackend($message, $backtrace, $link, $package);
}
/**
* @param array<mixed> $backtrace
*/
private static function delegateTriggerToBackend(string $message, array $backtrace, string $link, string $package): void
{
if ((self::$type & self::TYPE_PSR_LOGGER) > 0) {
$context = [
'file' => $backtrace[0]['file'],
'line' => $backtrace[0]['line'],
'package' => $package,
'link' => $link,
];
self::$logger->notice($message, $context);
}
if (! ((self::$type & self::TYPE_TRIGGER_ERROR) > 0)) {
return;
}
$message .= sprintf(
' (%s:%d called by %s:%d, %s, package %s)',
self::basename($backtrace[0]['file']),
$backtrace[0]['line'],
self::basename($backtrace[1]['file']),
$backtrace[1]['line'],
$link,
$package
);
@trigger_error($message, E_USER_DEPRECATED);
}
/**
* A non-local-aware version of PHPs basename function.
*/
private static function basename(string $filename): string
{
$pos = strrpos($filename, DIRECTORY_SEPARATOR);
if ($pos === false) {
return $filename;
}
return substr($filename, $pos + 1);
}
public static function enableTrackingDeprecations(): void
{
self::$type |= self::TYPE_TRACK_DEPRECATIONS;
}
public static function enableWithTriggerError(): void
{
self::$type |= self::TYPE_TRIGGER_ERROR;
}
public static function enableWithPsrLogger(LoggerInterface $logger): void
{
self::$type |= self::TYPE_PSR_LOGGER;
self::$logger = $logger;
}
public static function withoutDeduplication(): void
{
self::$deduplication = false;
}
public static function disable(): void
{
self::$type = self::TYPE_NONE;
self::$logger = null;
self::$deduplication = true;
foreach (self::$ignoredLinks as $link => $count) {
self::$ignoredLinks[$link] = 0;
}
}
public static function ignorePackage(string $packageName): void
{
self::$ignoredPackages[$packageName] = true;
}
public static function ignoreDeprecations(string ...$links): void
{
foreach ($links as $link) {
self::$ignoredLinks[$link] = 0;
}
}
public static function getUniqueTriggeredDeprecationsCount(): int
{
return array_reduce(self::$ignoredLinks, static function (int $carry, int $count) {
return $carry + $count;
}, 0);
}
/**
* Returns each triggered deprecation link identifier and the amount of occurrences.
*
* @return array<string,int>
*/
public static function getTriggeredDeprecations(): array
{
return self::$ignoredLinks;
}
}

View File

@ -0,0 +1,66 @@
<?php
declare(strict_types=1);
namespace Doctrine\Deprecations\PHPUnit;
use Doctrine\Deprecations\Deprecation;
use function sprintf;
trait VerifyDeprecations
{
/** @var array<string,int> */
private $doctrineDeprecationsExpectations = [];
/** @var array<string,int> */
private $doctrineNoDeprecationsExpectations = [];
public function expectDeprecationWithIdentifier(string $identifier): void
{
$this->doctrineDeprecationsExpectations[$identifier] = Deprecation::getTriggeredDeprecations()[$identifier] ?? 0;
}
public function expectNoDeprecationWithIdentifier(string $identifier): void
{
$this->doctrineNoDeprecationsExpectations[$identifier] = Deprecation::getTriggeredDeprecations()[$identifier] ?? 0;
}
/**
* @before
*/
public function enableDeprecationTracking(): void
{
Deprecation::enableTrackingDeprecations();
}
/**
* @after
*/
public function verifyDeprecationsAreTriggered(): void
{
foreach ($this->doctrineDeprecationsExpectations as $identifier => $expectation) {
$actualCount = Deprecation::getTriggeredDeprecations()[$identifier] ?? 0;
$this->assertTrue(
$actualCount > $expectation,
sprintf(
"Expected deprecation with identifier '%s' was not triggered by code executed in test.",
$identifier
)
);
}
foreach ($this->doctrineNoDeprecationsExpectations as $identifier => $expectation) {
$actualCount = Deprecation::getTriggeredDeprecations()[$identifier] ?? 0;
$this->assertTrue(
$actualCount === $expectation,
sprintf(
"Expected deprecation with identifier '%s' was triggered by code executed in test, but expected not to.",
$identifier
)
);
}
}
}

View File

@ -0,0 +1,22 @@
<?xml version="1.0"?>
<ruleset>
<arg name="basepath" value="."/>
<arg name="extensions" value="php"/>
<arg name="parallel" value="80"/>
<arg name="cache" value=".phpcs-cache"/>
<arg name="colors"/>
<!-- Ignore warnings, show progress of the run and show sniff names -->
<arg value="nps"/>
<config name="php_version" value="70100"/>
<!-- Directories to be checked -->
<file>lib</file>
<file>tests</file>
<!-- Include full Doctrine Coding Standard -->
<rule ref="Doctrine">
<exclude name="SlevomatCodingStandard.TypeHints.PropertyTypeHint.MissingNativeTypeHint" />
</rule>
</ruleset>

View File

@ -5,14 +5,21 @@
"docsSlug": "doctrine-event-manager",
"versions": [
{
"name": "1.0",
"branchName": "master",
"name": "1.1",
"branchName": "1.1.x",
"slug": "latest",
"current": true,
"aliases": [
"current",
"stable"
]
},
{
"name": "1.0",
"branchName": "1.0",
"slug": "1.0",
"current": false,
"maintained": false
}
]
}

View File

@ -1,6 +1,6 @@
# Doctrine Event Manager
[![Build Status](https://travis-ci.org/doctrine/event-manager.svg)](https://travis-ci.org/doctrine/event-manager)
[![Build Status](https://github.com/doctrine/event-manager/workflows/Continuous%20Integration/badge.svg)](https://github.com/doctrine/event-manager/actions)
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/doctrine/event-manager/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/doctrine/event-manager/?branch=master)
[![Code Coverage](https://scrutinizer-ci.com/g/doctrine/event-manager/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/doctrine/event-manager/?branch=master)

View File

@ -23,13 +23,18 @@
"php": "^7.1 || ^8.0"
},
"require-dev": {
"doctrine/coding-standard": "^6.0",
"phpunit/phpunit": "^7.0"
"doctrine/coding-standard": "^9",
"phpstan/phpstan": "~1.4.10 || ^1.5.4",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
"vimeo/psalm": "^4.22"
},
"conflict": {
"doctrine/common": "<2.9@dev"
"doctrine/common": "<2.9"
},
"config": {
"allow-plugins": {
"dealerdirect/phpcodesniffer-composer-installer": true
},
"sort-packages": true
},
"autoload": {
@ -41,10 +46,5 @@
"psr-4": {
"Doctrine\\Tests\\": "tests/Doctrine/Tests"
}
},
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
}
}

View File

@ -16,7 +16,7 @@ class EventArgs
/**
* Single instance of EventArgs.
*
* @var EventArgs
* @var EventArgs|null
*/
private static $_emptyEventArgsInstance;

View File

@ -48,6 +48,7 @@ class EventManager
* @param string|null $event The name of the event.
*
* @return object[]|object[][] The event listeners for the specified event, or all event listeners.
* @psalm-return ($event is null ? object[][] : object[])
*/
public function getListeners($event = null)
{

View File

@ -5,7 +5,7 @@ declare(strict_types=1);
namespace Doctrine\Common;
/**
* An EventSubscriber knows himself what events he is interested in.
* An EventSubscriber knows what events it is interested in.
* If an EventSubscriber is added to an EventManager, the manager invokes
* {@link getSubscribedEvents} and registers the subscriber as a listener for all
* returned events.

View File

@ -0,0 +1,5 @@
parameters:
level: 9
paths:
- lib/
- tests/

View File

@ -0,0 +1,15 @@
<?xml version="1.0"?>
<psalm
errorLevel="2"
resolveFromConfigFile="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
>
<projectFiles>
<directory name="lib/Doctrine/Common" />
<ignoreFiles>
<directory name="vendor" />
</ignoreFiles>
</projectFiles>
</psalm>

View File

@ -1,5 +1,11 @@
# CHANGELOG
## 1.5.2 - 2022-08-07
### Changed
- Officially support PHP 8.2
## 1.5.1 - 2021-10-22
### Fixed
@ -12,10 +18,11 @@
### Changed
- Call handler when waiting on fulfilled/rejected Promise
- Officially support PHP 8.1
### Fixed
- Fix manually settle promises generated with Utils::task
- Fix manually settle promises generated with `Utils::task`
## 1.4.1 - 2021-02-18

View File

@ -1,13 +0,0 @@
all: clean test
test:
vendor/bin/phpunit
coverage:
vendor/bin/phpunit --coverage-html=artifacts/coverage
view-coverage:
open artifacts/coverage/index.html
clean:
rm -rf artifacts/*

View File

@ -17,7 +17,7 @@ for a general introduction to promises.
- [Implementation notes](#implementation-notes)
# Features
## Features
- [Promises/A+](https://promisesaplus.com/) implementation.
- Promise resolution and chaining is handled iteratively, allowing for
@ -29,15 +29,14 @@ for a general introduction to promises.
`GuzzleHttp\Promise\Coroutine::of()`.
# Quick start
## Quick Start
A *promise* represents the eventual result of an asynchronous operation. The
primary way of interacting with a promise is through its `then` method, which
registers callbacks to receive either a promise's eventual value or the reason
why the promise cannot be fulfilled.
## Callbacks
### Callbacks
Callbacks are registered with the `then` method by providing an optional
`$onFulfilled` followed by an optional `$onRejected` function.
@ -60,12 +59,11 @@ $promise->then(
```
*Resolving* a promise means that you either fulfill a promise with a *value* or
reject a promise with a *reason*. Resolving a promises triggers callbacks
registered with the promises's `then` method. These callbacks are triggered
reject a promise with a *reason*. Resolving a promise triggers callbacks
registered with the promise's `then` method. These callbacks are triggered
only once and in the order in which they were added.
## Resolving a promise
### Resolving a Promise
Promises are fulfilled using the `resolve($value)` method. Resolving a promise
with any value other than a `GuzzleHttp\Promise\RejectedPromise` will trigger
@ -92,8 +90,7 @@ $promise
$promise->resolve('reader.');
```
## Promise forwarding
### Promise Forwarding
Promises can be chained one after the other. Each then in the chain is a new
promise. The return value of a promise is what's forwarded to the next
@ -123,7 +120,7 @@ $promise->resolve('A');
$nextPromise->resolve('B');
```
## Promise rejection
### Promise Rejection
When a promise is rejected, the `$onRejected` callbacks are invoked with the
rejection reason.
@ -140,7 +137,7 @@ $promise->reject('Error!');
// Outputs "Error!"
```
## Rejection forwarding
### Rejection Forwarding
If an exception is thrown in an `$onRejected` callback, subsequent
`$onRejected` callbacks are invoked with the thrown exception as the reason.
@ -195,7 +192,8 @@ $promise
$promise->reject('Error!');
```
# Synchronous wait
## Synchronous Wait
You can synchronously force promises to complete using a promise's `wait`
method. When creating a promise, you can provide a wait function that is used
@ -247,8 +245,7 @@ $promise->wait();
> PHP Fatal error: Uncaught exception 'GuzzleHttp\Promise\RejectionException' with message 'The promise was rejected with value: foo'
## Unwrapping a promise
### Unwrapping a Promise
When synchronously waiting on a promise, you are joining the state of the
promise into the current state of execution (i.e., return the value of the
@ -275,7 +272,7 @@ wait function will be the value delivered to promise B.
**Note**: when you do not unwrap the promise, no value is returned.
# Cancellation
## Cancellation
You can cancel a promise that has not yet been fulfilled using the `cancel()`
method of a promise. When creating a promise you can provide an optional
@ -283,10 +280,9 @@ cancel function that when invoked cancels the action of computing a resolution
of the promise.
# API
## API
## Promise
### Promise
When creating a promise object, you can provide an optional `$waitFn` and
`$cancelFn`. `$waitFn` is a function that is invoked with no arguments and is
@ -349,7 +345,7 @@ A promise has the following methods:
Rejects the promise with the given `$reason`.
## FulfilledPromise
### FulfilledPromise
A fulfilled promise can be created to represent a promise that has been
fulfilled.
@ -366,7 +362,7 @@ $promise->then(function ($value) {
```
## RejectedPromise
### RejectedPromise
A rejected promise can be created to represent a promise that has been
rejected.
@ -383,7 +379,7 @@ $promise->then(null, function ($reason) {
```
# Promise interop
## Promise Interoperability
This library works with foreign promises that have a `then` method. This means
you can use Guzzle promises with [React promises](https://github.com/reactphp/promise)
@ -409,7 +405,7 @@ a foreign promise. You will need to wrap a third-party promise with a Guzzle
promise in order to utilize wait and cancel functions with foreign promises.
## Event Loop Integration
### Event Loop Integration
In order to keep the stack size constant, Guzzle promises are resolved
asynchronously using a task queue. When waiting on promises synchronously, the
@ -437,10 +433,9 @@ $loop->addPeriodicTimer(0, [$queue, 'run']);
*TODO*: Perhaps adding a `futureTick()` on each tick would be faster?
# Implementation notes
## Implementation Notes
## Promise resolution and chaining is handled iteratively
### Promise Resolution and Chaining is Handled Iteratively
By shuffling pending handlers from one owner to another, promises are
resolved iteratively, allowing for "infinite" then chaining.
@ -476,8 +471,7 @@ all of its pending handlers to the new promise. When the new promise is
eventually resolved, all of the pending handlers are delivered the forwarded
value.
## A promise is the deferred.
### A Promise is the Deferred
Some promise libraries implement promises using a deferred object to represent
a computation and a promise object to represent the delivery of the result of
@ -505,7 +499,10 @@ $promise->resolve('foo');
## Upgrading from Function API
A static API was first introduced in 1.4.0, in order to mitigate problems with functions conflicting between global and local copies of the package. The function API will be removed in 2.0.0. A migration table has been provided here for your convenience:
A static API was first introduced in 1.4.0, in order to mitigate problems with
functions conflicting between global and local copies of the package. The
function API will be removed in 2.0.0. A migration table has been provided here
for your convenience:
| Original Function | Replacement Method |
|----------------|----------------|
@ -536,10 +533,12 @@ A static API was first introduced in 1.4.0, in order to mitigate problems with f
If you discover a security vulnerability within this package, please send an email to security@tidelift.com. All security vulnerabilities will be promptly addressed. Please do not disclose security-related issues publicly until a fix has been announced. Please see [Security Policy](https://github.com/guzzle/promises/security/policy) for more information.
## License
Guzzle is made available under the MIT License (MIT). Please see [License File](LICENSE) for more information.
## For Enterprise
Available as part of the Tidelift Subscription

View File

@ -81,16 +81,8 @@ class EachPromise implements PromisorInterface
$this->iterable->rewind();
$this->refillPending();
} catch (\Throwable $e) {
/**
* @psalm-suppress NullReference
* @phpstan-ignore-next-line
*/
$this->aggregate->reject($e);
} catch (\Exception $e) {
/**
* @psalm-suppress NullReference
* @phpstan-ignore-next-line
*/
$this->aggregate->reject($e);
}

View File

@ -1,3 +1,19 @@
> # UKRAINE NEEDS YOUR HELP NOW!
>
> On 24 February 2022, Russian [President Vladimir Putin ordered an invasion of Ukraine by Russian Armed Forces](https://www.bbc.com/news/world-europe-60504334).
>
> Your support is urgently needed.
>
> - Donate to the volunteers. Here is the volunteer fund helping the Ukrainian army to provide all the necessary equipment:
> https://bank.gov.ua/en/news/all/natsionalniy-bank-vidkriv-spetsrahunok-dlya-zboru-koshtiv-na-potrebi-armiyi or https://savelife.in.ua/en/donate/
> - Triple-check social media sources. Russian disinformation is attempting to coverup and distort the reality in Ukraine.
> - Help Ukrainian refugees who are fleeing Russian attacks and shellings: https://www.globalcitizen.org/en/content/ways-to-help-ukraine-conflict/
> - Put pressure on your political representatives to provide help to Ukraine.
> - Believe in the Ukrainian people, they will not surrender, they don't have another Ukraine.
>
> THANK YOU!
----
# HTML5-PHP
HTML5 is a standards-compliant HTML5 parser and writer written entirely in PHP.

View File

@ -1,5 +1,9 @@
# Release Notes
2.7.6 (2021-08-18)
- #218: Address comment handling issues
2.7.5 (2021-07-01)
- #204: Travis: Enable tests on PHP 8.0

View File

@ -104,7 +104,7 @@ class Scanner
*/
public function peek()
{
if (($this->char + 1) <= $this->EOF) {
if (($this->char + 1) < $this->EOF) {
return $this->data[$this->char + 1];
}

View File

@ -712,18 +712,24 @@ class Tokenizer
return true;
}
// If it doesn't start with -, not the end.
if ('-' != $tok) {
// If next two tokens are not '--', not the end.
if ('-' != $tok || '-' != $this->scanner->peek()) {
return false;
}
// Advance one, and test for '->'
if ('-' == $this->scanner->next() && '>' == $this->scanner->peek()) {
$this->scanner->consume(2); // Consume '-' and one of '!' or '>'
// Test for '>'
if ('>' == $this->scanner->current()) {
return true;
}
// Test for '!>'
if ('!' == $this->scanner->current() && '>' == $this->scanner->peek()) {
$this->scanner->consume(); // Consume the last '>'
return true;
}
// Unread '-';
$this->scanner->unconsume(1);
// Unread '-' and one of '!' or '>';
$this->scanner->unconsume(2);
return false;
}

View File

@ -195,7 +195,7 @@ class Command
*
* @return int The command exit code
*
* @throws \Exception When binding input fails. Bypass this by calling {@link ignoreValidationErrors()}.
* @throws ExceptionInterface When input binding fails. Bypass this by calling {@link ignoreValidationErrors()}.
*
* @see setCode()
* @see execute()

View File

@ -55,7 +55,7 @@ class AddConsoleCommandPass implements CompilerPassInterface
if (!$r->isSubclassOf(Command::class)) {
throw new InvalidArgumentException(sprintf('The service "%s" tagged "%s" must be a subclass of "%s".', $id, $this->commandTag, Command::class));
}
$commandName = $class::getDefaultName() !== null ? str_replace('%', '%%', $class::getDefaultName()) : null;
$commandName = null !== $class::getDefaultName() ? str_replace('%', '%%', $class::getDefaultName()) : null;
}
if (null === $commandName) {

View File

@ -131,7 +131,7 @@ class ApplicationDescription
}
if ($namespacedCommands) {
ksort($namespacedCommands);
ksort($namespacedCommands, \SORT_STRING);
foreach ($namespacedCommands as $key => $commandsSet) {
ksort($commandsSet);
$sortedCommands[$key] = $commandsSet;

View File

@ -641,7 +641,7 @@ class Table
{
$unmergedRows = [];
foreach ($rows[$line] as $column => $cell) {
if (null !== $cell && !$cell instanceof TableCell && !is_scalar($cell) && !(\is_object($cell) && method_exists($cell, '__toString'))) {
if (null !== $cell && !$cell instanceof TableCell && !\is_scalar($cell) && !(\is_object($cell) && method_exists($cell, '__toString'))) {
throw new InvalidArgumentException(sprintf('A cell must be a TableCell, a scalar or an object implementing "__toString()", "%s" given.', \gettype($cell)));
}
if ($cell instanceof TableCell && $cell->getRowspan() > 1) {

View File

@ -110,7 +110,7 @@ class ConsoleLogger extends AbstractLogger
$replacements = [];
foreach ($context as $key => $val) {
if (null === $val || is_scalar($val) || (\is_object($val) && method_exists($val, '__toString'))) {
if (null === $val || \is_scalar($val) || (\is_object($val) && method_exists($val, '__toString'))) {
$replacements["{{$key}}"] = $val;
} elseif ($val instanceof \DateTimeInterface) {
$replacements["{{$key}}"] = $val->format(\DateTime::RFC3339);

View File

@ -430,18 +430,18 @@ class SymfonyStyle extends OutputStyle
$chars = substr(str_replace(\PHP_EOL, "\n", $this->bufferedOutput->fetch()), -2);
if (!isset($chars[0])) {
$this->newLine(); //empty history, so we should start with a new line.
$this->newLine(); // empty history, so we should start with a new line.
return;
}
//Prepend new line for each non LF chars (This means no blank line was output before)
// Prepend new line for each non LF chars (This means no blank line was output before)
$this->newLine(2 - substr_count($chars, "\n"));
}
private function autoPrependText(): void
{
$fetched = $this->bufferedOutput->fetch();
//Prepend new line if last char isn't EOL:
// Prepend new line if last char isn't EOL:
if (!str_ends_with($fetched, "\n")) {
$this->newLine();
}

View File

@ -49,7 +49,7 @@ class Debug
if (!\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true)) {
ini_set('display_errors', 0);
ExceptionHandler::register();
} elseif ($displayErrors && (!filter_var(ini_get('log_errors'), \FILTER_VALIDATE_BOOLEAN) || ini_get('error_log'))) {
} elseif ($displayErrors && (!filter_var(\ini_get('log_errors'), \FILTER_VALIDATE_BOOLEAN) || \ini_get('error_log'))) {
// CLI - display errors only if they're not already logged to STDERR
ini_set('display_errors', 1);
}

View File

@ -354,8 +354,8 @@ class ErrorHandler
*/
private function reRegister(int $prev)
{
if ($prev !== $this->thrownErrors | $this->loggedErrors) {
$handler = set_error_handler('var_dump');
if ($prev !== ($this->thrownErrors | $this->loggedErrors)) {
$handler = set_error_handler('is_int');
$handler = \is_array($handler) ? $handler[0] : null;
restore_error_handler();
if ($handler === $this) {
@ -490,7 +490,7 @@ class ErrorHandler
$log = 0;
} else {
if (\PHP_VERSION_ID < (\PHP_VERSION_ID < 70400 ? 70316 : 70404)) {
$currentErrorHandler = set_error_handler('var_dump');
$currentErrorHandler = set_error_handler('is_int');
restore_error_handler();
}
@ -601,7 +601,7 @@ class ErrorHandler
$sameHandlerLimit = 10;
while (!\is_array($handler) || !$handler[0] instanceof self) {
$handler = set_exception_handler('var_dump');
$handler = set_exception_handler('is_int');
restore_exception_handler();
if (!$handler) {

View File

@ -55,7 +55,7 @@ class ExceptionHandler
public function __construct(bool $debug = true, string $charset = null, $fileLinkFormat = null)
{
$this->debug = $debug;
$this->charset = $charset ?: ini_get('default_charset') ?: 'UTF-8';
$this->charset = $charset ?: \ini_get('default_charset') ?: 'UTF-8';
$this->fileLinkFormat = $fileLinkFormat;
}
@ -390,7 +390,7 @@ EOF;
private function formatPath(string $path, int $line): string
{
$file = $this->escapeHtml(preg_match('#[^/\\\\]*+$#', $path, $file) ? $file[0] : $path);
$fmt = $this->fileLinkFormat ?: ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format');
$fmt = $this->fileLinkFormat ?: \ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format');
if (!$fmt) {
return sprintf('<span class="block trace-file-path">in <span title="%s%3$s"><strong>%s</strong>%s</span></span>', $this->escapeHtml($path), $file, 0 < $line ? ' line '.$line : '');

View File

@ -120,7 +120,7 @@ class AnalyzeServiceReferencesPass extends AbstractRecursivePass implements Repe
$value,
$this->lazy || ($targetDefinition && $targetDefinition->isLazy()),
true
);
);
}
return $value;

View File

@ -63,7 +63,7 @@ class CheckDefinitionValidityPass implements CompilerPassInterface
foreach ($definition->getTags() as $name => $tags) {
foreach ($tags as $attributes) {
foreach ($attributes as $attribute => $value) {
if (!is_scalar($value) && null !== $value) {
if (!\is_scalar($value) && null !== $value) {
throw new RuntimeException(sprintf('A "tags" attribute must be of a scalar-type for service "%s", tag "%s", attribute "%s".', $id, $name, $attribute));
}
}

View File

@ -143,7 +143,7 @@ class Definition
*
* @throws InvalidArgumentException in case the decorated service id and the new decorated service id are equals
*/
public function setDecoratedService($id, $renamedId = null, $priority = 0/*, int $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE*/)
public function setDecoratedService($id, $renamedId = null, $priority = 0/* , int $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE */)
{
if ($renamedId && $id === $renamedId) {
throw new InvalidArgumentException(sprintf('The decorated service inner name for "%s" must be different than the service name itself.', $id));
@ -370,7 +370,7 @@ class Definition
*
* @throws InvalidArgumentException on empty $method param
*/
public function addMethodCall($method, array $arguments = []/*, bool $returnsClone = false*/)
public function addMethodCall($method, array $arguments = []/* , bool $returnsClone = false */)
{
if (empty($method)) {
throw new InvalidArgumentException('Method name cannot be empty.');

View File

@ -688,13 +688,13 @@ EOF;
if ($v instanceof Reference && $this->container->has($id = (string) $v) && $this->container->findDefinition($id)->isSynthetic()) {
continue;
}
if (!is_scalar($v) || $this->dumpValue($v) !== $this->dumpValue($v, false)) {
if (!\is_scalar($v) || $this->dumpValue($v) !== $this->dumpValue($v, false)) {
return false;
}
}
} elseif ($arg instanceof Reference && $this->container->has($id = (string) $arg) && $this->container->findDefinition($id)->isSynthetic()) {
continue;
} elseif (!is_scalar($arg) || $this->dumpValue($arg) !== $this->dumpValue($arg, false)) {
} elseif (!\is_scalar($arg) || $this->dumpValue($arg) !== $this->dumpValue($arg, false)) {
return false;
}
}

View File

@ -111,7 +111,7 @@ class EnvVarProcessor implements EnvVarProcessorInterface
}
if ('file' === $prefix || 'require' === $prefix) {
if (!is_scalar($file = $getEnv($name))) {
if (!\is_scalar($file = $getEnv($name))) {
throw new RuntimeException(sprintf('Invalid file name: env var "%s" is non-scalar.', $name));
}
if (!file_exists($file)) {
@ -183,7 +183,7 @@ class EnvVarProcessor implements EnvVarProcessorInterface
return null;
}
if (!is_scalar($env)) {
if (!\is_scalar($env)) {
throw new RuntimeException(sprintf('Non-scalar env var "%s" cannot be cast to "%s".', $name, $prefix));
}
@ -280,7 +280,7 @@ class EnvVarProcessor implements EnvVarProcessorInterface
$value = $this->container->getParameter($match[1]);
}
if (!is_scalar($value)) {
if (!\is_scalar($value)) {
throw new RuntimeException(sprintf('Parameter "%s" found when resolving env var "%s" must be scalar, "%s" given.', $match[1], $name, \gettype($value)));
}

View File

@ -94,7 +94,7 @@ abstract class Extension implements ExtensionInterface, ConfigurationExtensionIn
if (!$class->implementsInterface(ConfigurationInterface::class)) {
@trigger_error(sprintf('Not implementing "%s" in the extension configuration class "%s" is deprecated since Symfony 4.1.', ConfigurationInterface::class, $class->getName()), \E_USER_DEPRECATED);
//throw new LogicException(sprintf('The extension configuration class "%s" must implement "%s".', $class->getName(), ConfigurationInterface::class));
// throw new LogicException(sprintf('The extension configuration class "%s" must implement "%s".', $class->getName(), ConfigurationInterface::class));
return null;
}

View File

@ -32,6 +32,11 @@ class ProxyHelper
return null;
}
return self::getTypeHintForType($type, $r, $noBuiltin);
}
private static function getTypeHintForType(\ReflectionType $type, \ReflectionFunctionAbstract $r, bool $noBuiltin): ?string
{
$types = [];
$glue = '|';
if ($type instanceof \ReflectionUnionType) {
@ -46,6 +51,17 @@ class ProxyHelper
}
foreach ($reflectionTypes as $type) {
if ($type instanceof \ReflectionIntersectionType) {
$typeHint = self::getTypeHintForType($type, $r, $noBuiltin);
if (null === $typeHint) {
return null;
}
$types[] = sprintf('(%s)', $typeHint);
continue;
}
if ($type->isBuiltin()) {
if (!$noBuiltin) {
$types[] = $type->getName();

View File

@ -82,7 +82,7 @@ abstract class AbstractConfigurator
switch (true) {
case null === $value:
case is_scalar($value):
case \is_scalar($value):
return $value;
case $value instanceof ArgumentInterface:

View File

@ -49,7 +49,7 @@ class DefaultsConfigurator extends AbstractServiceConfigurator
}
foreach ($attributes as $attribute => $value) {
if (null !== $value && !is_scalar($value)) {
if (null !== $value && !\is_scalar($value)) {
throw new InvalidArgumentException(sprintf('Tag "%s", attribute "%s" in "_defaults" must be of a scalar-type.', $name, $attribute));
}
}

View File

@ -27,7 +27,7 @@ trait TagTrait
}
foreach ($attributes as $attribute => $value) {
if (!is_scalar($value) && null !== $value) {
if (!\is_scalar($value) && null !== $value) {
throw new InvalidArgumentException(sprintf('A tag attribute must be of a scalar-type for service "%s", tag "%s", attribute "%s".', $this->id, $name, $attribute));
}
}

View File

@ -51,7 +51,7 @@ abstract class FileLoader extends BaseFileLoader
* @param bool|string $ignoreErrors Whether errors should be ignored; pass "not_found" to ignore only when the loaded resource is not found
* @param string|string[]|null $exclude Glob patterns to exclude from the import
*/
public function import($resource, $type = null, $ignoreErrors = false, $sourceResource = null/*, $exclude = null*/)
public function import($resource, $type = null, $ignoreErrors = false, $sourceResource = null/* , $exclude = null */)
{
$args = \func_get_args();

View File

@ -676,7 +676,7 @@ EOF
});
$schema = '<?xml version="1.0" encoding="utf-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:include schemaLocation="file:///'.str_replace('\\', '/', $tmpfile).'" />
<xsd:include schemaLocation="file:///'.rawurlencode(str_replace('\\', '/', $tmpfile)).'" />
</xsd:schema>';
file_put_contents($tmpfile, '<?xml version="1.0" encoding="utf-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">

View File

@ -277,7 +277,7 @@ class YamlFileLoader extends FileLoader
}
foreach ($tag as $attribute => $value) {
if (!is_scalar($value) && null !== $value) {
if (!\is_scalar($value) && null !== $value) {
throw new InvalidArgumentException(sprintf('Tag "%s", attribute "%s" in "_defaults" must be of a scalar-type in "%s". Check your YAML syntax.', $name, $attribute, $file));
}
}
@ -534,7 +534,7 @@ class YamlFileLoader extends FileLoader
}
foreach ($tag as $attribute => $value) {
if (!is_scalar($value) && null !== $value) {
if (!\is_scalar($value) && null !== $value) {
throw new InvalidArgumentException(sprintf('A "tags" attribute must be of a scalar-type for service "%s", tag "%s", attribute "%s" in "%s". Check your YAML syntax.', $id, $name, $attribute, $file));
}
}

View File

@ -51,10 +51,10 @@ class EnvPlaceholderParameterBag extends ParameterBag
if ($this->has($name)) {
$defaultValue = parent::get($name);
if (null !== $defaultValue && !is_scalar($defaultValue)) { // !is_string in 5.0
//throw new RuntimeException(sprintf('The default value of an env() parameter must be a string or null, but "%s" given to "%s".', \gettype($defaultValue), $name));
if (null !== $defaultValue && !\is_scalar($defaultValue)) { // !is_string in 5.0
// throw new RuntimeException(sprintf('The default value of an env() parameter must be a string or null, but "%s" given to "%s".', \gettype($defaultValue), $name));
throw new RuntimeException(sprintf('The default value of an env() parameter must be scalar or null, but "%s" given to "%s".', \gettype($defaultValue), $name));
} elseif (is_scalar($defaultValue) && !\is_string($defaultValue)) {
} elseif (\is_scalar($defaultValue) && !\is_string($defaultValue)) {
@trigger_error(sprintf('A non-string default value of an env() parameter is deprecated since 4.3, cast "%s" to string instead.', $name), \E_USER_DEPRECATED);
}
}
@ -162,10 +162,10 @@ class EnvPlaceholderParameterBag extends ParameterBag
@trigger_error(sprintf('A non-string default value of env parameter "%s" is deprecated since 4.3, cast it to string instead.', $env), \E_USER_DEPRECATED);
}
$this->parameters[$name] = (string) $default;
} elseif (null !== $default && !is_scalar($default)) { // !is_string in 5.0
//throw new RuntimeException(sprintf('The default value of env parameter "%s" must be a string or null, "%s" given.', $env, \gettype($default)));
} elseif (null !== $default && !\is_scalar($default)) { // !is_string in 5.0
// throw new RuntimeException(sprintf('The default value of env parameter "%s" must be a string or null, "%s" given.', $env, \gettype($default)));
throw new RuntimeException(sprintf('The default value of env parameter "%s" must be scalar or null, "%s" given.', $env, \gettype($default)));
} elseif (is_scalar($default) && !\is_string($default)) {
} elseif (\is_scalar($default) && !\is_string($default)) {
@trigger_error(sprintf('A non-string default value of env parameter "%s" is deprecated since 4.3, cast it to string instead.', $env), \E_USER_DEPRECATED);
}
}

View File

@ -53,7 +53,7 @@ class BufferingLogger extends AbstractLogger
foreach ($this->logs as [$level, $message, $context]) {
if (false !== strpos($message, '{')) {
foreach ($context as $key => $val) {
if (null === $val || is_scalar($val) || (\is_object($val) && \is_callable([$val, '__toString']))) {
if (null === $val || \is_scalar($val) || (\is_object($val) && \is_callable([$val, '__toString']))) {
$message = str_replace("{{$key}}", $val, $message);
} elseif ($val instanceof \DateTimeInterface) {
$message = str_replace("{{$key}}", $val->format(\DateTime::RFC3339), $message);

View File

@ -24,7 +24,7 @@ class Debug
if (!\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true)) {
ini_set('display_errors', 0);
} elseif (!filter_var(ini_get('log_errors'), \FILTER_VALIDATE_BOOLEAN) || ini_get('error_log')) {
} elseif (!filter_var(\ini_get('log_errors'), \FILTER_VALIDATE_BOOLEAN) || \ini_get('error_log')) {
// CLI - display errors only if they're not already logged to STDERR
ini_set('display_errors', 1);
}

View File

@ -70,6 +70,8 @@ class DebugClassLoader
'self' => 'self',
'parent' => 'parent',
'mixed' => 'mixed',
'list' => 'array',
'class-string' => 'string',
] + (\PHP_VERSION_ID >= 80000 ? [
'static' => 'static',
'$this' => 'static',

View File

@ -374,8 +374,8 @@ class ErrorHandler
*/
private function reRegister(int $prev): void
{
if ($prev !== $this->thrownErrors | $this->loggedErrors) {
$handler = set_error_handler('var_dump');
if ($prev !== ($this->thrownErrors | $this->loggedErrors)) {
$handler = set_error_handler('is_int');
$handler = \is_array($handler) ? $handler[0] : null;
restore_error_handler();
if ($handler === $this) {
@ -522,7 +522,7 @@ class ErrorHandler
$log = 0;
} else {
if (\PHP_VERSION_ID < (\PHP_VERSION_ID < 70400 ? 70316 : 70404)) {
$currentErrorHandler = set_error_handler('var_dump');
$currentErrorHandler = set_error_handler('is_int');
restore_error_handler();
}
@ -639,7 +639,7 @@ class ErrorHandler
$sameHandlerLimit = 10;
while (!\is_array($handler) || !$handler[0] instanceof self) {
$handler = set_exception_handler('var_dump');
$handler = set_exception_handler('is_int');
restore_exception_handler();
if (!$handler) {

View File

@ -56,8 +56,8 @@ class HtmlErrorRenderer implements ErrorRendererInterface
}
$this->debug = $debug;
$this->charset = $charset ?: (ini_get('default_charset') ?: 'UTF-8');
$this->fileLinkFormat = $fileLinkFormat ?: (ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format'));
$this->charset = $charset ?: (\ini_get('default_charset') ?: 'UTF-8');
$this->fileLinkFormat = $fileLinkFormat ?: (\ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format'));
$this->projectDir = $projectDir;
$this->outputBuffer = $outputBuffer;
$this->logger = $logger;
@ -319,7 +319,7 @@ class HtmlErrorRenderer implements ErrorRendererInterface
if ($context && false !== strpos($message, '{')) {
$replacements = [];
foreach ($context as $key => $val) {
if (is_scalar($val)) {
if (\is_scalar($val)) {
$replacements['{'.$key.'}'] = $val;
}
}

View File

@ -133,7 +133,7 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface
*
* @param string|null $eventName
*/
public function dispatch($event/*, string $eventName = null*/)
public function dispatch($event/* , string $eventName = null */)
{
if (null === $this->callStack) {
$this->callStack = new \SplObjectStorage();

View File

@ -48,7 +48,7 @@ class EventDispatcher implements EventDispatcherInterface
*
* @param string|null $eventName
*/
public function dispatch($event/*, string $eventName = null*/)
public function dispatch($event/* , string $eventName = null */)
{
$eventName = 1 < \func_num_args() ? func_get_arg(1) : null;

View File

@ -30,11 +30,11 @@ class ImmutableEventDispatcher implements EventDispatcherInterface
*
* @param string|null $eventName
*/
public function dispatch($event/*, string $eventName = null*/)
public function dispatch($event/* , string $eventName = null */)
{
$eventName = 1 < \func_num_args() ? func_get_arg(1) : null;
if (is_scalar($event)) {
if (\is_scalar($event)) {
// deprecated
$swap = $event;
$event = $eventName ?? new Event();

View File

@ -53,7 +53,7 @@ final class LegacyEventDispatcherProxy implements EventDispatcherInterface
*
* @return object
*/
public function dispatch($event/*, string $eventName = null*/)
public function dispatch($event/* , string $eventName = null */)
{
$eventName = 1 < \func_num_args() ? func_get_arg(1) : null;

View File

@ -34,6 +34,7 @@ class BinaryFileResponse extends Response
protected $offset = 0;
protected $maxlen = -1;
protected $deleteFileAfterSend = false;
protected $chunkSize = 8 * 1024;
/**
* @param \SplFileInfo|string $file The file to stream
@ -124,6 +125,22 @@ class BinaryFileResponse extends Response
return $this->file;
}
/**
* Sets the response stream chunk size.
*
* @return $this
*/
public function setChunkSize(int $chunkSize): self
{
if ($chunkSize < 1 || $chunkSize > \PHP_INT_MAX) {
throw new \LogicException('The chunk size of a BinaryFileResponse cannot be less than 1 or greater than PHP_INT_MAX.');
}
$this->chunkSize = $chunkSize;
return $this;
}
/**
* Automatically sets the Last-Modified header according the file modification date.
*/
@ -184,22 +201,25 @@ class BinaryFileResponse extends Response
*/
public function prepare(Request $request)
{
parent::prepare($request);
if ($this->isInformational() || $this->isEmpty()) {
$this->maxlen = 0;
return $this;
}
if (!$this->headers->has('Content-Type')) {
$this->headers->set('Content-Type', $this->file->getMimeType() ?: 'application/octet-stream');
}
if ('HTTP/1.0' !== $request->server->get('SERVER_PROTOCOL')) {
$this->setProtocolVersion('1.1');
}
$this->ensureIEOverSSLCompatibility($request);
$this->offset = 0;
$this->maxlen = -1;
if (false === $fileSize = $this->file->getSize()) {
return $this;
}
$this->headers->remove('Transfer-Encoding');
$this->headers->set('Content-Length', $fileSize);
if (!$this->headers->has('Accept-Ranges')) {
@ -269,6 +289,10 @@ class BinaryFileResponse extends Response
}
}
if ($request->isMethod('HEAD')) {
$this->maxlen = 0;
}
return $this;
}
@ -292,24 +316,42 @@ class BinaryFileResponse extends Response
*/
public function sendContent()
{
if (!$this->isSuccessful()) {
return parent::sendContent();
}
try {
if (!$this->isSuccessful()) {
return parent::sendContent();
}
if (0 === $this->maxlen) {
return $this;
}
if (0 === $this->maxlen) {
return $this;
}
$out = fopen('php://output', 'w');
$file = fopen($this->file->getPathname(), 'r');
$out = fopen('php://output', 'w');
$file = fopen($this->file->getPathname(), 'r');
stream_copy_to_stream($file, $out, $this->maxlen, $this->offset);
ignore_user_abort(true);
fclose($out);
fclose($file);
if (0 !== $this->offset) {
fseek($file, $this->offset);
}
if ($this->deleteFileAfterSend && file_exists($this->file->getPathname())) {
unlink($this->file->getPathname());
$length = $this->maxlen;
while ($length && !feof($file)) {
$read = ($length > $this->chunkSize) ? $this->chunkSize : $length;
$length -= $read;
stream_copy_to_stream($file, $out, $read);
if (connection_aborted()) {
break;
}
}
fclose($out);
fclose($file);
} finally {
if ($this->deleteFileAfterSend && file_exists($this->file->getPathname())) {
unlink($this->file->getPathname());
}
}
return $this;

View File

@ -243,8 +243,8 @@ class UploadedFile extends File
*/
public static function getMaxFilesize()
{
$sizePostMax = self::parseFilesize(ini_get('post_max_size'));
$sizeUploadMax = self::parseFilesize(ini_get('upload_max_filesize'));
$sizePostMax = self::parseFilesize(\ini_get('post_max_size'));
$sizeUploadMax = self::parseFilesize(\ini_get('upload_max_filesize'));
return min($sizePostMax ?: \PHP_INT_MAX, $sizeUploadMax ?: \PHP_INT_MAX);
}
@ -273,8 +273,11 @@ class UploadedFile extends File
switch (substr($size, -1)) {
case 't': $max *= 1024;
// no break
case 'g': $max *= 1024;
// no break
case 'm': $max *= 1024;
// no break
case 'k': $max *= 1024;
}

View File

@ -62,7 +62,7 @@ class HeaderBag implements \IteratorAggregate, \Countable
*
* @return array An array of headers
*/
public function all(/*string $key = null*/)
public function all(/* string $key = null */)
{
if (1 <= \func_num_args() && null !== $key = func_get_arg(0)) {
return $this->headers[strtr($key, self::UPPER, self::LOWER)] ?? [];

View File

@ -551,7 +551,7 @@ class Request
$request = ['g' => $_GET, 'p' => $_POST, 'c' => $_COOKIE];
$requestOrder = ini_get('request_order') ?: ini_get('variables_order');
$requestOrder = \ini_get('request_order') ?: \ini_get('variables_order');
$requestOrder = preg_replace('#[^cgp]#', '', strtolower($requestOrder)) ?: 'gp';
$_REQUEST = [[]];
@ -1646,7 +1646,8 @@ class Request
$languages = AcceptHeader::fromString($this->headers->get('Accept-Language'))->all();
$this->languages = [];
foreach ($languages as $lang => $acceptHeaderItem) {
foreach ($languages as $acceptHeaderItem) {
$lang = $acceptHeaderItem->getValue();
if (str_contains($lang, '-')) {
$codes = explode('-', $lang);
if ('i' === $codes[0]) {
@ -1684,7 +1685,7 @@ class Request
return $this->charsets;
}
return $this->charsets = array_keys(AcceptHeader::fromString($this->headers->get('Accept-Charset'))->all());
return $this->charsets = array_map('strval', array_keys(AcceptHeader::fromString($this->headers->get('Accept-Charset'))->all()));
}
/**
@ -1698,7 +1699,7 @@ class Request
return $this->encodings;
}
return $this->encodings = array_keys(AcceptHeader::fromString($this->headers->get('Accept-Encoding'))->all());
return $this->encodings = array_map('strval', array_keys(AcceptHeader::fromString($this->headers->get('Accept-Encoding'))->all()));
}
/**
@ -1712,7 +1713,7 @@ class Request
return $this->acceptableContentTypes;
}
return $this->acceptableContentTypes = array_keys(AcceptHeader::fromString($this->headers->get('Accept'))->all());
return $this->acceptableContentTypes = array_map('strval', array_keys(AcceptHeader::fromString($this->headers->get('Accept'))->all()));
}
/**

View File

@ -77,7 +77,7 @@ class Response
public const HTTP_PRECONDITION_REQUIRED = 428; // RFC6585
public const HTTP_TOO_MANY_REQUESTS = 429; // RFC6585
public const HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE = 431; // RFC6585
public const HTTP_UNAVAILABLE_FOR_LEGAL_REASONS = 451;
public const HTTP_UNAVAILABLE_FOR_LEGAL_REASONS = 451; // RFC7725
public const HTTP_INTERNAL_SERVER_ERROR = 500;
public const HTTP_NOT_IMPLEMENTED = 501;
public const HTTP_BAD_GATEWAY = 502;
@ -384,6 +384,7 @@ class Response
fastcgi_finish_request();
} elseif (!\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true)) {
static::closeOutputBuffers(0, true);
flush();
}
return $this;

View File

@ -90,7 +90,7 @@ class ResponseHeaderBag extends HeaderBag
*
* @param string|null $key The name of the headers to return or null to get them all
*/
public function all(/*string $key = null*/)
public function all(/* string $key = null */)
{
$headers = parent::all();
@ -254,7 +254,7 @@ class ResponseHeaderBag extends HeaderBag
* @param bool $httpOnly
* @param string $sameSite
*/
public function clearCookie($name, $path = '/', $domain = null, $secure = false, $httpOnly = true/*, $sameSite = null*/)
public function clearCookie($name, $path = '/', $domain = null, $secure = false, $httpOnly = true/* , $sameSite = null */)
{
$sameSite = \func_num_args() > 5 ? func_get_arg(5) : null;

View File

@ -35,8 +35,8 @@ abstract class AbstractSessionHandler implements \SessionHandlerInterface, \Sess
public function open($savePath, $sessionName)
{
$this->sessionName = $sessionName;
if (!headers_sent() && !ini_get('session.cache_limiter') && '0' !== ini_get('session.cache_limiter')) {
header(sprintf('Cache-Control: max-age=%d, private, must-revalidate', 60 * (int) ini_get('session.cache_expire')));
if (!headers_sent() && !\ini_get('session.cache_limiter') && '0' !== \ini_get('session.cache_limiter')) {
header(sprintf('Cache-Control: max-age=%d, private, must-revalidate', 60 * (int) \ini_get('session.cache_expire')));
}
return true;
@ -133,7 +133,7 @@ abstract class AbstractSessionHandler implements \SessionHandlerInterface, \Sess
#[\ReturnTypeWillChange]
public function destroy($sessionId)
{
if (!headers_sent() && filter_var(ini_get('session.use_cookies'), \FILTER_VALIDATE_BOOLEAN)) {
if (!headers_sent() && filter_var(\ini_get('session.use_cookies'), \FILTER_VALIDATE_BOOLEAN)) {
if (!$this->sessionName) {
throw new \LogicException(sprintf('Session name cannot be empty, did you forget to call "parent::open()" in "%s"?.', static::class));
}
@ -148,7 +148,7 @@ abstract class AbstractSessionHandler implements \SessionHandlerInterface, \Sess
*/
if (null === $cookie || isset($_COOKIE[$this->sessionName])) {
if (\PHP_VERSION_ID < 70300) {
setcookie($this->sessionName, '', 0, ini_get('session.cookie_path'), ini_get('session.cookie_domain'), filter_var(ini_get('session.cookie_secure'), \FILTER_VALIDATE_BOOLEAN), filter_var(ini_get('session.cookie_httponly'), \FILTER_VALIDATE_BOOLEAN));
setcookie($this->sessionName, '', 0, \ini_get('session.cookie_path'), \ini_get('session.cookie_domain'), filter_var(\ini_get('session.cookie_secure'), \FILTER_VALIDATE_BOOLEAN), filter_var(\ini_get('session.cookie_httponly'), \FILTER_VALIDATE_BOOLEAN));
} else {
$params = session_get_cookie_params();
unset($params['lifetime']);

View File

@ -116,7 +116,7 @@ class MongoDbSessionHandler extends AbstractSessionHandler
*/
protected function doWrite($sessionId, $data)
{
$expiry = new \MongoDB\BSON\UTCDateTime((time() + (int) ini_get('session.gc_maxlifetime')) * 1000);
$expiry = new \MongoDB\BSON\UTCDateTime((time() + (int) \ini_get('session.gc_maxlifetime')) * 1000);
$fields = [
$this->options['time_field'] => new \MongoDB\BSON\UTCDateTime(),
@ -139,7 +139,7 @@ class MongoDbSessionHandler extends AbstractSessionHandler
#[\ReturnTypeWillChange]
public function updateTimestamp($sessionId, $data)
{
$expiry = new \MongoDB\BSON\UTCDateTime((time() + (int) ini_get('session.gc_maxlifetime')) * 1000);
$expiry = new \MongoDB\BSON\UTCDateTime((time() + (int) \ini_get('session.gc_maxlifetime')) * 1000);
$this->getCollection()->updateOne(
[$this->options['id_field'] => $sessionId],

View File

@ -31,7 +31,7 @@ class NativeFileSessionHandler extends \SessionHandler
public function __construct(string $savePath = null)
{
if (null === $savePath) {
$savePath = ini_get('session.save_path');
$savePath = \ini_get('session.save_path');
}
$baseDir = $savePath;

View File

@ -328,7 +328,7 @@ class PdoSessionHandler extends AbstractSessionHandler
*/
protected function doWrite($sessionId, $data)
{
$maxlifetime = (int) ini_get('session.gc_maxlifetime');
$maxlifetime = (int) \ini_get('session.gc_maxlifetime');
try {
// We use a single MERGE SQL query when supported by the database.
@ -375,7 +375,7 @@ class PdoSessionHandler extends AbstractSessionHandler
#[\ReturnTypeWillChange]
public function updateTimestamp($sessionId, $data)
{
$expiry = time() + (int) ini_get('session.gc_maxlifetime');
$expiry = time() + (int) \ini_get('session.gc_maxlifetime');
try {
$updateStmt = $this->pdo->prepare(
@ -650,7 +650,7 @@ class PdoSessionHandler extends AbstractSessionHandler
throw new \RuntimeException('Failed to read session: INSERT reported a duplicate id but next SELECT did not return any data.');
}
if (!filter_var(ini_get('session.use_strict_mode'), \FILTER_VALIDATE_BOOLEAN) && self::LOCK_TRANSACTIONAL === $this->lockMode && 'sqlite' !== $this->driver) {
if (!filter_var(\ini_get('session.use_strict_mode'), \FILTER_VALIDATE_BOOLEAN) && self::LOCK_TRANSACTIONAL === $this->lockMode && 'sqlite' !== $this->driver) {
// In strict mode, session fixation is not possible: new sessions always start with a unique
// random id, so that concurrency is not possible and this code path can be skipped.
// Exclusive-reading of non-existent rows does not block, so we need to do an insert to block
@ -898,7 +898,7 @@ class PdoSessionHandler extends AbstractSessionHandler
protected function getConnection()
{
if (null === $this->pdo) {
$this->connect($this->dsn ?: ini_get('session.save_path'));
$this->connect($this->dsn ?: \ini_get('session.save_path'));
}
return $this->pdo;

View File

@ -79,7 +79,7 @@ class RedisSessionHandler extends AbstractSessionHandler
*/
protected function doWrite($sessionId, $data): bool
{
$result = $this->redis->setEx($this->prefix.$sessionId, (int) ($this->ttl ?? ini_get('session.gc_maxlifetime')), $data);
$result = $this->redis->setEx($this->prefix.$sessionId, (int) ($this->ttl ?? \ini_get('session.gc_maxlifetime')), $data);
return $result && !$result instanceof ErrorInterface;
}
@ -120,6 +120,6 @@ class RedisSessionHandler extends AbstractSessionHandler
#[\ReturnTypeWillChange]
public function updateTimestamp($sessionId, $data)
{
return (bool) $this->redis->expire($this->prefix.$sessionId, (int) ($this->ttl ?? ini_get('session.gc_maxlifetime')));
return (bool) $this->redis->expire($this->prefix.$sessionId, (int) ($this->ttl ?? \ini_get('session.gc_maxlifetime')));
}
}

View File

@ -30,6 +30,16 @@ class StrictSessionHandler extends AbstractSessionHandler
$this->handler = $handler;
}
/**
* Returns true if this handler wraps an internal PHP session save handler using \SessionHandler.
*
* @internal
*/
public function isWrapper(): bool
{
return $this->handler instanceof \SessionHandler;
}
/**
* @return bool
*/

View File

@ -163,6 +163,6 @@ class MetadataBag implements SessionBagInterface
{
$timeStamp = time();
$this->meta[self::CREATED] = $this->meta[self::UPDATED] = $this->lastUsed = $timeStamp;
$this->meta[self::LIFETIME] = $lifetime ?? (int) ini_get('session.cookie_lifetime');
$this->meta[self::LIFETIME] = $lifetime ?? (int) \ini_get('session.cookie_lifetime');
}
}

View File

@ -148,12 +148,42 @@ class NativeSessionStorage implements SessionStorageInterface
throw new \RuntimeException('Failed to start the session: already started by PHP.');
}
if (filter_var(ini_get('session.use_cookies'), \FILTER_VALIDATE_BOOLEAN) && headers_sent($file, $line)) {
if (filter_var(\ini_get('session.use_cookies'), \FILTER_VALIDATE_BOOLEAN) && headers_sent($file, $line)) {
throw new \RuntimeException(sprintf('Failed to start the session because headers have already been sent by "%s" at line %d.', $file, $line));
}
$sessionId = $_COOKIE[session_name()] ?? null;
if ($sessionId && $this->saveHandler instanceof AbstractProxy && 'files' === $this->saveHandler->getSaveHandlerName() && !preg_match('/^[a-zA-Z0-9,-]{22,}$/', $sessionId)) {
/*
* Explanation of the session ID regular expression: `/^[a-zA-Z0-9,-]{22,250}$/`.
*
* ---------- Part 1
*
* The part `[a-zA-Z0-9,-]` is related to the PHP ini directive `session.sid_bits_per_character` defined as 6.
* See https://www.php.net/manual/en/session.configuration.php#ini.session.sid-bits-per-character.
* Allowed values are integers such as:
* - 4 for range `a-f0-9`
* - 5 for range `a-v0-9`
* - 6 for range `a-zA-Z0-9,-`
*
* ---------- Part 2
*
* The part `{22,250}` is related to the PHP ini directive `session.sid_length`.
* See https://www.php.net/manual/en/session.configuration.php#ini.session.sid-length.
* Allowed values are integers between 22 and 256, but we use 250 for the max.
*
* Where does the 250 come from?
* - The length of Windows and Linux filenames is limited to 255 bytes. Then the max must not exceed 255.
* - The session filename prefix is `sess_`, a 5 bytes string. Then the max must not exceed 255 - 5 = 250.
*
* ---------- Conclusion
*
* The parts 1 and 2 prevent the warning below:
* `PHP Warning: SessionHandler::read(): Session ID is too long or contains illegal characters. Only the A-Z, a-z, 0-9, "-", and "," characters are allowed.`
*
* The part 2 prevents the warning below:
* `PHP Warning: SessionHandler::read(): open(filepath, O_RDWR) failed: No such file or directory (2).`
*/
if ($sessionId && $this->saveHandler instanceof AbstractProxy && 'files' === $this->saveHandler->getSaveHandlerName() && !preg_match('/^[a-zA-Z0-9,-]{22,250}$/', $sessionId)) {
// the session ID in the header is invalid, create a new one
session_id(session_create_id());
}
@ -221,7 +251,7 @@ class NativeSessionStorage implements SessionStorageInterface
return false;
}
if (null !== $lifetime && $lifetime != ini_get('session.cookie_lifetime')) {
if (null !== $lifetime && $lifetime != \ini_get('session.cookie_lifetime')) {
$this->save();
ini_set('session.cookie_lifetime', $lifetime);
$this->start();
@ -256,7 +286,7 @@ class NativeSessionStorage implements SessionStorageInterface
unset($_SESSION[$key]);
}
}
if ([$key = $this->metadataBag->getStorageKey()] === array_keys($_SESSION)) {
if ($_SESSION && [$key = $this->metadataBag->getStorageKey()] === array_keys($_SESSION)) {
unset($_SESSION[$key]);
}

View File

@ -11,6 +11,8 @@
namespace Symfony\Component\HttpFoundation\Session\Storage\Proxy;
use Symfony\Component\HttpFoundation\Session\Storage\Handler\StrictSessionHandler;
/**
* @author Drak <drak@zikula.org>
*/
@ -22,7 +24,7 @@ class SessionHandlerProxy extends AbstractProxy implements \SessionHandlerInterf
{
$this->handler = $handler;
$this->wrapper = $handler instanceof \SessionHandler;
$this->saveHandlerName = $this->wrapper ? ini_get('session.save_handler') : 'user';
$this->saveHandlerName = $this->wrapper || ($handler instanceof StrictSessionHandler && $handler->isWrapper()) ? \ini_get('session.save_handler') : 'user';
}
/**

View File

@ -28,7 +28,7 @@ class FileLocator extends BaseFileLocator
*/
private $path;
public function __construct(KernelInterface $kernel/*, string $path = null, array $paths = [], bool $triggerDeprecation = true*/)
public function __construct(KernelInterface $kernel/* , string $path = null, array $paths = [], bool $triggerDeprecation = true */)
{
$this->kernel = $kernel;

View File

@ -28,7 +28,7 @@ class AjaxDataCollector extends DataCollector
*
* @param \Throwable|null $exception
*/
public function collect(Request $request, Response $response/*, \Throwable $exception = null*/)
public function collect(Request $request, Response $response/* , \Throwable $exception = null */)
{
// all collecting is done client side
}

View File

@ -57,7 +57,7 @@ class ConfigDataCollector extends DataCollector implements LateDataCollectorInte
*
* @param \Throwable|null $exception
*/
public function collect(Request $request, Response $response/*, \Throwable $exception = null*/)
public function collect(Request $request, Response $response/* , \Throwable $exception = null */)
{
$eom = \DateTime::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_MAINTENANCE);
$eol = \DateTime::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_LIFE);
@ -79,8 +79,8 @@ class ConfigDataCollector extends DataCollector implements LateDataCollectorInte
'php_intl_locale' => class_exists(\Locale::class, false) && \Locale::getDefault() ? \Locale::getDefault() : 'n/a',
'php_timezone' => date_default_timezone_get(),
'xdebug_enabled' => \extension_loaded('xdebug'),
'apcu_enabled' => \extension_loaded('apcu') && filter_var(ini_get('apc.enabled'), \FILTER_VALIDATE_BOOLEAN),
'zend_opcache_enabled' => \extension_loaded('Zend OPcache') && filter_var(ini_get('opcache.enable'), \FILTER_VALIDATE_BOOLEAN),
'apcu_enabled' => \extension_loaded('apcu') && filter_var(\ini_get('apc.enabled'), \FILTER_VALIDATE_BOOLEAN),
'zend_opcache_enabled' => \extension_loaded('Zend OPcache') && filter_var(\ini_get('opcache.enable'), \FILTER_VALIDATE_BOOLEAN),
'bundles' => [],
'sapi_name' => \PHP_SAPI,
];

Some files were not shown because too many files have changed in this diff Show More