Kako postaviti pametne telefone i računala. Informativni portal
  • Dom
  • Windows 7, XP
  • Uklanjanje označenih objekata, zamjena veza. Uobičajena i upravljana aplikacija

Uklanjanje označenih objekata, zamjena veza. Uobičajena i upravljana aplikacija

U posljednje vrijeme bilo je puno članaka o nedostacima Bitrixa i njihovim opovrgavanjima. Budući da se piće ovako nastavilo, ja ću dodati svojih 5 centi.
U komentarima na članke napisali su da nedostaje konkretnosti, primjera i dubljeg osvrta.

Ovaj članak je pokušaj pisanja ove recenzije. Iako ne, ovo je više post mržnje i boli (možda čak i malo kukanja). Ovo je proširena verzija posta o nedostacima pištolja. Pokušat ću opisati većinu stvari koje iritiraju mene i moje kolege u Bitrixu. Pokušat ću u jednom postu sabrati sve one nedostatke koji svakodnevno uzrokuju mnogo boli. Na kraju ću pokušati izvući zaključke.

Tko sam ja? Da, općenito, običan programer. S Bitrixom radim od studenog 2010. (5,5 godina). radim samo s Bitrixom, nije napravio niti jedan komercijalni projekt koristeći drugi CMS, nije koristio okvire za izradu web stranica. Po djelatnostima se uglavnom bavim internet trgovinama, njihovom izradom, podrškom i razvojem.

TL;DR

Bitrix - UG, ne biste trebali ulaziti u ovaj bazen osim ako je to apsolutno neophodno.

Umjesto uvoda

Za početak predlažem da provedete misaoni eksperiment. Pokušajmo uzeti dva backend developera približno iste dobi i s približno istim radnim iskustvom (recimo 1 - 1,5 godina), samo tako da je jedan od njih sve ovo vrijeme radio s 1C-Bitrixom, a drugi sa Symfonyjem ( na primjer). Lako možete usporediti s kojim skupom tehnologija je jedan radio sve ovo vrijeme, a s kojim je drugi radio, i koji su skup znanja na kraju primili tijekom tog vremena.

U slučaju Symfony programera, to će biti: php5/7 + duboko razumijevanje OOP-a, općeprihvaćeni obrasci dizajna (barem MVC, DI, Factory, Repository), sposobnost razvoja jediničnih testova, korištenje predložaka (barem twig ), ORM (s Doctrine), skladatelj, git, PSR standardi, iskustvo u radu s konzolom i pisanjem konzolnih aplikacija, osnovne vještine postavljanja web servera.

U slučaju 1C-Bitrix programera, to će biti php5, html/css + javascript/jquery (nema predložaka izvan kutije, a Bitrix stavlja logiku u predloške, što god netko rekao, morat ćete petljaj s tim), možda git (a to uvelike ovisi o tvrtki, neki dinosauri još pile u proizvodnji preko FTP-a), ako imaš sreće - malo sql-a i... to je sve?

Shvaćam da je sve ovo vrlo individualno i da okolina osobe može igrati vrlo važnu ulogu. Ali ovdje govorim o onome što je razvojni programer sustava prisiljen učiniti odmah. U većini slučajeva, Bitrix programer je znatno inferioran u vještinama u usporedbi s programerima za druge okvire/CMS - a to je neosporna činjenica. A sve zato što Bitrix u startu daje previše slobode u nedostatku jasne arhitekture, dokumentacije i ispravnih rješenja, dok Symfony nudi sve što trebate.

Samo jednom je u našu tvrtku došla iskusna osoba koja nije iz svijeta 1C-Bitrixa (u regiji) i bila je za glavu iznad svojih kolega s istim iskustvom, jednostavno zbog činjenice da je prethodno bio stavljen na prava traka.
I sama sam takva. Nažalost, od samog početka sam bio prevaren istim marketinškim besmislicama, te sam završio u ne baš dobrom okruženju. I sam razumijem i osjećam da moji kolege sa sličnim radnim iskustvom, ali u istom Symfonyju, imaju širi pogled, a to je vrlo jaka nuspojava Bitrixa.
Sve ovo sugerira da ako se želite razvijati u svijetu web developmenta, onda definitivno ne biste trebali odabrati Bitrix kao osnovu.

Uspoređujući ova dva programera, želim skrenuti pozornost na okvir u koji nas sustav tjera i slobodu koju pruža. I Bitrix i Symfony - oba pružaju gotovo neograničenu fleksibilnost, au načelu, na svakom od njih možete stvoriti proizvod apsolutno bilo koje složenosti. Međutim, sustav bi trebao pomoći razvojnom programeru u rješavanju problema, umjesto da stavlja žbice u kotače. I ovdje Bitrix jako gubi.

Marketing

Želim odmah reći nekoliko riječi o ovome, jer... ovo je glavna komponenta uspjeha Bitrixa.
Možemo reći da je cijeli Bitrix, pa i dokumentacija za programere, prožet duhom marketinga. Čak i tamo pišu da je njihov proizvod "toliko cool da ga svi naši partneri cijene i poštuju" (dokaz, blok "Struktura"). Bitrix zapošljava dobre marketinške stručnjake koji kompetentno znaju prezentirati svoj proizvod. Svakih šest mjeseci organiziraju konferencije za partnere na kojima govore o učinjenom i koji su im planovi. Kao što pokazuje praksa, ti se planovi nikada ne ostvaruju na vrijeme i vrlo su često izdanja ili nepotpuna ili puna pogrešaka.
Kao primjer, senzacionalno refaktoriranje prodajnog modula, čije je puštanje u promet kasnilo više od godinu dana, a čak je i posljednji datum puštanja u promet (23. prosinca 2015.) kasnio za 3 mjeseca, te nova trgovina i BUS (Bitrix izd. “Site Management”) verzija 16 objavljena je tek krajem ožujka 2016. Ali kao rezultat toga, nakon ažuriranja korisnici ne samo da nisu dobili nove značajke. Korisnici su dobili uglavnom neoperabilnu trgovinu i hrpu novog nedokumentiranog koda za pokretanje.
Novi alati dobivaju tako glasna imena koja svi znaju: Kompozitno mjesto - x100 ubrzanje; Blokovi visokog opterećenja; Bitrix BigData. Zapravo, te riječi kriju sasvim obične stvari koje ne opravdavaju svoj naziv.
A ovakav pristup se, nažalost, može vidjeti posvuda. Izvana proizvod izgleda kao slatkiš koji ste kupili, instalirali i koristili. Ali ako se odmaknete od standardne isporuke s Bitrixom - to je to, održavanje funkcionalnosti tijekom ažuriranja pretvara se u pakao.
Međutim, najprije, tema marketinga najvjerojatnije će se više puta pojaviti u ovom postu.

Arhitektura

Deset godina Bitrix se očajnički zaveo u slijepu ulicu. Svaka nova značajka u proizvodu objavljena je u skladu s interesima poslovanja, bez odgovarajućeg razvoja s tehničkog gledišta. I, naravno, sve je to raslo kao gruda snijega.
Ako bolje razmislite, Bitrix nema arhitekturu kao takvu. Ne postoje čak ni općeprihvaćena, formulirana pravila koja bi omogućila da se slijedi ovakva arhitektura. U tečaju za programere, u odjeljku Arhitektura proizvoda, kaže se da Bitrix slijedi MVC arhitekturu i daje dijagram:

Želim odmah reći da se ovaj MVC jako razlikuje od klasične verzije. Ovdje postoji vrlo jaka zamjena koncepata, ovdje zapravo nema MVC-a, jednostavno postoji nekakva apstraktna podjela na module, komponente i predloške komponenti. I cijelo je mjesto izgrađeno od ovih cigli. Ali svaka od ovih cigli može preuzeti različite zadatke, pa su stoga međusobno usko povezane.
Pokušat ću detaljnije pogledati svaki od ovih aspekata arhitekture.

M - Model, ili API

Teško mi je procijeniti API sustava kao model. Da, API pruža sučelje za pristup podacima i omogućuje vam da njima upravljate. Ali Bitrix API omogućuje vam rad ne samo s podacima, već i s predlošcima, kao i sa zahtjevima korisnika. Pa dobro... to je samo moje mišljenje.
Trenutno Bitrix ima 2 API opcije. Konvencionalno se mogu podijeliti na star I novi. Novi API zove se D7 (iskreno, ne sjećam se zašto, ali Rizhikov je govorio o tome na jednoj od partnerskih konferencija).

Stari API zbirka je antišablona, ​​užasnih primjera lošeg koda. U Bitrixu se oduvijek smatralo normalnim statički pozivati ​​nestatičke metode i obrnuto, zahtijevati stanje kada je to neprikladno. Na primjer, dobro poznati CIBlockElement::GetList je možda jedna od najčešće korištenih metoda u razvoju. Njegova implementacija sadrži više od 500 redaka koda, koristi globale, gradi zastrašujuće, kolosalne upite i sadrži nerealan, jednostavno nečitljiv, nedokumentirani kod.

Pogledajmo

Funkcija GetList($arOrder=array("SORT"=>"ASC"), $arFilter=array(), $arGroupBy=false, $arNavStartParams=false, $arSelectFields=array()) ( /* Kombinacije filtara: CHECK_PERMISSIONS= "N" - provjeri dopuštenja trenutnog korisnika za infoblok MIN_PERMISSION="R" - kada se provjere dopuštenja, onda minimalna razina pristupa SHOW_HISTORY="N" - dodaj stavke povijesti na popis SHOW_NEW="N" - ako ne dodaj stavke povijesti, zatim dodajte nove, ali ne i objavljene elemente */ global $DB, $USER; $MAX_LOCK = intval(COption::GetOptionString("workflow","MAX_LOCK_TIME","60")); $uid = is_object($USER)? intval($USER->GetID()): 0; $formatActiveDates = CPageOption::GetOptionString("iblock", "FORMAT_ACTIVE_DATES", "-") != "-"; $shortFormatActiveDates = CPageOption::GetOptionString("iblock" , "FORMAT_ACTIVE_DATES", "SHORT"); $arIblockElementFields = array("ID"=>"BE.ID", "TIMESTAMP_X"=>$DB->DateToCharFunction("BE.TIMESTAMP_X"), "TIMESTAMP_X_UNIX"=>" UNIX_TIMESTAMP(BE.TIMESTAMP_X)", "MODIFIED_BY"=>"BE.MODIFIED_BY", "DATE_CREATE"=>$DB->DateToCharFunction("BE.DATE_CREATE"), "DATE_CREATE_UNIX"=>"UNIX_TIMESTAMP(BE.DATE_CREATE)" , "CREATED_BY"=>"BE.CREATED_BY", "IBLOCK_ID"=>"BE.IBLOCK_ID", "IBLOCK_SECTION_ID"=>"BE.IBLOCK_SECTION_ID", "ACTIVE"=>"BE.ACTIVE", "ACTIVE_FROM"=> ($formatActiveDates ? $DB->DateToCharFunction("BE.ACTIVE_FROM", $shortFormatActiveDates) : "IF(EXTRACT(HOUR_SECOND FROM BE.ACTIVE_FROM)>0, ".$DB->DateToCharFunction("BE.ACTIVE_FROM", "FULL")." , ".$DB->DateToCharFunction("BE.ACTIVE_FROM", "SHORT").")"), "ACTIVE_TO"=>($formatActiveDates ? $DB->DateToCharFunction("BE.ACTIVE_TO", $shortFormatActiveDates) : "IF(EXTRACT(HOUR_SECOND FROM BE.ACTIVE_TO)>0, ".$DB->DateToCharFunction("BE.ACTIVE_TO", "FULL").", ".$DB->DateToCharFunction("BE.ACTIVE_TO", " SHORT").")"), "DATE_ACTIVE_FROM"=>($formatActiveDates ? $DB->DateToCharFunction("BE.ACTIVE_FROM", $shortFormatActiveDates) : "IF(EXTRACT(HOUR_SECOND FROM BE.ACTIVE_FROM)>0, ". $DB->DateToCharFunction("BE.ACTIVE_FROM", "FULL").", ".$DB->DateToCharFunction("BE.ACTIVE_FROM", "SHORT").")"), "DATE_ACTIVE_TO"=>($ formatActiveDates ? $DB->DateToCharFunction("BE.ACTIVE_TO", $shortFormatActiveDates) : "IF(EXTRACT(HOUR_SECOND FROM BE.ACTIVE_TO)>0, ".$DB->DateToCharFunction("BE.ACTIVE_TO", "FULL") .", ".$DB->DateToCharFunction("BE.ACTIVE_TO", "SHORT").")"), "SORT"=>"BE.SORT", "NAME"=>"BE.NAME", " PREVIEW_PICTURE"=>"BE.PREVIEW_PICTURE", "PREVIEW_TEXT"=>"BE.PREVIEW_TEXT", "PREVIEW_TEXT_TYPE"=>"BE.PREVIEW_TEXT_TYPE", "DETAIL_PICTURE"=>"BE. DETAIL_PICTURE", "DETAIL_TEXT"=>"BE.DETAIL_TEXT", "DETAIL_TEXT_TYPE"=>"BE.DETAIL_TEXT_TYPE", "SEARCHABLE_CONTENT"=>"BE.SEARCHABLE_CONTENT", "WF_STATUS_ID"=>"BE.WF_STATUS_ID", "WF_PARENT_ELEMENT_ID" =>"BE.WF_PARENT_ELEMENT_ID", "WF_LAST_HISTORY_ID"=>"BE.WF_LAST_HISTORY_ID", "WF_NEW"=>"BE.WF_NEW", "LOCK_STATUS"=>"if (BE.WF_DATE_LOCK je null, "zeleno", if( DATE_ADD(BE.WF_DATE_LOCK, interval ".$MAX_LOCK." MINUTE) "BE.WF_LOCKED_BY", "WF_DATE_LOCK"=>$DB->DateToCharFunction("BE.WF_DATE_LOCK"), "WF_COMMENTS"=>"BE.WF_COMMENTS", "IN_SECTIONS"=>"BE.IN_SECTIONS", "SHOW_COUNTER"= >"BE.SHOW_COUNTER", "SHOW_COUNTER_START"=>$DB->DateToCharFunction("BE.SHOW_COUNTER_START"), "CODE"=>"BE.CODE", "TAGS"=>"BE.TAGS", "XML_ID" =>"BE.XML_ID", "EXTERNAL_ID"=>"BE.XML_ID", "TMP_ID"=>"BE.TMP_ID", "USER_NAME"=>"concat("(",U.LOGIN,") ", ifnull(U.NAME,"")," ",ifnull(U.LAST_NAME,""))", "LOCKED_USER_NAME"=>"concat("(",UL.LOGIN,"") ",ifnull(UL. IME ","")," ",ifnull(UL.LAST_NAME,""))", "CREATED_USER_NAME"=>"concat("(",UC.LOGIN,"") ",ifnull(UC.NAME," "), " ",ifnull(UC.LAST_NAME,""))", "LANG_DIR"=>"L.DIR", "LID"=>"B.LID", "IBLOCK_TYPE_ID"=>"B.IBLOCK_TYPE_ID" , "IBLOCK_CODE "=>"B.CODE", "IBLOCK_NAME"=>"B.NAME", "IBLOCK_EXTERNAL_ID"=>"B.XML_ID", "DETAIL_PAGE_URL"=>"B.DETAIL_PAGE_URL", "LIST_PAGE_URL"=> "B. LIST_PAGE_URL", "CANONICAL_PAGE_URL"=>"B.CANONICAL_PAGE_URL", "CREATED_DATE"=>$DB->DateFormatToDB("GGGG.MM.DD", "BE.DATE_CREATE"), "BP_PUBLISHED"=>"ako (BE. WF_STATUS_ID = 1, "Y", "N")",); poništi($shortFormatActiveDates); poništi($formatActiveDates); $bDistinct = false; CIBlockElement::PrepareGetList($arIblockElementFields, $arJoinProps, $bOnlyCount, $bDistinct, $arSelectFields, $sSelect, $arAddSelectFields, $arFilter, $sWhere, $sSectionWhere, $arAddWhereFields, $arGroupBy, $sGroupBy, $arO rder, $arSqlOrder, $arAddOrderByFields, $arIBlockFilter, $arIBlockMultProps, $arIBlockConvProps, $arIBlockAllProps, $arIBlockNumProps, $arIBlockLongProps); $arFilterIBlocks = isset($arFilter["IBLOCK_ID"])? array($arFilter["IBLOCK_ID"]): array(); //**************** IZ DIJELA**************************** ** ************** $sFrom = ""; foreach($arJoinProps["FPS"] as $iblock_id => $iPropCnt) ( $sFrom .= "tttINNER JOIN b_iblock_element_prop_s".$iblock_id." FPS".$iPropCnt." ON FPS".$iPropCnt.".IBLOCK_ELEMENT_ID = BE.IDn"; $arFilterIBlocks[$iblock_id] = $iblock_id; ) foreach($arJoinProps["FP"] as $propID => $db_prop) ( $i = $db_prop["CNT"]; if($db_prop[ "bFullJoin"]) $sFrom .= "tttINNER JOIN b_iblock_property FP".$i." ON FP".$i.".IBLOCK_ID = B.ID AND ". (IntVal($propID)>0? "FP". $i.".ID=".IntVal($propID)."n": " FP".$i.".CODE="".$DB->ForSQL($propID, 200).""n") ; else $sFrom .= "tttLEFT JOIN b_iblock_property FP".$i." ON FP".$i.".IBLOCK_ID = B.ID AND ". (IntVal($propID)>0? " FP".$i. ".ID=".IntVal($propID)."n": "FP".$i.".CODE="".$DB->ForSQL($propID, 200). ""n"); if($db_prop["IBLOCK_ID"]) $arFilterIBlocks[$db_prop["IBLOCK_ID"]] = $db_prop["IBLOCK_ID"]; ) foreach($arJoinProps["FPV"] ​​​​kao $ propID = > $db_prop) ( $i = $db_prop["CNT"]; if($db_prop["MULTIPLE"]=="Y") $bDistinct = istina; if($db_prop["VERSION"]==2 ) $ strTable = "b_iblock_element_prop_m".$db_prop["IBLOCK_ID"]; else $strTable = "b_iblock_element_property"; if($db_prop["bFullJoin"]) $sFrom .= "tttINNER JOIN ".$strTable." FPV". $i ." ON FPV".$i.".IBLOCK_PROPERTY_ID = FP".$db_prop["JOIN"].".ID I FPV".$i.".IBLOCK_ELEMENT_ID = BE.IDn"; else $sFrom .= "tttLEFT JOIN ".$strTable." FPV".$i." NA FPV".$i.".IBLOCK_PROPERTY_ID = FP".$db_prop["JOIN"].".ID I FPV".$i.". IBLOCK_ELEMENT_ID = BE.IDn"; if($db_prop["IBLOCK_ID"]) $arFilterIBlocks[$db_prop["IBLOCK_ID"]] = $db_prop["IBLOCK_ID"]; ) foreach($arJoinProps["FPEN"] as $propID => $db_prop) ( $i = $db_prop["CNT"]; if($db_prop["VERSION"] == 2 && $db_prop["MULTIPLE"] == "N") ( if($db_prop[" bFullJoin" ]) $sFrom .= "tttINNER JOIN b_iblock_property_enum FPEN".$i." ON FPEN".$i.".PROPERTY_ID = ".$db_prop["ORIG_ID"]." AND FPS".$db_prop["JOIN "] ".PROPERTY_".$db_prop["ORIG_ID"]." = FPEN".$i.".IDn"; else $sFrom .= "tttLEFT JOIN b_iblock_property_enum FPEN".$i." ON FPEN".$i.".PROPERTY_ID = ".$db_prop["ORIG_ID"].." AND FPS".$db_prop["JOIN"] . ".PROPERTY_".$db_prop["ORIG_ID"]." = FPEN".$i.".IDn"; ) else ( if($db_prop["bFullJoin"]) $sFrom .= "tttINNER JOIN b_iblock_property_enum FPEN".$i." ON FPEN".$i.".PROPERTY_ID = FPV".$db_prop["JOIN"]. ".IBLOCK_PROPERTY_ID AND FPV".$db_prop["JOIN"].".VALUE_ENUM = FPEN".$i.".IDn"; else $sFrom .= "tttLEFT JOIN b_iblock_property_enum FPEN".$i." NA FPEN". $i.".PROPERTY_ID = FPV".$db_prop["JOIN"].".IBLOCK_PROPERTY_ID AND FPV".$db_prop["JOIN"].".VALUE_ENUM = FPEN".$i.".IDn"; ) ako ($db_prop["IBLOCK_ID"]) $arFilterIBlocks[$db_prop["IBLOCK_ID"]] = $db_prop["IBLOCK_ID"]; ) foreach($arJoinProps["BE"] as $propID => $db_prop) ( $i = $db_prop["CNT"]; $sFrom .= "tttLEFT JOIN b_iblock_element BE".$i." ON BE".$ i.".ID = ". ($db_prop["VERSION"]==2 && $db_prop["MULTIPLE"]=="N"? "FPS".$db_prop["JOIN"].".PROPERTY_". $db_prop["ORIG_ID"] :"FPV".$db_prop["JOIN"]..VALUE_NUM"). ($arFilter["SHOW_HISTORY"] != "Y"? " I ((BE.WF_STATUS_ID=1 I BE) .WF_PARENT_ELEMENT_ID IS NULL)".($arFilter["SHOW_NEW"]=="Y"? " ILI BE.WF_NEW="Y"": "").")": "")."n"; if ( $db_prop["bJoinIBlock"]) $sFrom .= "tttLEFT JOIN b_iblock B".$i." ON B".$i.".ID = BE".$i.".IBLOCK_IDn"; if($db_prop [ "bJoinSection"]) $sFrom . = "tttLEFT JOIN b_iblock_sekcija BS".$i." NA BS".$i.".ID = BE".$i.".IBLOCK_SECTION_IDn"; if($db_prop["IBLOCK_ID"]) $arFilterIBlocks[$db_prop["IBLOCK_ID"]] = $db_prop["IBLOCK_ID"]; ) foreach($arJoinProps["BE_FPS"] as $iblock_id => $db_prop) ( $sFrom .= "tttLEFT JOIN b_iblock_element_prop_s".$iblock_id." JFPS".$db_prop["CNT"]." NA JFPS".$ db_prop["CNT"].".IBLOCK_ELEMENT_ID = BE".$db_prop["JOIN"].".IDn"; if($db_prop["IBLOCK_ID"]) $arFilterIBlocks[$db_prop["IBLOCK_ID"]] = $ db_prop["IBLOCK_ID"]; ) foreach($arJoinProps["BE_FP"] as $propID => $db_prop) ( $i = $db_prop["CNT"]; popis($propID, $link) = explode("~ ", $propID, 2); if($db_prop["bFullJoin"]) $sFrom .= "tttINNER JOIN b_iblock_property JFP".$i." NA JFP".$i.".IBLOCK_ID = BE".$db_prop[ "JOIN"].".IBLOCK_ID AND ". (IntVal($propID)>0? " JFP".$i.".ID=".IntVal($propID)."n": " JFP".$i. ".CODE="".$DB->ForSQL($propID, 200).""n"); else $sFrom .= "tttLEFT JOIN b_iblock_property JFP".$i." NA JFP".$i.". IBLOCK_ID = BE".$db_prop["JOIN"].".IBLOCK_ID AND ". (IntVal($propID)>0? " JFP".$i.".ID=".IntVal($propID)."n" : " JFP".$i.".CODE="".$DB->ForSQL($propID, 200).""n"); if($db_prop["IBLOCK_ID"]) $arFilterIBlocks[$db_prop[" IBLOCK_ID"]] = $db_prop["IBLOCK_ID"]; ) foreach($arJoinProps["BE_FPV"] ​​​​as $propID => $db_prop) ( $i = $db_prop["CNT"]; popis($propID, $link) = explode("~", $propID, 2) ; if($db_prop["MULTIPLE"]=="Y") $bDistinct = true; if($db_prop["VERSION"]==2) $strTable = "b_iblock_element_prop_m".$db_prop["IBLOCK_ID"] ; else $strTable = "b_iblock_element_property"; if($db_prop["bFullJoin"]) $sFrom .= "tttINNER JOIN ".$strTable." JFPV".$i." ON JFPV".$i.".IBLOCK_PROPERTY_ID = JFP" .$db_prop["JOIN"].".ID I JFPV".$i.".IBLOCK_ELEMENT_ID = BE".$db_prop["BE_JOIN"].".IDn"; else $sFrom .= "tttLEFT JOIN " .$ strTable." JFPV".$i." ON JFPV".$i.".IBLOCK_PROPERTY_ID = JFP".$db_prop["JOIN"].".ID I JFPV".$i.".IBLOCK_ELEMENT_ID = BE" .$ db_prop["BE_JOIN"].".IDn"; if($db_prop["IBLOCK_ID"]) $arFilterIBlocks[$db_prop["IBLOCK_ID"]] = $db_prop["IBLOCK_ID"]; ) foreach($arJoinProps[ "BE_FPEN "] kao $propID => $db_prop) ( $i = $db_prop["CNT"]; popis($propID, $link) = explode("~", $propID, 2); if($db_prop[ "VERZIJA "] == 2 && $db_prop["MULTIPLE"] == "N") ( if($db_prop["bFullJoin"]) $sFrom .= "tttINNER JOIN b_iblock_property_enum JFPEN".$i." ON JFPEN" .$ i.".PROPERTY_ID = ".$db_prop["ORIG_ID"].." I JFPS".$db_prop["JOIN"].".PROPERTY_".$db_prop["ORIG_ID"].." = JFPEN" .$i. ".IDn"; inače $sOd . = "tttLEFT JOIN b_iblock_property_enum JFPEN".$i." ON JFPEN".$i.".PROPERTY_ID = ".$db_prop["ORIG_ID"].." I JFPS".$db_prop["JOIN"].".PROPERTY_ " .$db_prop["ORIG_ID"]." = JFPEN".$i.".IDn"; ) else ( if($db_prop["bFullJoin"]) $sFrom .= "tttINNER JOIN b_iblock_property_enum JFPEN".$i." ON JFPEN".$i.".PROPERTY_ID = JFPV".$db_prop["JOIN"]. ".IBLOCK_PROPERTY_ID AND JFPV".$db_prop["JOIN"].".VALUE_ENUM = JFPEN".$i.".IDn"; else $sFrom .= "tttLEFT JOIN b_iblock_property_enum JFPEN".$i." ON JFPEN". $i.".PROPERTY_ID = JFPV".$db_prop["JOIN"].".IBLOCK_PROPERTY_ID AND JFPV".$db_prop["JOIN"].".VALUE_ENUM = JFPEN".$i.".IDn"; ) ako ($db_prop["IBLOCK_ID"]) $arFilterIBlocks[$db_prop["IBLOCK_ID"]] = $db_prop["IBLOCK_ID"]; ) if(strlen($arJoinProps["BES"])) ( $sFrom .= "ttt".$arJoinProps["BES"]."n"; ) if(strlen($arJoinProps["FC"])) ( $sFrom .= "ttt".$arJoinProps["FC"]."n"; $bDistinct = $bDistinct || (isset($arJoinProps["FC_DISTINCT"]) && $arJoinProps["FC_DISTINCT"] == "Y "); ) if($arJoinProps["RV"]) $sFrom .= "tttLEFT JOIN b_rating_voting RV ON RV.ENTITY_TYPE_ID = "IBLOCK_ELEMENT" AND RV.ENTITY_ID = BE.IDn"; if($arJoinProps["RVU"]) $sFrom .= "tttLEFT JOIN b_rating_vote RVU ON RVU.ENTITY_TYPE_ID = "IBLOCK_ELEMENT" AND RVU.ENTITY_ID = BE.ID AND RVU.USER_ID = ".$uid."n"; if($arJoinProps["RVV"]) $sFrom .= "ttt".($arJoinProps["RVV"]["bFullJoin"]? "INNER": "LEFT")." PRIDRUŽI SE b_rating_vote RVV NA RVV.ENTITY_TYPE_ID = "IBLOCK_ELEMENT" I RVV.ENTITY_ID = BE.IDn"; //********************KRAJ OD DIJELA**************************** ********* ***************** $bCatalogSort = false; if(count($arAddSelectFields)>0 || count($arAddWhereFields)>0 || count($arAddOrderByFields)>0) ( if(CModule::IncludeModule("catalog")) ( $res_catalog = CCatalogProduct::GetQueryBuildArrays( $arAddOrderByFields, $arAddWhereFields, $arAddSelectFields); if($sGroupBy=="" && !$bOnlyCount && !(is_object($this) && isset($this->strField))) $sSelect .= $res_catalog["SELECT "]." "; $sFrom .= str_replace("LEFT JOIN", "ntttLEFT JOIN", $res_catalog["FROM"])."n"; //$sWhere .= $res_catalog["WHERE"]." "; premješteno u MkFilter if(is_array($res_catalog["ORDER"]) && count($res_catalog["ORDER"])) ( $bCatalogSort = true; foreach($res_catalog["ORDER"] as $i=>$ val) $arSqlOrder[$i] = $val; ) ) ) $i = array_search("CREATED_BY_FORMATTED", $arSelectFields); if ($i !== false) ( if ($sSelect && $sGroupBy=="" && !$bOnlyCount && !(is_object($this) && isset($this->strField))) ( $sSelect .= " ,UC. IME UC_NAME, UC.LAST_NAME UC_LAST_NAME, UC.SECOND_NAME UC_SECOND_NAME, UC.EMAIL UC_EMAIL, UC.ID UC_ID, UC.LOGIN UC_LOGIN"; ) else ( unset($arSelectFields[$i]); ) ) $sOrderBy = ""; foreach($arSqlOrder as $i=>$val) ( if(strlen($val)) ( if($sOrderBy=="") $sOrderBy = " ORDER BY "; else $sOrderBy .= ","; $sOrderBy .= $val." "; ) ) $sSelect = trim($sSelect, ", tnr"); if(strlen($sSelect)<= 0) $sSelect = "0 as NOP "; $bDistinct = $bDistinct || (isset($arFilter["INCLUDE_SUBSECTIONS"]) && $arFilter["INCLUDE_SUBSECTIONS"] == "Y"); if($bDistinct) $sSelect = str_replace("%%_DISTINCT_%%", "DISTINCT", $sSelect); else $sSelect = str_replace("%%_DISTINCT_%%", "", $sSelect); $sFrom = " b_iblock B INNER JOIN b_lang L ON B.LID=L.LID INNER JOIN b_iblock_element BE ON BE.IBLOCK_ID = B.ID ".ltrim($sFrom, "tn") .(in_array("USER_NAME", $arSelectFields)? "tttLEFT JOIN b_user U ON U.ID=BE.MODIFIED_BYn": "") .(in_array("LOCKED_USER_NAME", $arSelectFields)? "tttLEFT JOIN b_user UL ON UL.ID=BE.WF_LOCKED_BYn": "") .(in_array("CREATED_USER_NAME", $arSelectFields) || in_array("CREATED_BY_FORMATTED", $arSelectFields)? "tttLEFT JOIN b_user UC ON UC.ID=BE.CREATED_BYn": "")." "; $strSql = " FROM ".$sFrom." WHERE 1=1 " .$sWhere." ".$sGroupBy." "; if(isset($this) && is_object($this) && isset($this->strField)) ( $this->sFrom = $sFrom; $this->sWhere = $sWhere; return "SELECT ".$sSelect.$strSql; ) if($bOnlyCount) ( $res = $DB->Query(" SELECT ".$sSelect.$strSql, false, "FILE: ".__FILE__."
LINE: ".__LINE__); $res = $res->Fetch(); return $res["CNT"]; ) if(is_array($arNavStartParams)) ( $nTopCount = intval($arNavStartParams["nTopCount"]) ; $nElementID = intval($arNavStartParams["nElementID"]); if($nTopCount > 0) ( $strSql = "SELECT ".$sSelect.$strSql.$sOrderBy." LIMIT ".$nTopCount; $res = $ DB->Query($strSql); ) elseif($nElementID > 0 && $sGroupBy == "" && $sOrderBy != "" && strpos($sSelect, "BE.ID") !== false && !$bCatalogSort ) ( $nPageSize = intval($arNavStartParams["nPageSize"]); if($nPageSize > 0) ( $DB->Query("SET @rank_e=0"); $DB->Query("SET @rank_r= 0"); $DB->Query(" SELECT ".$sSelect." ,@rank_r:=@rank_r+1 AS rang1 ,if (BE.ID = ".$nElementID.", @rank_e:=@rank_r, null) rank2 ".$strSql.$sOrderBy." "); $DB->Query("SET @rank_r=0"); $res = $DB->Query(" SELECT * FROM (SELECT ".$sSelect. " ,@rank_r:=@rank_r+1 AS RANK ".$strSql.$sOrderBy." LIMIT 18446744073709551615) el0 WHERE el0.RANK između @rank_e-$nPageSize i @rank_e+$nPageSize "); ) else ( $DB->Query("SET @rank=0"); $res = $DB->Query(" SELECT * FROM (SELECT ".$sSelect." ,@rank:=@rank+1 AS RANK ".$strSql.$sOrderBy." OGRANIČENJE 18446744073709551615) el0 WHERE el0.ID = ".$nElementID." "); ) ) else ( if($sGroupBy == "") ( $res_cnt = $DB->Query( "SELECT COUNT(".($bDistinct? "DISTINCT BE.ID": ""x"").") kao C ".$strSql); $res_cnt = $res_cnt->Fetch(); $cnt = $res_cnt ["C"]; ) else ( $res_cnt = $DB->Query("SELECT "x" ".$strSql); $cnt = $res_cnt->SelectedRowsCount(); ) $strSql = "SELECT ".$sSelect .$strSql.$sOrderBy; $res = novi CDBResult(); $res->NavQuery($strSql, $cnt, $arNavStartParams); ) ) else//if(is_array($arNavStartParams)) ( $strSql = "SELECT ".$sSelect.$strSql.$sOrderBy; $res = $DB->Query($strSql, false, "DATOTEKA: ".__FILE__."
LINE: ".__LINE__); ) $res = new CIBlockResult($res); $res->SetIBlockTag($arFilterIBlocks); $res->arIBlockMultProps = $arIBlockMultProps; $res->arIBlockConvProps = $arIBlockConvProps; $res-> arIBlockAllProps = $arIBlockAllProps; $res->arIBlockNumProps = $arIBlockNumProps; $res->arIBlockLongProps = $arIBlockLongProps; return $res; )

Kao što možda pretpostavljate, ova metoda prima popis elemenata bloka informacija iz baze podataka, a za dobivanje popisa nije potrebno kreirati instancu klase CIBlockElement. Međutim, za dodavanje elementa informacijskog bloka potrebno je stanje, i to samo kako bi se zabilježile informacije o posljednjoj pogrešci koja se dogodila u javnom svojstvu klase.

Stari API intenzivno koristi globalne varijable kao što su $APPLICATION, $USER, $DB. Oni su instance određenih klasa, au dokumentaciji su se ponosno nazivali singletoni, iako sada više nisam našao te riječi.
Da biste generirali pogrešku, na primjer, u rukovateljima događajima, morate koristiti metodu $APPLICATION->ThrowException(), koja zapravo ne baca iznimke.

Javna funkcija ThrowException($msg, $id = false) ( $this->ResetException(); if(is_object($msg) && (is_subclass_of($msg, "CApplicationException") || (strtolower(get_class($msg)) =="capplicationexception"))) $this->LAST_ERROR = $msg; inače $this->LAST_ERROR = nova CApplicationException($msg, $id); )

I da - sva ta ljepota i dalje se koristi u razvoju novih projekata, jer... D7 još ne podržava sve značajke starog API-ja. Isti modul infobloka i dalje vam omogućuje da izvršite samo odabir entiteta, a ne u cijelosti. Još nije moguće izraditi novi element ili ažurirati postojeći pomoću novog API-ja.

Novi API već se ponešto razlikuje od starog. Prvo, sav kod iz novog kernela podijeljen je u prostore imena, gdje postoji jasna ovisnost o modulu. Na primjer, analog CIBlockElement::GetList iz nove jezgre je BitrixIblockElementTable::getList, gdje je root imenski prostor ime dobavljača, a sljedeći imenski prostor je naziv modula. Kako bi ovo funkcioniralo, Bitrix je napisao vlastiti autoloader, BitrixMainLoader::autoLoad, koji uopće nije kompatibilan s PSR-0/4.

Zapravo, kod autoloadera u obliku jedne funkcije

Javna statička funkcija autoLoad($className) ( $file = ltrim($className, "\"); // popravi web env $file = strtr($file, static::ALPHA_UPPER, static::ALPHA_LOWER); static $documentRoot = null; if ($documentRoot === null) $documentRoot = static::getDocumentRoot(); if (isset(self::$arAutoLoadClasses[$file])) ( $pathInfo = self::$arAutoLoadClasses[$file]; if ($pathInfo["module"] != "") ( $m = $pathInfo["module"]; $h = isset(self::$arLoadedModulesHolders[$m]) ? self::$arLoadedModulesHolders[$m ] : "bitrix"; include_once($documentRoot."/".$h."/modules/".$m."/" .$pathInfo["file"]); ) else ( require_once($documentRoot.$pathInfo ["file"]); ) return; ) if (preg_match("#[^\\/a-zA-Z0-9_]#", $file)) return; if (substr($file, -5) = = "tablica") $file = substr($file, 0, -5); $file = str_replace("\", "/", $file); $arFile = explode("/", $file); if ($arFile === "bitrix") ( array_shift($arFile); if (empty($arFile)) return; $module = array_shift($arFile); if ($module == null || empty($arFile) ) povratak; ) else ( $module1 = array_shift($arFile); $module2 = array_shift($arFile); if ($module1 == null || $module2 == null || empty($arFile)) return; $module = $module1 .".".$module2; ) if (!isset(self::$arLoadedModulesHolders[$module])) return; $filePath = $documentRoot."/".self::$arLoadedModulesHolders[$module].."/modules/".$module."/lib/".implode("/", $arFile).".php" ; if (file_exists($filePath)) require_once($filePath); )

Novi API pokazuje veliku ljubav prema Singletonu:

  • BitrixMainApplication::getInstance - instanca aplikacije
  • BitrixMainConfigConfiguration::getInstance - instanca klase za upravljanje konfiguracijama
  • BitrixMainPageAsset::getInstance - Instanca upravitelja imovine
  • BitrixMainEventManager::getInstance - upravitelj događaja

Možda će u budućnosti sve to dobiti svoj ServiceLayer (postoji određeni BitrixMainServiceManager u novoj jezgri, koji se još ne koristi i nije dokumentiran), ali malo je još nade.

ORM je još jedna od inovacija D7, a ovo je nešto što može tvrditi da je pravi model! Klasu ORM entiteta možete razlikovati od bilo koje druge klase po nazivu. Klasa entiteta uvijek mora završavati sa Tablica (Tablica elemenata, Tablica odjeljaka, Tablica naloga itd.). Štoviše, paradoksalno, naziv datoteke s klasom entiteta ORM ne bi trebao završavati na tablici. Na primjer, za ElementTable moramo stvoriti datoteku element.php. Snimak zaslona u nastavku prikazuje sadržaj direktorija lib (D7 autoload radi samo u ovom direktoriju) modula iblock. Pokušajte na oko odrediti što su ORM entiteti, a što obične klase s poslovnom logikom.


ORM, uglavnom, još nije ništa posebno. Omogućuje vam da opišete tablice baze podataka u obliku klasa i omogućuje vam izvršavanje upita na tim tablicama i njihovo međusobno povezivanje. Ne postoji ActiveRecord ili Repository i ne očekuje se.

Primjer tipične klase ORM entiteta za element infobloka

*

  • ID int obavezno *
  • TIMESTAMP_X datum i vrijeme izborno *
  • MODIFIED_BY int izborno *
  • DATE_CREATE datum i vrijeme izborno *
  • CREATED_BY int izborno *
  • IBLOCK_ID int obavezno *
  • IBLOCK_SECTION_ID int izborno *
  • AKTIVNO bool izborno zadano "Y" *
  • ACTIVE_FROM datum i vrijeme izborno *
  • ACTIVE_TO datum i vrijeme izborno *
  • SORT int izborno zadano 500 *
  • IME niz (255) obavezno *
  • PREVIEW_PICTURE int izborno *
  • PREVIEW_TEXT string izborno *
  • PREVIEW_TEXT_TYPE enum ("tekst", "html") izborni zadani "tekst" *
  • DETAIL_PICTURE int izborno *
  • DETAIL_TEXT string izborno *
  • DETAIL_TEXT_TYPE enum ("tekst", "html") opcijski zadani "tekst" *
  • SEARCHABLE_CONTENT string izborno *
  • WF_STATUS_ID int izborno zadano 1 *
  • WF_PARENT_ELEMENT_ID int izborno *
  • WF_NEW enum ("N", "Y") izborno *
  • WF_LOCKED_BY int izborno *
  • WF_DATE_LOCK datum i vrijeme izborno *
  • WF_COMMENTS string izborno *
  • IN_SECTIONS bool izborno zadano "N" *
  • XML_ID niz (255) izborno *
  • CODE string (255) izborno *
  • OZNAKE niz (255) izborno *
  • TMP_ID string(40) izborno *
  • WF_LAST_HISTORY_ID int izborno *
  • SHOW_COUNTER int izborno *
  • SHOW_COUNTER_START datum i vrijeme izborno *
  • PREVIEW_PICTURE_FILE referenca na (@link BitrixFileFileTable) *
  • DETAIL_PICTURE_FILE referenca na (@link BitrixFileFileTable) *
  • IBLOCK referenca na (@link BitrixIblockIblockTable) *
  • WF_PARENT_ELEMENT referenca na (@link BitrixIblockIblockElementTable) *
  • IBLOCK_SECTION referenca na (@link BitrixIblockIblockSectionTable) *
  • MODIFIED_BY_USER referenca na (@link BitrixUserUserTable) *
  • CREATED_BY_USER referenca na (@link BitrixUserUserTable) *
  • WF_LOCKED_BY_USER referenca na (@link BitrixUserUserTable) * * * @package BitrixIblock **/ class ElementTable extends MainEntityDataManager ( const TYPE_TEXT = "text"; const TYPE_HTML = "html"; /** * Vraća naziv DB tablice za entitet. * * @return string */ javna statička funkcija getTableName( ) ( return "b_iblock_element"; ) /** * Vraća definiciju mape entiteta. * * @return array */ javna statička funkcija getMap() ( return array("ID" => new MainEntityIntegerField("ID", array("primary) " => true, "autocomplete" => true, "title" => Loc::getMessage("ELEMENT_ENTITY_ID_FIELD"),)), "TIMESTAMP_X" => new MainEntityDatetimeField("TIMESTAMP_X", array("default_value" => new MainTypeDateTime(), "title" => Loc::getMessage("ELEMENT_ENTITY_TIMESTAMP_X_FIELD"),)), "MODIFIED_BY" => new MainEntityIntegerField("MODIFIED_BY", array("title" => Loc::getMessage("ELEMENT_ENTITY_MODIFIED_BY_FIELD") ,)), "DATE_CREATE" => new MainEntityDatetimeField("DATE_CREATE", array("default_value" => new MainTypeDateTime(), "title" => Loc::getMessage("ELEMENT_ENTITY_DATE_CREATE_FIELD"),)), "CREATED_BY" = > new MainEntityIntegerField("CREATED_BY", array("title" => Loc::getMessage("ELEMENT_ENTITY_CREATED_BY_FIELD"),)), "IBLOCK_ID" => new MainEntityIntegerField("IBLOCK_ID", array("required" => true, " title" => Loc::getMessage("ELEMENT_ENTITY_IBLOCK_ID_FIELD"),)), "IBLOCK_SECTION_ID" => new MainEntityIntegerField("IBLOCK_SECTION_ID", array("title" => Loc::getMessage("ELEMENT_ENTITY_IBLOCK_SECTION_ID_FIELD")),)), " ACTIVE" => new MainEntityBooleanField("ACTIVE", array("values" => array("N", "Y"), "default_value" => "Y", "title" => Loc::getMessage("ELEMENT_ENTITY_ACTIVE_FIELD "),)), "ACTIVE_FROM" => new MainEntityDatetimeField("ACTIVE_FROM", array("title" => Loc::getMessage("ELEMENT_ENTITY_ACTIVE_FROM_FIELD")),)), "ACTIVE_TO" => new MainEntityDatetimeField("ACTIVE_TO", array("title" => Loc::getMessage("ELEMENT_ENTITY_ACTIVE_TO_FIELD"),)), "SORT" => new MainEntityIntegerField("SORT", array("default_value" => 500, "title" => Loc::getMessage ("ELEMENT_ENTITY_SORT_FIELD"),)), "NAME" => new MainEntityStringField("NAME", array("required" => true, "validation" => array(__CLASS__, "validateName"), "title" => Loc ::getMessage("ELEMENT_ENTITY_NAME_FIELD"),)), "PREVIEW_PICTURE" => new MainEntityIntegerField("PREVIEW_PICTURE", array("title" => Loc::getMessage("ELEMENT_ENTITY_PREVIEW_PICTURE_FIELD"),)), "PREVIEW_TEXT" => novo MainEntityTextField("PREVIEW_TEXT", array("title" => Loc::getMessage("ELEMENT_ENTITY_PREVIEW_TEXT_FIELD"),)), "PREVIEW_TEXT_TYPE" => new MainEntityEnumField("PREVIEW_TEXT_TYPE", array("values" => array(self:: TYPE_TEXT, self::TYPE_HTML), "default_value" => self::TYPE_TEXT, "title" => Loc::getMessage("ELEMENT_ENTITY_PREVIEW_TEXT_TYPE_FIELD"),)), "DETAIL_PICTURE" => new MainEntityIntegerField("DETAIL_PICTURE", array( "title" => Loc::getMessage("ELEMENT_ENTITY_DETAIL_PICTURE_FIELD"),)), "DETAIL_TEXT" => new MainEntityTextField("DETAIL_TEXT", array("title" => Loc::getMessage("ELEMENT_ENTITY_DETAIL_TEXT_FIELD"),)), "DETAIL_TEXT_TYPE" => new MainEntityEnumField("DETAIL_TEXT_TYPE", array("values" => array(self::TYPE_TEXT, self::TYPE_HTML), "default_value" => self::TYPE_TEXT, "title" => Loc:: getMessage("ELEMENT_ENTITY_DETAIL_TEXT_TYPE_FIELD"),)), "SEARCHABLE_CONTENT" => new MainEntityTextField("SEARCHABLE_CONTENT", array("title" => Loc::getMessage("ELEMENT_ENTITY_SEARCHABLE_CONTENT_FIELD"),)), "WF_STATUS_ID" => novi MainEntityInteger Polje ( "Wf_status_id", Array ("Title" => Loc :: getmessage ("Element_entity_wf_status_id_field"),)), "WF_PARENT_ELEMENT_ID" => New MainentityintegerField , Array ("Title" => Loc :: Getmessage ("Element_entity_wf_part_element_id_field "),) ), "WF_NEW" => new MainEntityEnumField("WF_NEW", array("values" => array("N", "Y"), "title" => Loc::getMessage("ELEMENT_ENTITY_WF_NEW_FIELD") ,)), "WF_LOCKED_BY" => new MainEntityIntegerField("WF_LOCKED_BY", array("title" => Loc::getMessage("ELEMENT_ENTITY_WF_LOCKED_BY_FIELD"),)), "WF_DATE_LOCK" => new MainEntityDatetimeField("WF_DATE_LOCK", array( "title" = > Loc::getMessage("ELEMENT_ENTITY_WF_DATE_LOCK_FIELD"),)), "WF_COMMENTS" => new MainEntityTextField("WF_COMMENTS", array("title" => Loc::getMessage("ELEMENT_ENTITY_WF_COMMENTS_FIELD"),)), "IN_SECTIONS" = > novo MainEntityBooleanField("IN_SECTIONS", array("values" => array("N", "Y"), "title" => Loc::getMessage("ELEMENT_ENTITY_IN_SECTIONS_FIELD"),)), "XML_ID " => novo MainEntityStringField("XML_ID", array("validation" => array(__CLASS__, "validateXmlId"), "title" => Loc::getMessage("ELEMENT_ENTITY_XML_ID_FIELD"),)), "CODE" => new MainEntityStringField("CODE ", array("validation" => array(__CLASS__, "validateCode"), "title" => Loc::getMessage("ELEMENT_ENTITY_CODE_FIELD"),)), "TAGS" => new MainEntityStringField("TAGS ", array( "validation" => array(__CLASS__, "validateTags"), "title" => Loc::getMessage("ELEMENT_ENTITY_TAGS_FIELD"), "TMP_ID" => new MainEntityStringField("TMP_ID", array( "validation" => array( __RAZRED__, "va

    I primjer rada s ovim entitetom

    //Odabir podataka $dbElements = BitrixIblockElementTable::query() ->setFilter(["IBLOCK_ID" => CATALOG_IBLOCK_ID, "ACTIVE" => "Y"]) ->setSelect(["NAME", "ID", "DETAIL_PAGE_URL ", "DATE_ACTIVE_FROM"]) ->addSelect("IBLOCK_SECTION_ID", "PARENT_SECTION") ->setLimit(10) ->addOrder("id", "DESC") ->exec(); while ($arElement = $dbElements->fetch()) ( echo "($arElement["NAME"]) - " . $arElement["DATE_ACTIVE_FROM"]->format("d.m.Y H:i:s"); ) //Dodavanje zapisa $addResult = BitrixIblockElementTable::add([ "NAME" => "Naziv novog elementa", "IBLOCK_ID" => CATALOG_IBLOCK_ID ]); if (!$addResult->isSuccess()) ( echo implode("
    " ,$addResult->getErrorMessages()); )

    Bitrix je vrlo ponosan na svoj modul Highload Blocks, koji je u potpunosti napisan pomoću D7.
    Prije su imali samo informacijske blokove kao pohranu proizvoljnog skupa informacija. Informacijski blok, za one koji ne znaju, je entitet koji je pohranjen u bazi podataka kao kompleks nekoliko tablica (1 tablica za “osnovna” polja elementa informacijskog bloka i do 2 tablice za svojstva element informacijskog bloka). Sva polja osnovnih elemenata svatko infoblokovi su pohranjeni u jednoj tablici. Ako imate 15 informacijskih blokova, od kojih svaki ima 500k elemenata, svi ti elementi će zapravo biti u jednoj tablici. Dodatna svojstva elemenata infobloka pridružuju se iz drugih tablica. Ako su to informacijski blokovi prve verzije, tada su sva svojstva svih informacijskih blokova također u jednoj tablici, au slučaju informacijskih blokova 2.0 (pozdrav, marketing) - svojstva svakog informacijskog bloka već su podijeljena u različite tablice .
    I cijela se ova stvar prirodno jako usporila već na relativno malim skupovima podataka. 400 tisuća elemenata u jednom informacijskom bloku već prilično usporavaju rad admin panela. Marketinški stručnjaci iz Bitrixa su smislili i stvorili Highload blokove! Razlika u implementaciji između konvencionalnih informacijskih blokova je minimalna. Sada se za svaki highload blok kreira vlastita tablica + osim toga, kreira se još jedna tablica za pohranu višestrukih vrijednosti. Uobičajeni pristup stvaranju obične tablice u bazi podataka nazvali su ponosnim imenom visoko opterećenje jednostavno zato što usporava manje od običnih informacijskih blokova!
    Osim toga, unutar modula, kako bi radio prema D7, klase entiteta se generiraju dinamički i ocjenjuju se pri svakom pogotku.To je highload.

    Pogledaj ovo

    Javna statička funkcija compileEntity($hlblock) ( globalno $USER_FIELD_MANAGER; // generiraj entitet & upravitelj podataka $fieldsMap = array(); // dodaj ID $fieldsMap["ID"] = array("data_type" => "integer", "primary" => true, "autocomplete" => true); // izgradite klasu upravitelja podataka $entity_name = $hlblock["NAME"]; $entity_data_class = $hlblock["NAME"]; if (!preg_match("/^ +$/i", $entity_data_class)) ( throw new MainSystemException(sprintf("Nevažeći naziv entiteta `%s`.", $entity_data_class)); ) $entity_data_class .= "Tablica"; if (class_exists($entity_data_class)) ( // ponovno izgradi ako već postoji EntityBase::destroy($entity_data_class); ) else ( $entity_table_name = $hlblock["TABLE_NAME"]; // napravi s praznom mapom $eval = " class ".$entity_data_class. " extends ".__NAMESPACE__."DataManager ( javna statička funkcija getTableName() ( return ".var_export($entity_table_name, true)."; ) javna statička funkcija getMap() ( return ".var_export($fieldsMap, true)."; ) javna statička funkcija getHighloadBlock() ( return ".var_export($hlblock, true)."; ) ) "; eval($eval); ) // zatim konfigurirajte i priložite polja /** @var BitrixMainEntityDataManager $entity_data_class */ $entity = $entity_data_class::getEntity(); $uFields = $USER_FIELD_MANAGER->getUserFields("HLBLOCK_ ".$hlblock["ID"]); foreach ($uFields as $uField) ( if ($uField["MULTIPLE"] == "N") ( // samo dodajte jedno polje $field = $USER_FIELD_MANAGER->getEntityField ($uField, $uField["FIELD_NAME"]); $entity->addField($field); foreach ($USER_FIELD_MANAGER->getEntityReferences($uField, $field) as $reference) ( $entity->addField($reference) ); ) ) else ( // build utm entitet static::compileUtmEntity($entity, $uField); ) ) return EntityBase::getInstance($entity_name); )

    Kvragu s tim, ali ti isti highload blokovi ni na koji način ne mogu djelovati kao alternativa običnim informacijskim blokovima. Ispostavilo se da su izmišljeni samo za pohranu nehijerarhijskih referentnih podataka. Osim toga, modul još uvijek ne podržava tako potrebne funkcije u administratorskoj ploči, kao što je filtriranje po polju kao što je "Datum", nemoguće je nazvati entitet HLblock nekim ljudima razumljivim imenom kako se administrator ne bi uplašio svaki put kada ulazite na stranicu za uređivanje entiteta, na primjer, BrandReference. Sve to sugerira da je ova stvar zamišljena kao alternativa sporim informacijskim blokovima, ali nisu je stigli dovršiti (ili nisu uspjeli, ili je išlo protiv interesa biznisa), te su na kraju pustili polugotovu funkcionalnost kao novu značajku, a trgovci su je pročešljali i učinili da izgleda lijepo došli su na ovu ideju.

    C - Kontroler, odnosno komponenta

    Obična komponenta u Bitrixu može se usporediti s widgetima iz Yii. Ovo je određeni spremnik, odvojen od svih ostalih spremnika, koji uzima neke parametre kao ulaz, obavlja određeni posao i s rezultatom rada povezuje pogled. Programeri Bitrixa duboko su uvjereni da komponente koje isporučuju odmah rješavaju većinu problema s kojima se susreću njihovi kolege. Ali, kao i obično, programerima se uvijek ništa ne sviđa, a mogućnosti standardnih komponenti uvijek "malo" nedostaju. Stoga je Bitrixoids odlučio dati programerima priliku da modificiraju rezultat komponente... pomoću prikaza. U direktoriju predložaka komponente možete stvoriti datoteku result_modifier.php, u koju možete dodati vlastite podatke rezultatu komponente. A ako iznenada želite koristiti ove podatke u drugom predlošku, morat ćete kopirati i zalijepiti ovu datoteku (ili uključiti ovu datoteku iz drugog predloška). Oduvijek me mučilo pitanje - čemu taj patos? Zašto ne biste dodali hrpu zahtjeva izravno u PHP predložak? Ispostavilo se da je razlika mala.
    Što ja pričam o predlošcima u odjeljku o kontrolerima...

    Bitrix ima 2 vrste 2.0 komponenti (opet pozdrav marketingu) - obične i složene. Uobičajena komponenta je widget. Složena komponenta je neka vrsta kontrolera + usmjerivača, koji na temelju URL-a razumije koju stranicu sa skupom widgeta treba prikazati. Radni postupak je otprilike sljedeći:

    • url kaže /catalog/bolshaya-zelenaya-shapka.html
    • koristeći mod_rewrite, Bitrix razumije da za fizički odjeljak /catalog uvijek morate uključiti datoteku /catalog/index.php
    • složena komponenta analizira URL i razumije da trebate povezati detaljnu stranicu proizvoda, nazovimo to detaljima
    • složena komponenta skuplja parametre koji su potrebni za rad njenih podređenih komponenti
    • složena komponenta povezuje svoj predložak detail.php, unutar kojeg je navedena veza podređenih regularnih komponenti

    Ne izgleda baš lijepo, ali može funkcionirati. Međutim, nije sve tako jednostavno... Ako promijenite parametre složene komponente pomoću vizualnog editora, datoteku s postavkama adresiranja (urlrewrite.php) sustav će prebrisati. Štoviše, ako ste tamo iznenada napisali nešto netočno za druge stranice, nešto će se sigurno pokvariti bez ikakvog upozorenja. U praksi to može dovesti do gubitka funkcionalnosti cijelih dijelova stranice.
    Postavljanje parametara složene komponente može biti naporan posao. Jedna takva komponenta lako može imati stotine ulaznih parametara, jednostavno zato što je potrebno konfigurirati parametre podređenih komponenti.
    Složena komponenta - čini se da je usmjerivač. Međutim, sve rute koje stvorite u ovoj komponenti neće biti uključene u automatski generirani sitemap.xml. Ove veze neće biti uključene u modul pretraživanja. Nećete moći generirati adresu rute izvana (na primjer, želite staviti poveznicu na detaljnu stranicu robne marke negdje na bočnoj traci i nećete moći tražiti od usmjerivača da generira ovaj URL ).

    Općenito govoreći, nitko zapravo ne obavlja funkcije usmjerivača u Bitrixu. U infoblokovima možete konfigurirati URL predložak za stranicu infobloka, stranicu odjeljka infobloka i stranicu elementa infobloka. To je to, infoblokovi više ne mogu imati stranice.
    Za forume je moguće prilagoditi predloške nekih stranica. Može se prilagoditi za blogove. Možda se nešto može konfigurirati negdje drugdje... sve je to toliko decentralizirano da postaje prilično teško sve to spojiti.

    Redovne komponente su nešto jednostavnije cjeline od složenih komponenti. Njihov zadatak je uzeti skup parametara kao ulaz, obraditi ih, unijeti rezultat rada u predložak i sve pohraniti u predmemoriju.
    Sva logika komponente sadržana je u datoteci component.php. S verzijom 12 Bitrixa (trenutno je aktualna verzija 16, prošle su 4 godine), postalo je moguće "koristiti OOP" u komponentama. Ova inovacija je da umjesto komponente.php datoteke, možete kreirati datoteku class.php, u koju, umjesto uobičajenih rezanaca, možete napisati klasu naslijeđenu od CBitrixComponent. I ovo je bio veliki korak naprijed, jer... postalo je moguće naslijediti komponente i uopće ne koristiti result_modifier.php, i ne prakticirati copy-paste ako iznenada trebate jako prilagoditi komponentu. Ali ni ovdje još uvijek nije sve tako dobro. Od cjelokupnog skupa komponenti, samo 25-30 posto može se pohvaliti da ima klasu u svom arsenalu. Štoviše, dobra polovica njih jednostavno vam neće dati priliku da se potpuno proširite, jer... Često su napisani nelogično.
    Usput, dobri ljudi pokušavaju standardizirati, nekako pomoći programerima da napišu komponente, a postoji i odgovarajući alat

    V - Pogled, odnosno predlošci

    Predlošci u Bitrixu mogu se podijeliti u nekoliko vrsta:

    • Obični i složeni 2.0 predlošci komponenti
    • Predlošci web stranica
    • Predlošci za druge entitete (pošta, bilteni, web obrasci, generatori izvoza i još mnogo toga)

    Predlošci komponenti čak imaju mogućnost korištenja pokretača predložaka. U načelu, možete spojiti bilo koji predložak, ali nema pomoćnih alata izvan kutije. Ako nekom treba, imam par linkova na nastavke za twig i blade, koji rade i dosta se koriste u proizvodnji. Ali i ovdje su Bitrixoidi postali izopačeni. Predložak se može koristiti samo s komponentama. Neće biti moguće povezati mehanizam predložaka s prikazivačem predložaka web stranice ili drugim entitetima jer tamo nema renderera.

    Još jedna neugodna stvar kod predložaka komponenti je njihov položaj. Komponenta je povezana pomoću jednostavnog dizajna

    $APPLICATION->IncludeComponent("bitrix:catalog.section", "template_name", );

    Drugi parametar je naziv predloška komponente. Dakle, ovisno o različitim uvjetima, lokacija ovog predloška može biti na najneočekivanijim mjestima:

    • bitrix/komponente/bitrix/katalog.odjeljak/predlošci/naziv_predloška
    • local/components/bitrix/catalog.section/templates/template_name
    • bitrix/templates/.default/components/bitrix/catalog.section/template_name
    • bitrix/templates/site_template/components/bitrix/catalog.section/template_name
    • local/templates/.default/components/bitrix/catalog.section/template_name
    • lokalno/templates/site_template/components/bitrix/catalog.section/template_name
    • bitrix/komponente/bitrix/katalog/predlošci/.default/bitrix/katalog.odjeljak/ime_predloška
    • local/templates/site_template/components/bitrix/catalog/.default/bitrix/catalog.section/template_name

    A nisam još nabrojao sve mogućnosti...

    Predložak stranice može se smatrati skupom datoteka: header.php, footer.php (da, stranica ih mora imati), description.php (opis sustava predloška stranice), template_styles.css (stilovi predloška stranice), direktorij s predlošcima komponenti i druga skupina manje značajnih datoteka. To je sve. I na to ne možete utjecati ni na koji način, ne možete ništa učiniti. Nemoguće je pokupiti predložak motora.

    Nema se što reći o drugim predlošcima. Oni su ili jednostavno pohranjeni u bazi podataka u obliku izgleda s nekim "varijabilnim" podacima uključenim u njega, ili je to glupa PHP datoteka koja obavlja sav posao, od dohvaćanja parametara iz baze podataka do prikazivanja informacija. Na primjer, možete pogledati YML generator datoteka za tržište. Nema smisla postavljati ga ovdje, jednostavno zato što je prilično velik, oko 2k redaka. Kome treba neka gugla, ima u /bitrix/modules/catalog/load/yandex_run.php

    Priroda datoteke

    Kao što je gore postalo jasno, u Bitrixu arhitektura nije baš dobra. Ali Bitrix također ima još jedan važan aspekt svoje arhitekture.
    Bitrix je CMS s pola datoteke. Puno stvari se kontrolira pomoću nekih datoteka:

    • Trebate stranicu - napravite datoteku
    • Trebate skup stranica - izradite datoteku i tamo povežite komponentu koja radi s infoblokovima
    • Morate postaviti naslov za stranicu - uredite datoteku
    • Morate postaviti naslov za sve stranice odjeljka - stvorite posebnu datoteku.section.php u korijenu ovog odjeljka
    • Morate urediti prava - uredite datoteku .access.php
    • Postavke prije inicijalizacije sustava - u datoteci dbconn.php, .settings.php i .settings_extra.php
    • result_modifier.php, component_epilog.php, init.php, .parameters.php, .description.php ....

    I postoji ogroman broj takvih posebnih datoteka razasutih po Bitrixu. S jedne strane, to daje određenu fleksibilnost u radu sa sustavom. S druge strane, to se može pretvoriti u muku i za programera i za upravitelja stranice. Datoteke stranica ponekad se pretvore u zbrku PHP koda, izgleda i komponenti dodataka. Kao rezultat toga, vizualni uređivač može netočno analizirati ovu datoteku, a prilikom uređivanja može lako izbjeći PHP oznake na nekim mjestima, što će dovesti do toga da stranica ne radi. Kažete - nema potrebe pisati PHP kod u takve datoteke? Da znam. Ali Bitrix vas vrlo često i bez alternative prisiljava na to.
    A u glavi morate stalno imati informacije o tome kakve su datoteke i koje podatke mogu sadržavati. Različite datoteke trebaju sadržavati različite podatke s različitim strukturama i morate ih zapamtiti za svaku opciju. Traženje ovoga u dokumentaciji svaki put je težak posao.

    Pored navedenog

    Možete se beskrajno žaliti kako sve loše radi u Bitrixu. Po mom mišljenju, sve te pritužbe mogu se okarakterizirati jednom frazom - "nekako ne u potpunosti". I doista, ako Bitrixoids iznenada najave neku značajku, onda je nekako ne puste u potpunosti, ne dovrše je, ne dovedu je na pamet. Ima dosta primjera:

    • implementiran ORM - još nije dovršen, ne može se u potpunosti koristiti
    • Napravili smo autoloader, radi samo po modulima, a ne po standardima
    • omogućio je povezivanje mehanizma predložaka, ali ga ne možete koristiti svugdje, a ne u potpunosti
    • itd. i tako dalje.

    Ukratko, pokušat ću okarakterizirati preostale probleme s kojima se svakodnevno suočavam.

    Administrator

    Ako je netko radio s admin panelom, kreirao svoje stranice u administrativnom dijelu na način na koji Bitrix predlaže da se to radi, razumjet će me. To je jednostavno pakao. Za one koji nisu upućeni, Bitrix predlaže korištenje datoteke s rezancima za svaku stranicu. Na primjer, stranica za detaljan prikaz narudžbe u administratorskoj ploči koju su izradili programeri Bitrixa zauzima više od 4k redaka. Moj IDE počinje usporavati kada gledam sadržaj ove datoteke. Tu imate php, js i html. Dobro je da su se riješili SQL-a, iako sam siguran da ga ima na drugim administrativnim stranicama.
    A što je spriječilo administrativne stranice da rade koristeći iste komponente nije jasno. Jednostavno ne postoji način da prilagodite većinu administrativnih stranica. U slučaju komponenti, to se može učiniti u tren oka.
    Usput, dobri ljudi su napravili modul koji će vam pomoći u izgradnji administrativnih stranica

    js okvir

    Bitrix ima js komponentu koja djeluje kao neka vrsta klijentskog okvira. Nitko od programera ne voli to iz nekoliko razloga:

    • gotovo da nije dokumentirano
    • on je monstruozan
    • uvelike duplicira jquery koji je mnogima poznat

    Bitrix ga vrlo često koristi u svojim komponentama, što izaziva još više ljutnje među programerima. Jezgra ove biblioteke u umanjenom obliku iznosi 85 kb, što nije malo. Ne možete izbjeći njegovo povezivanje ako želite koristiti sve mogućnosti Bitrixa (kompozit, upravljanje imovinom).

    Copy-paste duh

    U posljednje vrijeme, sve rjeđe, ali ipak dosta često, Bitrix vas tjera da nešto kopirate i zalijepite. Ako želite izmijeniti rad komponente, kopirajte je i zalijepite. Ako želite izraditi vlastiti predložak za učitavanje, kopirajte i zalijepite sistemski i dovršite ga. Ako želite napraviti gotovo isti predložak koji imate, kopirajte ga i zalijepite te ga malo promijenite. O tome čak govore i na tečajevima za programere početnike. Nemam riječi.

    Upravljanje imovinom i CDN

    Jako mi se sviđa način na koji Bitrix upravlja resursima. U načelu je moguće registrirati skup specifičnih "knjižnica". Svaka biblioteka je skup css/js datoteka, koje mogu ovisiti o nekim drugim bibliotekama. Ako povežete biblioteku sa stranicom, tada će prije povezivanja sve ovisnosti biti razriješene i sve ovisne biblioteke bit će umetnute na stranicu. Čini se da je sve u redu, samo će svaki resurs biti umetnut kao zasebna datoteka u skriptu ili oznaku veze. I zahvaljujući tome, postoje stranice koje imaju 30-50 povezanih skripti i isto toliko stilskih datoteka.
    To je usrano pitanje, rekli su u Bitrixu i napravili čarobnu kvačicu koja spaja sve te datoteke u jednu. I pojavile su se stranice na kojima su umjesto 50 skripti bile 2, svaka od 300-500kb. Prije nekog vremena ovo je spajanje radilo s pogreškama i spajalo je iste resurse nekoliko puta, ali sada se čini da je to popravljeno.
    A onda im se Bitrixoids sklonio s puta - dodali su mogućnost učitavanja svih resursa na CDN poslužitelj. Koja uvijek otpadne...
    Zatim se pojavio Google Pagespeed Insights koji je preporučio premještanje svih resursa na dno stranice. A u Bitrixu su opet napravili čarobni checkbox koji glupo izostavlja sve resurse u tijelu ako nisu označeni posebnim atributom.
    Oni također distribuiraju minimizirane verzije svojih skripti zajedno s kutijom, koje se povezuju kada upotrijebite drugi čarobni potvrdni okvir na administratorskoj ploči.
    Općenito, nema scss za vas, nema TypeScripta. Ako želite kompetentno upravljati resursima, nemojte koristiti ugrađeni Bitrix sustav, koristite webpack koji se lako može upariti s Bitrixom.

    Više stranica/više jezika

    Ovo je vjerojatno najgora glavobolja za programera, koja traje od samog početka proizvoda. Ne možete jednostavno napraviti višejezičnu web stranicu. A ako trebate višejezični katalog s različitim cijenama i valutama, onda se to pretvara u brašno, za što također morate platiti urednu svotu (morat ćete izdvojiti za kupnju dodatne licence za sljedeću jezičnu verziju mjesto).
    Ako stvarate višejezičnu i viševalutnu web stranicu, budite spremni na činjenicu da će se Bitrix tome vrlo agresivno oduprijeti. Postavke za više stranica decentralizirane su kroz administrativnu ploču. Svaki entitet u administratorskoj ploči ima vlastitu ovisnost o jezičnoj verziji stranice. Neki entiteti možda uopće ne podržavaju ovisnosti o web-mjestu/jeziku, dok drugi imaju samo nedvosmisleno vezanje za jezik, tako da će se ovaj entitet morati duplicirati i zatim podržati.
    U osnovnoj verziji, da bi informacijski blok radio na nekoliko jezika, morat ćete stvoriti duplikat ovog informacijskog bloka. Ali u praksi nitko to ne radi i pokušava osmisliti vlastite načine centralnog pohranjivanja jednog entiteta, distribuirajući njegove atribute ovisne o jeziku u druge objekte za pohranu.
    Ne možete postaviti zadani jezik tijekom lokalizacije. Ako imate jezičnu varijablu koja opisuje neku frazu na ruskom, a ta jezična varijabla nije u engleskoj verziji, tada će na engleskoj stranici biti prikazan prazan redak i na to se ne može ni na koji način utjecati (u mnogim slučajevima možete ostaviti ruski izraz tako da nema praznina).

    Mehanizam upravljanja pravima

    Bili su vrlo pametni s ovim podsustavom. Često je teško dokučiti zašto ste nekom subjektu dodijelili prava gledanja, a korisnik ih ne može koristiti. Na primjer, da biste dali pravo uređivanja informacijskog bloka, morate dati pristup direktoriju /bitrix/admin, dodijeliti prava za određeni informacijski blok i dodijeliti prava u glavnom modulu. Potrebno je obaviti previše operacija za izdavanje prava za jedan entitet. A ako nema dovoljno prava, onda bez čeprkanja po izvornom kodu nema načina da shvatite zašto.

    Konfiguracija

    Bitrix nema centralizirano čvorište koje bi vam omogućilo upravljanje postavkama sustava. Postavke su ponovno decentralizirane u cijelom sustavu. Opcije su dostupne u postavkama modula, u postavkama komponente, u COption (nije postavljeno na administrativnu ploču). U admin panelu opcije za jedan modul mogu biti raspoređene na 3-4 različite stranice, koje se nalaze na potpuno različitim mjestima. urlrewrite se može uređivati ​​putem administratorske ploče! Sada i .settings i .settings_extra. Ponekad uopće nije jasno koje od njih imaju veći prioritet, vrlo često nema dovoljno objašnjenja opcija, a odnosi su nejasni. Ne postoji izvorni način dijeljenja konfiguracije između programera.
    Postavke mogu biti vrlo nelogične. Ponekad to dođe do točke apsurda... pogledajte bigdata komponentu - može li to neobučena osoba postaviti?

    Integracija s 1C

    Ovo je stavka na popisu značajki Bitrixa na koju pada prilično velik broj kupaca. Bitrix obećava da će postaviti dvosmjernu integraciju web mjesta s 1C u 2 klika, što će odmah isporučiti sadržaj i dokumente iz jednog sustava u drugi.
    Da, doista jest, ali uz nekoliko upozorenja.
    Prvo, da biste izvršili integraciju "iz kutije" bez dodatnog napora, morate učiniti sve točno onako kako je napisano u Bitrix dokumentaciji - izgraditi katalog na web mjestu prema pravilima koja Bitrix nudi i izgraditi katalog u 1C koje Bitrix zahtijeva. U idealnom slučaju, stvorite sve od nule, a onda će možda sve raditi za vas izvan okvira.
    Drugo, Bitrix nije kompatibilan sa svim 1C konfiguracijama izvan kutije. Prvo vrijedi provjeriti
    Treće, ne postoji idealan svijet. Tipično, kupac koji želi web stranicu već ima maloprodajni posao, što znači da već ima 1C, što je veliko smetlište. I ovo smeće treba baciti na mjesto. A kako se stranica ne bi pokazala kao isto smeće, mehanizam razmjene treba značajno poboljšati.
    Vrlo često se zahtjevi korisnika uvelike razlikuju od vizije proizvoda koju je Bitrixov tim formirao, a zatim usavršavanje mehanizma razmjene može biti prilično skupo, usporedivo u intenzitetu rada s razvojem jedinstvenog modula razmjene za određeni slučaj.
    Stoga se ne treba iluzirati da ćete svoju stranicu moći lako integrirati s 1C. Sve su to spletke trgovaca.

    Pročišćavanje razmjene s 1C također je zasebna tema. Klasa CIBlockCMLImport odgovorna je za organiziranje razmjene kataloga - 5.7k redaka. Jedna od glavnih metoda koja najčešće zahtijeva proširenje je CIBlockCMLImport::ImportElement, koja sadrži više od 1k redaka. Dovoljno je naslijediti ga jednom, ažurirati proizvod nekoliko puta tijekom dužeg vremenskog razdoblja i možete dobiti neradnu razmjenu s 1C. Stoga se programeri često ne zamaraju ovom klasom i pokušavaju nekako ući u proces uvoza pomoću rukovatelja događajima. Rad s rukovateljima događajima u Bitrixu, posebno u modulu infoblokova, također nije baš ugodno iskustvo, makar samo zato što događaji iste vrste nisu jednoobrazno raspoređeni, a neki događaji jednostavno nisu dovoljni.
    Općenito, stvari su tužne kao i prije.

    Nedosljednost

    Ponekad mi se čini da programeri različitih modula zapravo ne komuniciraju jedni s drugima. Kada proučavate izvorne kodove kernela, nailazite na vrlo heterogena rješenja koja bi se mogla implementirati na jednom motoru, ali su iz nekog razloga različito implementirana.
    Na primjer, možete uzeti svojstva elemenata bloka informacija i UserFields. Oba entiteta su zapravo dodatno polje za drugi entitet. Ima vrstu, značenje i opis. Vrijednost je pohranjena u zasebnim tablicama baze podataka; one imaju otprilike slično sučelje za pristup podacima. Pa zašto ne napraviti isto sučelje za njih?
    Krajem ožujka modul prodaje je ažuriran na najnoviju verziju, a obećali su i proizvoljna svojstva za narudžbe. Postoji li stvarno novo, treće sučelje za rad s proširenim svojstvima entiteta?

    Bitrix24

    Ovo je općenito posebna tema za raspravu. Često dolazi do zabune zbog ovog sustava. Postoje 2 opcije za B24 - SaaS i Standlone. Postoji tržište za B24, ali ono sadrži aplikacije samo za SaaS verziju! Ako imate verziju u kutiji, kupljenu za 200 tisuća, nećete moći instalirati tako popularne aplikacije kao što je dizajner dokumenata, i općenito nećete moći instalirati nijednu aplikaciju s tržišta za Bitrix24 na svoj Bitrix24. Ovo je takav paradoks.
    Umjesto toga, tržište iz redovne verzije bit će dostupno u vašem Bitrix24. Postoji mnogo više rješenja, ali ona su koncentrirana uglavnom oko Site Managementa, a ne B24.

    Bitrix24, kako su mi rekli u odjelu tehničke podrške, holistički je sustav. Ako ometate rad standardnih komponenti sustava, budite spremni da će ova funkcionalnost prestati s naknadnim ažuriranjima. Bitrix neće računati na to da ćete finalizirati komponente portala, i to unatoč činjenici da svoje klijente službeno upućuju na partnere

    Usput, modificiranje komponenti u verziji B24 u kutiji prilično je težak zadatak. Komponente koje generiraju js kod, koji pomoću ajaxa pristupa php kodu, koji kao odgovor generira html+js. Ovo je paklena mješavina u koju stvarno ne želite zaroniti.

    Dokumentacija

    Bitrix dokumentacija zaostaje za razvojem proizvoda 1-1,5 godina. Kod je vrlo slabo pokriven phpDocs, a često je komentar prije nastave samo za pokazivanje, automatski se generira u IDE-u.
    Sam stil prezentacije dokumentacije u službenim izvorima često je previše "slobodan", a sadržaj nekih članaka u dokumentaciji možda nema nikakve veze sa samim Bitrixom.
    Tečaj za programere ima puno informacija, ali format u kojem se programer upoznaje s mogućnostima sustava ne pruža razinu percepcije koja je potrebna. Ako odete u Symfony Cookbook, tamo je sve izloženo, svi potrebni aspekti opisani su ovisno o verziji. Dok u Bitrixu tečaj za razvojne programere sadrži, na nejasan način, strukturirane informacije o starim i novim kernelima, koje su prvo predstavljene odvojeno, a zatim pomiješane, što početnicima zadaje glavobolju.

    Organizacija procesa razvoja

    Zbog specifičnosti sustava nije lako organizirati prikladan razvojni proces. Ne posljednja verzija Business edition-a (koja je bila pri ruci) nakon instalacije zauzima, razmislite, gotovo 530 megabajta

    $ du -s *|sort -nr|cut -f 2-|while read a;do du -hs $a;done 523M bitrix 204K upload 64K bitrixsetup.php 56K desktop_app 20K readme.html 20K license.html 4.0K web . config 4.0K urlrewrite.php 4.0K readme.php 4.0K license.php 4.0K install.config 4.0K index.php

    Od ove količine, dobra polovica su binarne datoteke i instalateri, koji općenito nisu potrebni za kontrolu verzija. Općenito govoreći, uobičajeno je ne verzirati jezgru Bitrixa. Programeri Bitrixa sami jamče integritet jezgre i upravljaju ovisnostima verzija različitih modula tijekom ažuriranja. Ali to odmah nosi barem jedan veliki nedostatak - nemoguće je implementirati potpuno funkcionalan projekt s jednim timom iz kontrole verzija; morate ga sastaviti u dijelovima: izvore kernela nabavite iz sigurnosne kopije Bitrixa, a izvore programera iz git-a .
    Ni s bazom ne ide dobro. Ako sami možete koristiti migracije tijekom razvoja, tada Bitrix ubacuje ažuriranja u bazu pomoću običnih skripti koje ne možete kontrolirati. Stoga ćete prilikom ažuriranja i dalje morati prenijeti sigurnosne kopije baze podataka sa središnjeg razvojnog hosta drugim programerima.
    Dobri ljudi, opet, alati za rezanje pomažu organizirati sve ovo, ali nažalost još uvijek nije moguće prisiliti Bitrix da slijedi ova pravila.
    Službeno, Bitrix vam omogućuje da imate 2 kopije jedne distribucije. Jedan je za proizvodnju, drugi za razvoj. Ako imate nekoliko programera na jednom projektu, onda ste, takoreći, odmetnik) Zapravo, dovoljno je da stroju s Bitrixom prekinete dolazne i odlazne veze s/na www.bitrixsoft.com, a zatim mogu prikovati koliko god želite kopija razvoja, samo se neće moći ažurirati.

    Kolege

    I posljednje pitanje koje bih želio dotaknuti.
    Zbog činjenice da Bitrix ima niske barijere za ulazak, postoji mnogo nekvalificiranog osoblja među tvrtkama koje pružaju usluge na ovom tržištu. Tijekom svoje karijere vidio sam mnogo različitih projekata (ukupno više od stotinu) dovršenih na 1C-Bitrixu. Sa sigurnošću mogu reći da je 95% njih urađeno na “bagerski” način. Rijetko smo nailazili na projekte čiji je razvoj imao smisla za pristup, ali to su bili samo neki. Sve je ovo jako tužno.

    zaključke

    Naravno, svi nedostaci ne mogu se razmotriti u jednom članku. Svakodnevno nailazite na neke sitnice koje vas svakodnevno ometaju u radu. Ali jednostavno je nemoguće uzeti u obzir sve takve sitnice, a vjerojatno i nema potrebe.

    Kakvi se zaključci ovdje mogu izvući? Bitrix je izuzetno složen sustav zbog činjenice da ima loše zamišljenu arhitekturu i mnoge nedostatke koji nastavljaju živjeti u proizvodu dugo vremena. S druge strane, Bitrix je prilično jednostavan sustav koji zahtijeva puno nižu razinu kvalifikacija za početak, za razliku od okvira.
    Podrška ovom proizvodu je vrlo nezahvalan zadatak u usporedbi s proizvodima kao što su Symfony, Laravel, Yii. Proizvod doista voli ubaciti žbice u kotače i neiskusnim i iskusnim programerima, što se pak može odraziti na cijenu usluga iskusnih Bitrix programera.

    Žalim li što sam proveo toliko vremena radeći s ovim sustavom? Radije da nego ne. Bilo bi mudrije da ovo vrijeme provedem proučavajući nešto ispravnije i logičnije (što sada aktivno pokušavam). Ali slučajno se dogodilo da na početku mog puta nije bilo nikoga tko bi me uputio u pravom smjeru.

    Ako ste PHP programer početnik, radije ćete proučavati okvire kao što su Symfony, Laravel, Yii, ZendFramework nego Bitrix. Vjerujte mi, to će vam se više nego isplatiti u budućnosti. Nakon što ste svladali bilo koji od ovih okvira, neće vam biti teško razviti nešto za Bitrix u budućnosti. Ako nemate izbora, proučite Bitrix, ali u slobodno vrijeme bolje je ipak pokušati uroniti u svijet okvira kako biste stavili svoj mozak na mjesto.

    Ako ste programer s iskustvom u Bitrixu, ali bez iskustva u drugim okvirima, onda svakako uronite u drugi svijet; otkrit ćete puno novih i korisnih znanja koja će vam pomoći da napišete mnogo bolja rješenja za 1C-Bitrix. Pokušajte koristiti rješenja iz drugih okvira u svojim projektima, srećom to nije teško učiniti zahvaljujući komponentnom pristupu potonjeg i skladatelja.

    Ako ste kupac, nemojte vjerovati trgovcima Bitrixa. Ništa neće biti tako lako kao što kažu u Bitrix prezentacijama. I nemojte kriviti svoje programere za ovo, oni nemaju ništa s tim. Ako želite napraviti veliku i složenu online trgovinu na razini Eldorado/Mvideo/Sportmaster, Bitrix možda nije najbolji izbor.

    Često je tijekom razvoja potrebno odabrati i obrisati dio podataka označenih za brisanje. Ova potreba posebno utječe na velike baze podataka s desecima ili stotinama tisuća objekata označenih za brisanje. Obrada svih podataka odjednom traje jako dugo, tako da je bez praktičnog alata u kojem možete pregledno pregledavati, selektirati i brisati neki dio podataka to nemoguće.

    Ova obrada je rezultat mog rada u određenom vremenskom razdoblju. Funkcionalnost je po potrebi proširena. Obrada radi u uobičajenom načinu rada aplikacije iu debelom klijentu upravljane aplikacije. Implementirano u obradi:

    • prikazivanje stabla metapodataka s mogućnošću označavanja onih objekata baze podataka koje je potrebno izbrisati;
    • prikazivanje broja objekata označenih za brisanje, označenih od strane korisnika i mogućih za brisanje;
    • mogućnost uključivanja/isključivanja ekskluzivnog načina rada;
    • moguće je brisati povezane evidencije samostalnih informacijskih registara;
    • mogućnost grupne zamjene pronađenih poveznica;
    • prikazivanje veza na objekt koji se briše u obliku stabla. Odraz u ovom stablu strukture cikličkih (rekurzijskih) veza, isticanje ključnih veza (koje sprječavaju brisanje objekta);
    • brisanje paketa cikličkih poveznica u transakciji - “ili sve ili ništa”, tako da “Object not found...” u bazi podataka;
    • mogućnost proizvoljnih upita odabira za svaki objekt metapodataka. U tom slučaju zahtjevi za odabir mogu se kopirati. Ovo je korisno, na primjer, kada trebate izbrisati dokumente za određeno razdoblje za organizaciju; ili referentne knjige o bilo kojem kriteriju odabira;
    • očuvanje i restauracija prethodno korištenih odabira;
    • indikator napredovanja pri traženju objekata označenih za brisanje i praćenje referencijalnosti uz mogućnost prekidanja operacije.

    Za pružanje ove funkcije obrada aktivno koristi RAM. I, iako su poduzete mjere za optimalno korištenje RAM-a, u nekim slučajevima (velike baze podataka, veliki broj izbrisanih objekata) može doći do situacije s nedostatkom memorije. U takvim slučajevima potrebno je ograničiti popis objekata za brisanje ili prijeći na korištenje 64-bitnog 1C klijenta.

    Najnovija verzija 1.14. Promjene:

    • Kašnjenja u prijelazima klijent-poslužitelj na velikim količinama podataka su smanjena;
    • Poboljšana logika za konfiguracije s kontnim planovima bez dodijeljenih vrsta podračuna .

    Verzija 1.13. Promjene:

    • Ispravljena plutajuća pogreška postupka obrasca pri pokušaju brisanja;
    • U redovnom obliku dodana je mogućnost označavanja srodnih poveznica za brisanje. Da biste označili za brisanje, odaberite jedan ili više redaka povezanih veza i odaberite "Označi za brisanje" iz kontekstnog izbornika. Blok povezanih veza prikazuje stablo. Kada odaberete red u stablu i pozovete oznaku za brisanje, elementi svih podređenih redaka označavaju se za brisanje.
    • U redovnom obliku dodana je funkcija "Prikaži na popisu" povezanog stabla veza.

    Obrada verzije 1.12. Promjene:

    • Ispravljena je nekritična pogreška u uobičajenom obliku koja se javlja prilikom ažuriranja prikaza povezanih veza.

    Obrada verzije 1.11. Promjene:

    • Ispravljena je pogreška u bojanju povezanih ključeva unosa registra informacija.

    Obrada verzije 1.10. Promjene:

    • Vraćen je mehanizam djelovanja opcije „Brisanje evidencije informacijskih registara“. Ova funkcionalnost sada se odnosi na zapise informacijskih registara u kojima objekt koji se briše nije glavni. Zapisi s vodećim izbrisanim objektom automatski se brišu;
    • Onemogućeno snimanje/brisanje s oznakom Data Exchange.Loading;
    • U stablu veza dodan je prikaz atributa "Posted" i "Deletion Flag" za povezane objekte. U normalnom obliku - u obliku slike linija, u upravljanom obliku - u obliku potvrdnih okvira.

    Obrada verzije 1.09. Promjene:

    • Ispravljena je tipfelerska pogreška u algoritmu prilikom kontrole referencijalnosti vlasničkih imenika;
    • Promijenjen je dio koda za upravljani obrazac koji nije dopuštao njegovo pokretanje na jednoj od standardnih konfiguracija;
    • Dodana kontrola nad standardnim tabličnim dijelovima konfiguracijskih objekata.

    Obrada verzije 1.08. Promjene:

    • Implementiran posao obrade u debelom klijentu upravljane aplikacije.

    Obrada verzije 1.07. Promjene:

    • Implementiran je mehanizam praćenja/zamjene referenci za izvanbilančne dimenzije knjigovodstvenih registara.

    Obrada verzije 1.06. Promjene:

    • Onemogućeno je brisanje stabla metapodataka nakon pretraživanja - sada se stablo metapodataka uvijek prikazuje;
    • Dodan mehanizam zamjene veza.
    • Dodan prikaz ukupnog broja objekata u bazi podataka;
    • Mehanizam brisanja je prebačen u način rada za razmjenu podataka Loading = True;
    • Opcija "Brisanje unosa u registar detalja" sada radi za vodeće i nevodeće dimenzije.

    Pomoć za obradu promijenjena:

    Obrada se sastoji iz dva dijela: Stablo izbrisanih objekata (3) I Stablo veza (4) na objekt koji se briše.

    U stablu izbrisanih objekata vrše se osnovne postavke za traženje izbrisanih poveznica. Stablo poveznica analizira one koje se odnose na izbrisane

    objekt drugi objekti informacijske baze.Obrada se kontrolira pomoću Izbornik osnovnih radnji (1), oznake u stablu

    objekti koji se brišu i Izbornik dodatnih funkcija (2)

    1. Izbornik osnovnih radnji

    -Čisto- inicijalizira stablo metapodataka objekata, briše prethodno dobivene rezultate;

    -Pronaći- traži objekte baze podataka označene za brisanje pomoću označenih objekata. Pretraga se vrši pomoću imenika,

    Dokumenti, kontni planovi, planovi vrsta obilježja, planovi vrsta obračuna, planovi razmjene, zadaci, poslovni procesi;

    -Zamjena- zamjenjuje obrisani link onim navedenim u stupcu "Zamjena". Kod zamjene referenci u detaljima upisati dimenzijemože doći do situacije

    Kada rezultirajući skup sadrži duplicirane retke duž dimenzija, u takvim se situacijama duplicirani retci brišu. U ovom slučaju, prednost se daje retku s najmanjim brojem u redoslijedu.

    -Kontrolirati- prati referentnu prirodu pronađenih objekata baze podataka označenih za brisanje. Kontrola se provodi prema detaljima, mjerenjima,

    Resursi objekata metapodataka, detalji tabelarnih dijelova objekata metapodataka, vrste obračuna obračunskih registara, konti i analitika računovodstvenih registara,

    Vodeći zadaci poslovnih procesa,mjerenja niza dokumenata.

    -Izbrisati- briše označene objekte koji se mogu brisati.

    2. Izbornik dodatnih funkcija

    -Odabiri- podizbornik s operacijama za odabir stabla objekata (dalje).

    -Brisanje unosa u registru informacija- omogućiti/onemogućiti način brisanja srodnih zapisa samostalnih informacijskih registara.

    -Prikaz popisa izbrisanih- kada je ova opcija uključena, pri brisanju će se u porukama sustava prikazati popis obrisanih objekata;

    -Monopol način rada- omogućiti/onemogućiti isključivi način rada baze podataka;

    -Pronađite i uklonite- na odabranim objektima metapodataka izvode se tri radnje u nizu: pronađi - kontroliraj - izbriši.

    3. Stablo objekata

    U svom početnom stanju predstavlja potpuni popis objekata metapodataka.Za te objekte potrebno je postaviti oznake

    među kojima će se tražiti oni označeni za brisanje.

    Izvođenjem pretraživanja u stupcu stabla " Ukupno"Broj pronađenih objekata označenih za brisanje bit će prikazan u stupcu" Ukupno poveznica" prikaz

    ukupan broj veza ove vrste objekta.

    Izvođenjem kontrole u stupcu stabla " Moguće brisanje" će prikazati broj objekata koji se mogu izbrisati.

    Stabla su obojena zeleno ili crveno ovisno o mogućnosti brisanja pronađenih objekata. Redovi koji sadrže informacije označeni su plavom bojom

    Pomoću kontekstnog izbornika stablo se može sortirati željenim redoslijedom.

    Funkcije grupnog postavljanja/isključivanja rade na odabranim linijama stabla.

    Potvrdni okvir " Ocjena" se koristi i kod traženja objekata označenih za brisanje, i kod praćenja referencijalnosti i zamjene poveznica.

    U kolumni " Izbor"Za grupe objekata možete navesti prilagođeni upit za dodatno filtriranje objekata pronađenih za brisanje.Dvaput kliknite na stupac "Odabir".

    otvara prilagođeni obrazac zahtjeva

    Prilagođeni zahtjev omogućuje vam primjenu dodatnog filtra prilikom odabira objekata označenih za brisanje.

    Konačni odabir iz zahtjeva mora sadržavati polje pod nazivom " Veza", ovo će polje biti polje filtra.

    U obrascu konstruktora zahtjeva (7) :

    -Čisto- briše trenutni zahtjev;

    -Zadano- generira novi zahtjev na temelju tipa podataka trenutnog objekta;

    -Dobiti parametre- ažuriranje liste parametara iz zahtjeva

    Upiti za filtriranje mogu se instalirati samo na razini 2. grupiranja stabla izbrisanih objekata, tj. na razini odjeljka metapodataka.

    4. Stablo povezanih veza

    Kada aktivirate liniju u stablu objekata, stablo veza prikazuje hijerarhijsku strukturu pronađenih veza na objekt koji se briše.

    Kada se otkrije kružna referenca objekata u strukturi stabla, trenutni objekt koji je uključen u kružnu referencu je

    prikazivat će se opetovano i završavati u cikličkom referentnom stablu.

    U redovima ovog stabla veze koje se ne mogu izbrisati ili nisu izbrisane prema trenutnim postavkama označene su crvenom bojom;

    koji ne dopuštaju konačno brisanje trenutnog objekta.

    Dvostrukim klikom na retke ovog stabla moguće je vidjeti pridruženu vezu.

    5. Kontekstni izbornik stabla objekata

    Kontekstni izbornik stabla objekata radi prema odabranim linijama stabla.

    Dostupne akcije:

    -Postavite/poništite oznake- postavlja/odznačava odabrane drvorede, uključujući podređene vodove;

    -Sortiranje uzlaznim/silaznim redoslijedom- upravljanje sortiranjem drvoreda;

    -Očisti odabir- (tipkovnički prečac Ctrl-X ) upiti filtera podataka brišu se u odabranim redovima stabla;

    1. Koji se informacijski sadržaj može postaviti na web stranice?

    Korisnici
    + Tijek studija
    + Informacijski blokovi
    + Oblici

    2. Kada koristite sustav s više mjesta

    + uobičajeni proračuni korisnika koriste se za sve stranice
    - za svaku stranicu kreiraju se zasebni proračuni korisnika

    Trebate dobru struju? Najprije ga morate naučiti kontrolirati, a PKE mjerni uređaj to može savršeno. Energetski ispitivač PKE-A-S4 omogućuje energetski pregled, mjerenje i registraciju količina električne energije, potrošnje električne energije, profila opterećenja i mjerenje opterećenja sekundarnih krugova.

    3. Ako prilikom postavljanja stranice ne navedete naziv stranice u odjeljku "Parametri", tada

    + sustav će koristiti naziv stranice naveden u postavkama glavnog modula
    - koristit će se vrijednost navedena u parametru "Ime" u odjeljku glavnih postavki
    - vrijednost neće biti definirana

    4. Broj mjesta u sustavu

    + određeno licencnim ugovorom i licencom za dodatne stranice
    - ovisi o broju jezika sučelja u sustavu
    - neograničeno

    5. Konfiguriranje jezičnih postavki za javni dio stranice provodi se:

    U obrascu za uređivanje parametara korijenskog direktorija stranice
    - u obliku stvaranja/uređivanja jezika
    + zasebno za svaku stranicu u obliku izrade i uređivanja stranice

    6. Mogu li konfigurirati više od dvije stranice u konfiguraciji s više stranica?

    + Možete ako kupite dodatne licence za dodatna mjesta
    - Ne, to je zabranjeno licencnim ugovorom
    - Da, bez ograničenja

    7. Prilikom aktivacije licence za 4 dodatne stranice (pored dvije dostupne za korištenje prema zadanim postavkama), može se koristiti sljedeći broj kopija jezgre sustava:

    3
    - 6
    + 1
    - 2

    8. Prilikom pregledavanja strukture datoteke, podjela po stranicama će se izvršiti u sljedećim slučajevima:

    Organizacija s više stranica na jednoj domeni
    + logički prikaz strukture
    + organiziranje više stranica na različitim domenama

    9. Koriste se tehnologije za prijenos korisničkih kolačića između stranica

    + ako je u postavkama glavnog modula aktivirana opcija "Distribuiraj kolačiće na sve domene".
    - uvijek ako u sustavu postoji statistički modul
    - ako je aktivirana opcija "Proširi autorizaciju na sve domene".

    Postavite odgovarajuću opciju u postavkama web mjesta
    + označite odgovarajuću opciju u postavkama glavnog modula
    - postavite odgovarajuću opciju u postavkama Grupe korisnika

    11. Kako možete zatvoriti samo jednu stranicu s identifikatorom ru za posjetitelje?

    Pomoću gumba: Postavke -> Glavni modul -> Servisne procedure -> Zatvori pristup za posjetitelje
    + postavljanje posebnog programskog koda u datoteku: /bitrix/php_interface/ru/init.php

    12. U postavkama kojih modula možete odvojiti parametre za različite stranice?

    Nijedan dopustiti
    - Modul Web Forms, Document Flow, Structure Management modul
    - Online trgovina, Blog modul, Glavni modul
    - Svi dopuštaju
    + Modul za blog, Modul za upravljanje strukturom, Internet trgovina

    13. Za stvaranje dodatnih stranica u sustavu osim onih dopuštenih u licenci, morate:

    Stvorite dodatni jezik sučelja
    - kreirajte račun u sustavu, kreirajte poseban poddirektorij
    + dobiti licencu za dodatnu stranicu, kreirati račun u sustavu, odrediti put do datoteka javnog dijela stranice

    14. Je li moguće razdvojiti prava za pregled statistike različitih stranica u proizvodu:

    Da, ako napravite odgovarajuće postavke pristupa u modulu Statistika
    + Ne, korisnik koji ima pravo pregleda statistike moći će vidjeti statistiku za sve stranice

    15. Zasebno za svako mjesto možete postaviti sljedeće postavke za modul Upravljanje strukturom:

    + postaviti vrste svojstava
    - organizirati sustav pristupa odjeljcima za svaku stranicu
    - odaberite vizualni HTML uređivač i njegove postavke pojedinačno za svaku stranicu
    + postavite vrste jelovnika
    + definirati broj dodatnih opcija izbornika

    I što kažu, ovi glasovi. Jedan i. Isto: Ja sam prodavač, ja sam prodavač. Što ćeš učiniti. Što možeš učiniti. Da, Hidra luk u Rusiji 2016. A to znači da Bull Gates ne uspostavlja kontakt. Ne radi. Ili možda dolazi. Ali ti ne razumiješ. Možda je Minotaur onaj mrtvi štakor na stropu. . Možda.

    I ništa ti nisu objasnili. A to znači poseban postupak. Pa sam otišao u mraku. Jadne koze... Ma, nema veze, skužit ćemo to i kazniti krivce. Bit će za njih nigella sativa svijeće upute, trinaesta plaća u čvrstoj valuti... Podigao ju je. Stavila sam na stol bilježnicu s profilom Dantea Alighierija na koricama i neko vrijeme se koncentrirala olovkom na papir i odmah sam pogodila da unutra crta iste Danteove profile, samo male. Iz nekog razloga ti ljudi misle da tijekom dugog dvadesetog stoljeća nigella sativa svijeće upute nisu proučavali njihove metode rada. Odloživši blok za pisanje. Zakoračio je prema meni, kao da će svojim zakašnjelim zagrljajem zaliječiti sve moje duševne rane, ali tada je zazvonio telefon na njegovom stolu. Shmyga je opsovao i podigao slušalicu. Osluškivao je nekoliko sekundi, a onda mu je lice postalo sumorno i pozorno. Da gospodine, . Rekao je i poklopio. Podigavši ​​pogled prema meni, podigao je ruke s osjećajem krivnje. Vidi što se događa.

    Poslovna tajna. Mornari nemaju pitanja”, odgovorio je Maljuta. Stepa ga je čudno pogledao. Točno tri sata kasnije nazvao je kapetan Lebedkin. Zašto ti treba moj život? Spremljeno? - upitao je prijeteći. - Pa da se baviš politikom. Ja... - počeo je Styopa. "Ne pišaj", rekao je kapetan veselo. - Šalim se.

    Želja. Onda samo naprijed, . reče Čapajev ustajući s leđa ecstasy hotel. Izašavši iz stožernog vagona, otišli smo u stražnji dio vlaka. Ono što se događalo činilo mi se sve čudnijim. Nekoliko vagona pored kojih smo prošli bili su mračni i činilo se da jesu. Prazan. Nigdje nije bilo svjetla; Iza vrata se nije čuo nijedan zvuk. Jedva sam mogao povjerovati u to iza ploča od orahovine u čijoj se ulaštenoj površini zrcalio svjetlo Čapajevljeve cigare. Crveni vojnik spava, ali pokušao sam ne razmišljati o tome.

    Do 2003. japanski stručnjaci. Bilo je moguće razviti skup od nekoliko mikrosondi koje vape hidra izravno mozak i omogućio, donekle, objektiviziranje slike ljudske percepcije. Japanska oprema nije mogla utvrditi što točno osjeća i misli promatrana osoba. Ali omogućio je dobivanje slike u boji (iako mutne) onoga što je on vape hidra. I ne samo u stvarnosti, već iu brzoj fazi sna. To je postalo moguće jer signal nije uzet iz optičkog živca, već iz tih zona. Mozgovi koji su odgovorni za izravnu reprezentaciju. Opremu je odmah nabavio tim Potashinskog. Signal iz skupa sondi ugrađenih u mozak mogao bi se prenositi bežično. Veze koje su omogućile bablonautu da vodi normalan život, ni na koji način ograničen sudjelovanjem u eksperimentu. Bilo je potrebno samo da se negdje u blizini nalazi prijemnik signala. Koja je zatim u stvarnom vremenu prenosila informacije na računalo. Ukratko, shema pokusa Potashinskog izgledala je ovako: Najprije je u mozak bablonauta-eksperimentatora usađen set kontrolnih elektroda (za ovu ulogu dobrovoljci su, kao i obično, odabrani među mladim službenicima FSB-a).

    S mrtve točke. Slušaj, brate, rekao je, kakva je ovo priroda? O čemu ti pričaš? - upita Isa. Pa, rekao si u autu da tijelo od šrapnela ima istu prirodu kao ono duginog. A kakva je ovo priroda? Bolje ne pitaj o ovome. Brate,” Isa se namrštila. Zašto. Još nisi spreman za ovo. Kako nije spreman. A amfetamin marihuana u isto vrijeme. Da sam spreman, ne bih pitao. Dakle, možete odgovoriti. Ili.

    Uskoro. pitao. Kupi hašiš u Vladivostoku sad, rekoh, evo... Netko drugi je izbirljiv. Ljubavnik bi se mogao uvrijediti što mu nije dopušteno dalje od mrežnog hodnika. Ali Porfirije nije takav. Prvo što sam napravio bilo je spajanje na njezine ogmentne naočale. Dobro, rekla je. Kakvi zalisci... U međuvremenu, ja stavljam sliku naočala na ploču. Preoblikujući ga pogledom sa stropne kamere. Ifak ​​je podigao sve morfe bez naprezanja svoje moći. Bilo je monstruozno. Sada me Mara vidjela u svojim ogmentnim naočalama na mjestu aifaka i ujedno mogla promatrati.

    Razvijena šifra. Ponekad bi primijetio da ga ponovno muče snovi koji se ponavljaju prema shemi 1. Ili prema shemi 2. I odjednom, otvorenim tekstom, poput krika koji bježi: Sanjao mješavine za pušenje 24 sata dnevno, ubio me u djetinjstvu... Glas iza paravana. Zašutio je. Što ona radi? - upitao je Sam. "Zaspala sam", odgovorila je Natasha. Sam je nježno pomilovao bodljikavi vrh njezina trbuha i zavalio se na sofu. Natasha je tiho progutala. Sam je povukao kutiju na podu prema sebi, otvorio je i izvadio malu staklenu kutiju. Staklenka, pljunuo je crveno u nju, zeznuo je i bacio natrag - cijela ova operacija ga je odvela mješavine za pušenje danonoćno sekundi "Znaš, Natasha", rekao je.

    Nakon toga on hašiški svetac Hej, Tatarsky. Nema odgovora. Tatarsky je pričekao još minutu i shvatio da je ostao sam. Sam s umom spremnim da podivlja. Hitno sam se morala nečim okupirati. Nazovi, šapnuo je. - Kome. Gireev. On zna što mu je činiti. Dugo vremena. Nitko se nije javljao na telefon. Napokon, na petnaesto ili dvadeseto zvonjenje, Gireev je turobno odgovorio: Zdravo. Andryusha.

    Ne, rekao je. U zaključanoj sobi sjedi čovjek koji ne zna kineski. Kroz prozor mu daju ceduljice s pitanjima na kineskom. Za njega su to samo papirići na kojima su iscrtane vijuge čije značenje ne razumije. Ali njegova je soba puna raznih knjiga. Pravila koja detaljno opisuju kako i kojim redoslijedom odgovarati samo vijugama. I on, postupajući u skladu s tim pravilima, daje odgovore na kineskom u drugom prozoru. Oni stvaraju potpuno povjerenje kod svakog tko stoji vani da zna kineski. Iako on sam uopće ne razumije o čemu ga pitaju. Preglednik adresa hydra onion Koje je značenje njegovih odgovora? Predstavljeno. Pa ja sam ga predstavio. Sura je ista kineska soba, samo automatizirana. Umjesto osobe s referentnim knjigama, tu je skener koji čita hijeroglife. Ogromna baza referenci i pravila koja vam omogućuju odabir hijeroglifa za odgovor.

    Ironično, to je ono što mi je donijelo jasnoću. Barem u praktičnom smislu. Shvatio sam problem s kojim sam se suočio. Nije samo složeno, nego je nedokučivo. Bilo je teško čak i ispravno formulirati pitanja vezana uz to. Činilo se jedinom utjehom Kako pronaći mjesto Hydra na Torus jeziku, stvari su jednako skliske. S ljudskom sviješću. Nisam se mogao nositi s ovim. I odlučio sam da bi najbolji izlaz iz situacije bio povratak. Posao kao i obično, ostavljajući egzistencijalne vježbe za kasnije ili zaboravljajući na njih.

    Uskoro je put doveo do bogatog sela sa svježe okrečenom bijelom crkvom. Tužan, jednonogi vojnik u izblijedjeloj sivoj odori sjedio je kraj crkvene ograde. Ne znate gdje je Optina Pustyn. upitao je T. sagnuvši se prema njemu s konja. To je ono o čemu dečki pričaju. upita vojnik. Koja je nedavno osnovana kao ustanova. Zaključio sam da je serviser poludio. Kako je ovo mjesto nedavno postavljeno. Što znači, u svakom slučaju, sve je u redu, časna čast, rekao je vojnik i Hydra rulet ruku, još ćeš biti daleko. Ovdje postoje samo dvije ceste i obje idu u jednom smjeru. Idite prvim putem, ili drugim. Ako želite kraći put, onda kroz šumu. Tamo je vilica, tako da možete ići na obje strane.

    I druge grimase, o kojima ste, mislim, već puno čuli... Lena nije shvaćala kakva je tata-mama budala osamnaestogodišnjakinja (mladić je brzo i tiho promrmljao te riječi), ali je odmah zaboravila na to - ona iznenada do te mjere poželjela srknuti dvadesetak tisuća eura vrijednog vina da joj je potekla voda na usta. Dvoranom se prolomio tihi uzdah koji je potvrdio da okupljeni nisu tek tako čuli za grimase. I uspjeli smo vrlo detaljno proučiti sve dostupne podatke o njima. “Nedavno su zapadne obavještajne agencije pokrenule pravi lov na naše bogate idiote”, nastavio je mladić. - Čuli ste, naravno, za velike afere adresa hidra luka tk okey site hidra u torusu uhićenja: prvo Courchevel, zatim Fiji, zatim butik Hermes, a sada Saint Moritz, Maldivi i Antarktik. Kampanja je pomno planirana i ima dva glavna cilja – prvo, diskreditirati. Ruska civilizacija - uspostaviti kontrolu nad svojim resursima prikupljanjem kompromitirajućih dokaza o vlasnicima njezinih glavnih dobara. Naša je elita postala meta, a objektivna stvarnost trenutne točke u prostor-vremenu je takva da. S njom smo postali mete. Namrštivši se, ušutio je, kao da daje priliku svojim slušateljima da shvate ozbiljnost situacije. Tada mu se tužni osmijeh vratio na lice i nastavio je: Moramo držati situaciju pod kontrolom.

    Ona se naceri. Barem ne morate glumiti uvrijeđenu nevinost pred svojima. O čemu. Kad sam ga provocirao. Kad je gola iskočila iz Hidra luk ulaz i stala ispred njega doggy style. Vi ovo smatrate provokacijom. Sigurno. Zašto ste mu, pitam se, okrenuli leđa? Slegnuo sam ramenima. Za pouzdanost. Što je tu posebno pouzdano? Rep je bliže meti”, rekao sam, ne baš samouvjereno. Dobro. I moraš pogledati preko ramena.

    Treći montal vanilla ecstasy i to: Njegovoj Preuzvišenosti O. Konstantinu Petroviču Pobedonoscevu, službenik. Ovime prenosim Vašoj Ekselenciji prijevod staroegipatskog natpisa. Listić zlatnog zlata pronađen u medaljonu montal vanilla ecstasy leš oca Varsonofija Netrebka u sklopu istrage o slučaju grofa T. Prema stručnjacima iz Egipatskog muzeja, obris hijeroglifa omogućuje nam datiramo tekst u doba 18. dinastije ili malo kasnije vrijeme. Natpis glasi: Tajno ime hermafrodita s mačjom glavom, koja daje moć nad njim, je suština. ANGC. Ako možete kontrolirati hermafrodita s ovim imenom. Fino. Prevoditelji koji ANGC mogu se prevesti i kao tradicionalni BHGV (ili drugačije, ovisno o izboru korespondentnih tablica pri korištenju hijeroglifskih registara). Međutim, sam medaljon ne može se prenijeti Vašoj Ekselenciji unatoč Vašem zahtjevu.

    Navigacija postova

  • Najbolji članci na temu