Opcje dwuwartościowe - przechowywanie

Często nasze tabele w bazie danych zawierają pola, która mogą przyjmować dwie wartości (dwa stany): 0 i 1. Na przykład tabela z użytkownikami zawiera pole ZABLOKOWANY, które mówi czy użytkownik jest zablokowany czy nie. Jeśli jest zablokowany to przyjmuje wartość 1 a jeśli nie jest - wartość 0. Wszystko ładnie pięknie gdy są to pojedyncze pola i nie zajmują dużo miejsca. Ale co w przypadku gdy nasza tabela zawiera kilka, kilkanaście lub nawet kilkadziesiąt opcji opisu (np. tabela z ofertami, która zawiera pola OPCJA_1, OPCJA_2, OPCJA_3, .... OPCJA_N) ? Czy mamy wówczas też tworzyć kilkadziesiąt pól na każdą z opcji o możliwych wartościach 0 i 1? Nie - tutaj z pomocą przyjdzie nam system dwójkowy (binarny) oraz operacje bitowe.

Całość przedstawię na podanym powyżej przykładzie: tabela z jakimiś ofertami. Tabela zawiera osiem pól. Każde z pól będzie typu TINYINT czyli zajmować będzie jeden bajt. Pola mogą mieć wartości 1 lub 0 oznaczające kolejno posiadanie danej opcji przez ofertę lub nie.

CREATE TABLE `oferta` (
  `ID` int unsigned NOT NULL auto_increment,
  `NAZWA` varchar(32) NOT NULL,
  `OPCJA_1` tinyint unsigned NOT NULL default 0,
  `OPCJA_2` tinyint unsigned NOT NULL default 0,
  `OPCJA_3` tinyint unsigned NOT NULL default 0,
  `OPCJA_4` tinyint unsigned NOT NULL default 0,
  `OPCJA_5` tinyint unsigned NOT NULL default 0,
  `OPCJA_6` tinyint unsigned NOT NULL default 0,
  `OPCJA_7` tinyint unsigned NOT NULL default 0,
  `OPCJA_8` tinyint unsigned NOT NULL default 0,
  PRIMARY KEY  (`ID`),
  KEY `OPCJA_1` (`OPCJA_1`),
  KEY `OPCJA_2` (`OPCJA_2`),
  KEY `OPCJA_3` (`OPCJA_3`),
  KEY `OPCJA_4` (`OPCJA_4`),
  KEY `OPCJA_5` (`OPCJA_5`),
  KEY `OPCJA_6` (`OPCJA_6`),
  KEY `OPCJA_7` (`OPCJA_7`),
  KEY `OPCJA_8` (`OPCJA_8`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

Jak widać tabela już wizualnie jest duża. Stworzyliśmy 8 pól. Każde z pól zajmuje jeden bajt. Dodatkowo jeśli tych opcji chcemy używać przy wyszukiwaniu to dobrze też jest założyć na nie indeksy. Także mamy już 8 bajtów na opis opcji jednego rekordu plus indeksy

Ale możemy to znaczącą zmniejszyć. Wystarczy znać podstawy systemu dwójkowego oraz operacji bitowych. Nie będę tu tego opisywał, przedstawię jedynie podstawy do zrozumienia na czym cały myk polega.

Teoria

Jak zapewne wiecie jeden bajt zawiera 8 bitów. Bit to po prostu wartość 0 lub 1. Czyli skoro jeden bajt zawiera osiem bitów to na jednym bajcie możemy zapisać do ośmiu informacji zerojedynkowych. Teraz wystarczy "wirtualnie" określić, że ustawienie w danej pozycji bita stanowi wybór jednej z opcji i mamy problem z głowy.

zapis dwójkowy | wartość dziesiętna | opcja
0 0 0 0 0 0 0 0      0               żadna opcja
0 0 0 0 0 0 0 1      1               opcja 1 
0 0 0 0 0 0 1 0      2               opcja 2
0 0 0 0 0 1 0 0      4               opcja 3
0 0 0 0 1 0 0 0      8               opcja 4
0 0 0 1 0 0 0 0      16              opcja 5
0 0 1 0 0 0 0 0      32              opcja 6 
0 1 0 0 0 0 0 0      64              opcja 7
1 0 0 0 0 0 0 0      128             opcja 8

Ustawiając wartości 1 na różnych bitach otrzymujemy inne wartości dzisiętne.

zapis dwójkowy | wartość dziesiętna | opcja
0 0 0 0 0 0 0 0      0               żadna opcja 
0 0 0 0 0 1 0 1      5               opcja 1 + opcja 3
1 0 0 0 0 1 0 1      133             opcja 1 + opcja 3 + opcja 8
0 0 1 1 0 0 0 0      48              opcja 5 + opcja 6
..............

Tyle teorii "dwójkowej". Teraz trochę teorii w php. Zapoznajcie się proszę z operatorami bitowymi

Chcąc w php dodać bitowo do siebie dwie liczby (ustawić wartość, która odpowiadać będzie zaznaczeniu dwóch naszych opcji) należy wykonać taki kod

<?php
//liczba 4 odpowiada opcji 3     0 0 0 0 0 1 0 0
//liczba 16 odpowiada opcji 5    0 0 0 1 0 0 0 0
$opcje = 4 | 16; //20
//liczba 20 odpowiada opcji 3 oraz opcji 5    0 0 0 1 0 1 0 0
?>

Ok, umiemy już dodawać opcje do siebie. Ale jak sprawdzić w wyszukiwaniu czy dana opcja jest zaznaczona mając podaną liczbę określającą zaznaczone opcje? Posłużymy się operatorem &

<?php
//$opcje = 20; opcja 3 oraz opcja 5
//sprawdzamy czy w zmiennej $opcje znajduje się opcja 3 (wartość 4)
//jeśli wynikem sprawdzania będzie liczba której szukamy, to znaczy że szukana opcja jest w naszym zbiorze
//jeśli wynikiem będzie inna liczba wówczas opcji nie ma
$res = $opcje & 4; //wynikiem jest 4 - opcja 3 więc tu jest
$res = $opcje & 8; //wynikiem jest 0 - nie ma tu więc opcji 4
?>

Możemy też jednocześnie poszukiwać kilku opcji

<?php
//szukamy czy występują jednocześnie opcje 1 (1) oraz 3 (4) czyli szukamy liczby 5 (0 0 0 0 0 1 0 1 )
//1 0 0 0 0 1 0 1      133                        opcja 1 + opcja 3 + opcja 8
$res = 133 & 5;//wynikem jest 5 czyli zawarte są tu opcje 1 oraz 3

//szukamy czy występują jednocześnie opcje 2 (2) oraz 3 (4) czyli szukamy liczby 6 (0 0 0 0 0 1 1 0 )
$res = 133 & 6;//wynikem jest 4 czyli liczba różna od szukanej. Nie ma więc tutaj jednocześnie opcji 2 oraz 3
?>

Powyższe obliczenia można również wykonywać bezpośrednio na bazie danych - przyda nam się to w praktycznym pisaniu wyszukiwarki.

Zauważcie, że jeśli szukamy tylko jednej opcji, to w przypadku gdy jej nie znajdziemy, wynikiem zawsze będzie 0. W przypadku poszukiwania kilku opcji, wynikiem negatywnym może być liczba większa od 0 ale inna niż ta, której szukaliśmy. Właściwość ta nam się przyda przy zaznaczaniu checkboxów, ale o tym za chwilę.

Praktyka

Tak więc nasze 8 pól opcji zamieniamy na jedno pole typu TINYINT. Typ ten zajmuje jeden bajt czyli osiem bitów. Jeśli byście chcieli przechowywać do 16 opcji, musicie użyć typu SMALLINT (2 bajty - 16 bitów). Zwiększając typy możecie przechowywać więcej opcji - ale to już chyba hardcore robić kilkadziesiąt opcji dla jednej tabeli

CREATE TABLE `oferta` (
  `ID` int unsigned NOT NULL auto_increment,
  `NAZWA` varchar(32) NOT NULL,
  `OPCJE` tinyint unsigned NOT NULL default 0,
  PRIMARY KEY  (`ID`),
  KEY `OPCJE` (`OPCJE`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

Porównując tę tabelę do naszej pierwszej od razu widać wizualnie różnicę. Pamięciowo też już jest o wiele lepiej.

Zajmiemy się teraz reprezentacją opcji. Opcje możemy przedstawić jako checkboxy

<input type="checkbox" name="opcja[]" value="1" />Opcja1 
<input type="checkbox" name="opcja[]" value="2" />Opcja2
<input type="checkbox" name="opcja[]" value="4" />Opcja3
....
<input type="checkbox" name="opcja[]" value="128" />Opcja8

Zauważcie, iż użyłem nazwy checkboxa z [] - określa to nazwę tablicową. Dzięki temu po zaznaczeniu kilku opcji, formularz wyśle na serwer wszystkie zaznaczone opcje jako tablica wartości. Tablicę tę będzie można odebrać w php z $_POST['opcja'].

Jeśli pobierzemy z bazy wartość pola OPCJE i chcemy w formularzu zaznaczyć te opcje, które są zawarte w tym polu, korzystamy ponownie z operatora &

<?php

$opcje = 20; //wartość pobrana z bazy z pola OPCJE

//poniżej zostaną zaznaczone opcja 3 oraz opcja 5
echo '<input type="checkbox" name="opcja[]" value="1" '.($opcje & 1 ? 'checked="checked"' : '').'/> Opcja 1';
echo '<input type="checkbox" name="opcja[]" value="2" '.($opcje & 2 ? 'checked="checked"' : '').'/> Opcja 2';
echo '<input type="checkbox" name="opcja[]" value="4" '.($opcje & 4 ? 'checked="checked"' : '').'/> Opcja 3';
echo '<input type="checkbox" name="opcja[]" value="8" '.($opcje & 8 ? 'checked="checked"' : '').'/> Opcja 4';
echo '<input type="checkbox" name="opcja[]" value="16" '.($opcje & 16 ? 'checked="checked"' : '').'/> Opcja 5';
echo '<input type="checkbox" name="opcja[]" value="32" '.($opcje & 32 ? 'checked="checked"' : '').'/> Opcja 6';
echo '<input type="checkbox" name="opcja[]" value="64" '.($opcje & 64 ? 'checked="checked"' : '').'/> Opcja 7';
echo '<input type="checkbox" name="opcja[]" value="128" '.($opcje & 128 ? 'checked="checked"' : '').'/> Opcja 8';
?>

Teraz jeśli chcemy zapisać zaznaczone checkboxy (opcje) do bazy to musimy użyć operatora |

<?php
if (!empty($_POST)){ //jeśli wysłano formularz
	$opcje = 0;//zaczynamy od nie wybranej żadnej opcji
	if (!empty($_POST['opcja'])){ //jeśli wybraliśmy jakieś checkboxy
		foreach ($_POST['opcja'] as $op){ //przelatujemy po wartościach wybranych checkboxów
			$op = (int)$op; //rzutujemy wartość na inta by przypadkiem ktoś nam "kuku" nie zrobił
			//dodajemy bitowo opcje
			$opcje |= $op; //zapis ten jest równoważny do  $opcje = $opcje | $op;
		}
	}
//teraz w zmiennej $opcje mamy zaznaczone opcje i możemy tę wartość zapisać do bazy
}
?>

Mamy już wczytywanie i zapisywanie opcji. Pozostało jeszcze zrobić nam wyszukiwanie. Wyszukiwarka również będzie zawierała formularz z checkboxami określającymi opcje. Wyszukanie opcji będzie podobne do ich zapisania - też trzeba najpierw zsumować zaznaczone opcje, a następnie przy pomocy operatora & wyszukać oferty, które je zawierają.

<?php
$opcje = 0; //na początku nic nie szukamy
//w wyszukiwarkach zazwyczaj korzysta się z get zamiast post
if (!empty($_GET['opcja'])){ //jeśli wybraliśmy jakieś checkboxy to ich będziemy szukać
	foreach ($_GET['opcja'] as $op){ //przelatujemy po wartościach wybranych checkboxów
		$op = (int)$op; //rzutujemy wartość na inta by przypadkiem ktoś nam "kuku" nie zrobił
		//dodajemy bitowo opcje
		$opcje |= $op; //zapis ten jest rownoważny do  $opcje = $opcje | $op;
	}
}

//tworzymy podstawowe zapytanie do pobrania ofert
$sql = 'select * from oferta';

//jeśli wybraliśmy jakieś opcje, to jeszcze bedziemy ich szukac.
//dodajemy więc WHERE do zapytania
if (!empty($opcje))
	$sql.=" where OPCJE & $opcje = $opcje"; //jak już pisałem wcześniej, jeśli szukamy opcji to wynik musi nam zwrócić szukaną liczbę

//wykonujemy zapytanie
$res = mysql_query($sql);

//i tutaj już sobie wyświetlamy znalezione wyniki
?>

I to już wszystko. Na pierwszy rzut oka może to się wydawać skomplikowane - wystarczy jednak przerobić to ze dwa razy i powinno już być lżej. A znajomość tej metody może Wam się przydać - ja z niej korzystam dość często.

Wiem, że kod można było napisać bardziej uniwersalnie, np. poprzez dodanie pętli zamiast generować wszystkie opcje ręcznie. Nie chciałem jednak wprowadzać dodatkowych "bajerów" by nie zaciemniać istoty problemu.

W dziale download znajdziecie paczkę, która zawiera przykładową bazę danych oraz kody do zapisywania i wyszukiwania opcji. Przeanalizujcie je dokładnie - pomogą Wam utrwalić przedstawione tu informacje.

I na koniec mały "bonus" dla tych wszystkich, którzy nie lubią 0 i 1 lecz wolą bardziej wartości tekstowe. Mysql udostępnia specjalny typ danych, który umożliwia w opisanej tu metodzie operować na tekstach: SET

Komentarze

 

2010-07-27 17:44 Michał

Ja używam ENUM oraz SET wygodniej po prostu

2010-07-27 18:15 nospor

Ja zaś jakoś przyzwyczaiłem się do cyferek i rzadko sięgam po te typy. Z ENUM ostatnio zacząłem korzystać tylko dlatego, by nie zapomnieć jak się z niego korzysta

2010-07-27 18:56 gość_cojack

Tak na prawdę to bajt może mieć 9 stanów, jeszcze same 0 nospor.

2010-07-27 19:34 nospor

@cojak nie mówimy tutaj że bajt ma stany a bity. Bajt ma 8 bitów. Za pomocą tych ośmiu bitów można również zapisać bajt o wartośći liczbowej 0. I według Ciebie oznacza to, iż dzięki temu można na jednym bajcie zapisać 9 opcji? Proszę więc o przykład
Jeśli zaś Twoja myśl o 9 stanach zmierzała do czegoś innego to też ją proszę rozwiń.

2010-07-27 19:52 gość_Kshyhoo

Fajny artykuł, przypomniał mi naszą "pogawędkę" na temat ENUM.

2010-07-27 22:44 gość_cojack

@nospor np gdybyś chciał zrobić grupy użytkowników na masce bitowej, pozwalając adminowi dodawać je, to jest to bardzo mało wygodne bo przez to się maska bitowa rozszerza. No ale to akurat nie wątek o tym. Tak bajt ma tylko 8 bitów i tutaj się nie będę kłócił ;D Ale jak sam napisałeś powyżej ( nie mogę wkleić kodu )

To patrz, jakąś opcją równie dobrze mogło by być stan zerowy nie prawda :> Jak masz możliwość 9 stanów to czemu i nie 9 opcji? A mam nadzieję że ten artykuł to tylko tak w ramach rozrywki pisany, a nie tak na poważnie, to mało czytelne jest programowanie. Ja tam nie lubię pól bitowych i masek, może dlatego że mało w C pisałem. Ale jakoś ich nie lubię ;p Jedynie co z bitów używam to w postgresie zamiast boolean bo mnie masakrycznie irytuje jak mi postgres wypluwa 't' lub 'f' jako wartość logiczną i weź się z tym później męcz w php.

2010-07-27 22:51 gość_Vokiel

Operatory bitowe to ciekawa opcja, chociaż nie często się z nią spotykałem.

Kiedyś zrobiłem mały system dostępu do aplikacji oparty. Modułów w aplikacji było dość dużo,a nie chciałem robić uprawnień dostępu na zasadzie ciągu cyfr rozdzielanego separatorem (przecinkiem, średnikiem). Sposób przez Ciebie tu opisany spisywał się bardzo dobrze. No i ćwiczyło się liczenie w pamięci w systemie dwójkowym, 12 - tylko dostęp do odczytu komunikatów, 255 - o super admin

2010-07-27 23:08 nospor

@cojak jeden z nas czegoś tu nie rozumie. Może ty mnie, może ja Ciebie
Jak masz możliwość 9 stanów to czemu i nie 9 opcji?
Jak to sobie wyobrażasz? Skoro wykorzystasz 0 jako opcja 9 to jakim cudem w polu zapiszesz: "nie wybrano żadnej opcji"?
Przecież podałem to nawet na przykładzie:
zapis dwójkowy | wartość dziesiętna | opcja 
0 0 0 0 0 0 0 0      0                           żadna opcja 
0 0 0 0 0 0 0 1      1                           opcja 1  
0 0 0 0 0 0 1 0      2                           opcja 2 
0 0 0 0 0 1 0 0      4                           opcja 3 
0 0 0 0 1 0 0 0      8                           opcja 4 
0 0 0 1 0 0 0 0      16                         opcja 5 
0 0 1 0 0 0 0 0      32                         opcja 6  
0 1 0 0 0 0 0 0      64                         opcja 7 
1 0 0 0 0 0 0 0      128                        opcja 8
Tu nie ma miejsca na opcje nr 9. Chcesz mieć 9 opcji to daj SMALLINT gdzie masz dwa bajty - 16 bitów - zmieścisz wówczas 16 opcji.
A mam nadzieję że ten artykuł to tylko tak w ramach rozrywki pisany, a nie tak na poważnie, to mało czytelne jest programowanie. Ja tam nie lubię pól bitowych i masek,
To, że coś jest mało czytelne nie znaczy, że jest złe. To że ty czegoś nie lubisz też nie znaczy, że jest złe. Dla mnie to co tu przedstawiłem to banalna sprawa - używam tego często. Nie widzę w tym nic "niepoważnego".
gdybyś chciał zrobić grupy użytkowników na masce bitowej, pozwalając adminowi dodawać je, to jest to bardzo mało wygodne
A ty gdybyś próbował samochodem lecieć to też to jest bardzo mało wygodne... Cojak, uważam Cię za rozsądanego chłopaka, ale Twoja argumentacja tutaj mnie przeraża. W życiu nie robiłem grup użytkowników na masce bitowej (choć jakby przysiąść to można się pobawić, może coś ciekawego by wyszło). Do jazdy używam samochodu, do latania używam samolotu. Do wbijania gwoździ używam młotka a nie packi na muchy. Na muchy używam packi na muchy a nie młotka. Zamiast używać bez sensu 8 pól w bazie używam jednego jeśli sytuacja na to pozwala. Artytkuł jest o tym jak tego używać. Jeśli ktoś znajdzie zastosowanie to proszę bardzo niech używa jeśli się przyda. Ale niech nikt na siłe nie wciska tego gdzie popadnie bo nie taki tego cel. A juz na pewno niech nikt z tego nie korzysta jeśli ma małe pojęcie o operatorach bitowych i ich nie lubi

Opisałem tę metodę tutaj, gdyż na forum stosunkowo często pojawiał się taki problem. Ludzie się głowili, wymyślali cuda nie widy a rozwiązanie było banalne - bity
Nie raz udzielałem na forum tej odpowiedzi i sporej części początkujących ona przypadała do gustu. Postanowiłem więc opisać ją ciut dokładniej - nie jako żart, ale jako poważne rozwiązanie.

2010-07-27 23:18 nospor

@vokiel o widzisz. Może opisz swój przykład trochę dokładniej - zapewne by naświetlił wykorzystanie tej metody w innej trochę sytuacji niż opisanej tu przeze mnie

2010-07-28 00:09 gość_cojack

No przecież napisałem że to nie temat o grupach no coś się uczepił. Jakoś tak samo mi się z kontekstu wyrwało. Ale jest też inne rozwiązanie tego problemu, dajmy na to że produkt może mieć atrybuty, które są przypisane cechom, do której kategorii przynależy produkt. I taki produkt jednej cechy może mieć wiele atrybutów. Tego to już byś raczej na bitach nie poleciał, chociaż na upartego to wszystko można. No ale rozwiązanie takiego problemu przy zachowaniu normalizacji bazy danych należałoby utworzyć relację many-to-many i to chyba nie jedną. Także do Twojego problemu, też zastosowałbym tą opcję, łatwo można sobie jojnować crosować itp ;] A przy tych przesunięciach bitowych to bym się tępym ołówkiem pochlastał...

2010-07-28 07:26 nospor

No przecież napisałem że to nie temat o grupach no coś się uczepił.
No bo robisz wstawki ni z gruszki nie z pietruszki i już sam nie wiem o co ci chodzi Make php code not war

2010-08-02 01:36 gość_Pan Rumcajs

Fajny artykuł i dobry pomysł do wykorzystania. Przydałoby się tylko jeszcze używać czcionki o stałej szerokości podczas prezentowania wycinków kodu - polepszyłoby to na pewno czytelność.
Dzięki!

2011-01-28 15:55 gość_Martinesku

Pierwszy raz tu trafiłem szukając opcji bitowych.
Bardzo ciekawy artykuł, pisany przystępnym językiem.
Od razu widać, że nie był pisany "na pałę" w ciągu 10 min.
Tylko tak dalej.

2011-04-23 11:08 gość_Gość

Ok... Ale jak mam np. wartość 3 (opcja 1 i 2) i chcę odjąć 2 by mieć tylko opcję 1 - to jak to zrobić?

2011-04-23 13:52 nospor

Przecież podałęm na początku arta linka do operatorów birowych. Wystarczy go przejrzeć.
<?php
$zm = 3 ^ 2;
echo $zm;
?>

2011-05-11 20:23 gość_strukt

Prościej, ale i tak na około i nie zbyt zgrabnie. Wystarczy jedno pole INT gdzie dla opcji jeden, INT przyjmie wartosc 1/0, dla opcji2 2/0, dla opcji3 3/0 - Dla mnie osobiście artykuł jest ciekawy matematycznie i wykazujące Twoją sporą wiedzę, ale sposób nie należy do praktycznych.
Pozdrawiam

2011-05-11 20:41 nospor

Co praktyczności: używam tego sposoby od lat i nie widzę w nim nic niepraktycznego.
Co do Twojego sposobu to go nie rozumiem. Możesz go rozwinąć?
Piszesz, że ma być pole INT. Ok. Tylko wyjaśnij mi proszę jakim sposobem to pole może przyjąć wartość 1/0 albo 2/0? Czegoś tu nie rozumiem. 1 dzielone przez 0? 2 dzielone przez 0?

2011-07-04 14:40 gość_Filip

opcja w mysql z użyciem set, bardzo mi przypadła do gustu :> i raczej zacznę ją stosować, bo faktycznie, w niektórych tabelach robi się tych wszystkich dodatkowych opcji w efekcie czego tabela przybiera dość sporych rozmiarów.. No ale koniec z tym dzięki wielkie za wpis.

2011-10-13 03:14 gość_Emtec

Nie czytałem wszystkich komentarzy, ale z góry zakładam że Nospor ma rację. 0 nigdy nie można opisać jako operacji, bo na jakim kol wiek bicie - "sprawdzisz czy zawiera 0" zawsze zwróci prawdę. Sam mam zaimplementowane maski w grze którą piszę (C++, ale to jest nie ważne). I gdybym miał zrobić ~200 pół dla własności dla obiektu to bym ześwirował. Tak mam w core ładne emu gdzie mam np.
enum _flags
{
OBJECT_CAN_MOVE = 0x00001,
OBJECT_CAN_SAY = 0x00002,
OBJECT_CAN_RESP = 0x00004,
OBJECT_HAS_QUEST = 0x00008.
};

oczywiście to tylko przykładowe enum - a w core jest około ~200 (wszystkie zachowania obiektu). Później tylko sprawdzam if(sObject.GetObject(entry).GetFlags() & OBJECT_HAS_QUEST) - i po sprawie. Wszystko w jednym miejscu, na pewno zajmuje o wiele mniej miejsca jak w bazie tak i w pamięci. Jest o wiele szybsze. Gdy chce sprawdzić wszystkie obiekty w bazie które posiadają flagę HAS_QUEST wystarczy że wpiszę SELECT * FROM `object_templates` WHERE `flags` & 0x00008; Itp. a nie muszę pisać bez sensownych query (które przy o wiele większym sprawdzaniu zajmują więcej czasu). Podam jeszcze przykład - chcemy sprawdzić czy dany obiekt ma flagi takie jak:

OBJECT_CAN_SAY i OBJECT_CAN_RESP. Robimy przesunięcia i wspólna wartość wychodzi 0x00006. Więc ponowne piszemy query ale zamiast 0x00008 podajemy 0x00006 - i wszystkie obiektu które to mogą, wyświetlają nam się. Gdybyśmy zrobili pola - query musiało by się już opierać na dwóch where.

Trochę chaotycznie to wszystko opisałem, wybaczcie - udziela się brak snu od paru dni. Podsumowując temat, mogę od siebie dodać plusy tego mechanizmu:
+ Szybkość
+ Własności w jednym miejscu
+ O wiele wygodniejsze sprawdzanie kilku wlasności
+ Łatwość wybrania rekordów który mają x własności.

Pozdrawiam.

Do tego dochodzi sam fakt - operowania na flagach podczas działania. Np flags | 0x0004 i wszystkie inne operacje przesunięć bitowych. W php akurat to już nie ma za dużego znaczenia.

2011-10-13 07:49 nospor

Dziękuję Emtec za ciekawy i praktyczny przykład z życia programisty wzięty

2011-10-13 21:31 gość_Emtec

Nie ma za co, pokazałeś - prosty, ale najłatwiejszy i najładniejszy sposób. Ten schemat jest dość bardzo znany i używany w świecie c++, więc nie widzę przeszkód żeby go implementować w php. Warto też wspomnieć o kolejnych plusach jakie to wszystko niesie. Przykładowo mamy tablice users i groups.
W tabeli users mamy flagi, do tego uzytkownik należy do kilku grup które też mają jakieś własności (flagi). Przy załadowaniu łaczymy wszystkie te maski w jedno czyli UserFlags & Groups1 & Groups2 & Groups3 (uzytkownik nalezy do grup 1,2,3) - wychodzi nam wspólna wartość. Jeśli w masce grupy 1 jest CAN_MOVE i w grupie 2 też, to to się nie powtórzy - będzie tylko jedno (tak na chłopski rozum już). Bez sprawdzania - czy może ma do tego prawa tu, albo może tu. Jeśli jest w złączonych flagach to oznacza że ma możliwość takiej operacji.

2011-10-14 07:25 nospor

No to tylko taka mała poprawka. Ja wiem co miałeś na myśli, ale ktoś początkujący może nie wiedzieć.
UserFlags & Groups1 & Groups2 & Groups3
Nie and a or i to bitowy or

2011-10-14 09:27 gość_Emtec

Dokładnie Dla innych - popełniłem błąd (chociaż chodziło o całkiem inną rzecz, dobrze że nospor zwrócił uwagę)i zamiast & powinien być | . Czyli UserFlags | Groups1 | Groups2 | Groups3 A później koniunkcją sprawdzać (&.

Tutaj opis dla tych co będą zainteresowani tematem: http://www.algorytm.org/kurs-algorytmiki/operacje-bitowe.html

2012-02-16 18:57 Michał

Jakże bliska mi opcja z asemblera

2012-05-22 20:54 gość_gidaban

Witam

Czy ktoś miał przyjemność zastosować to w zend_form ?

Chodzi mi o przesyłanie danych z bazy do formularza i zaznaczenie wybranych opcji :-)

2012-05-23 07:49 nospor

Robisz dokładnie tak samo, ino że przy wykorzystaniu mechanizmów zend. Jeśli znasz zenda to nie powinno to być dla Ciebie żadnego problemu.
Jeśli nie znasz zenda, to wypadałoby się wpierw go nauczyć.

2012-05-27 14:02 gość_gidaban

no to tak :-)

Mam w bazie zapisaną wartość 3 suma(1i2) tylko w tym sęk jak to przekazać do zend_form ? w przypadku edycji danych zapisanych w bazie ?

Pozdrawiam

2012-05-28 08:23 nospor

No przecież napisałem: robisz dokładnie tak samo jak ja tutaj, tylko ty masz użyć zenda.

Jak ja robiłem: echo '<input type="checkbox"
to ty masz w to miejsce dodać pole checkbox w zendform. No chyba pole w zend form potrafisz dodać?

2012-05-29 20:24 gość_gidaban

controller

$data= $model->find($id)->curent(); // odczytuje dane z bazy

całą resztę pominę
form nie został wysłany więc uzupełniam go danymi z bazy czyli

$form->populate($data->toArray());

wszystkie pola ładnie uzupełnia więc jest ok. Ale teraz czy można zaznaczyć pola typu chceckbox z odpowiednimi opcjami pobranymi z bazy?

wkleić też jak to mam w pliku zend_form ?

2012-05-29 21:09 nospor

Dawno się zendem nie bawiłem, ale tam przecież masz dodawanie pól w tym i checkboxów. Skoro każdego checkbox masz jako oddzielne pole to możesz każdemu z osobna powiedzieć czy ma być zaznaczone czy nie, nieprawdaż? A to czy pole ma być zaznaczone czy nie to pokazane masz w moim przykładzie.

2012-05-29 21:13 gość_gidaban

Jeśli chodziło by o zwykłe checkboxy to nie ma z tym problemu. Tylko właśnie chodzi mi o zastosowanie tej techniki. Nie mogę tu wkleić tego co mam w pliku. Masz o mnie e-mail to napisz i tam może wkleję?

2012-05-29 21:33 nospor

Czemu nie możesz wkleić? Wklej same pola checkbox. Całość aplikacji mnie nie interesuje.

2012-05-29 21:44 gość_gidaban

$eqModel = new Application_Model_DbTable_Wyposazenie();
        $array = $eqModel->getEqForForm();
        $equipment = new Zend_Form_Element_MultiCheckbox('objectEquipment');
        $equipment->setName('objectEquipment')->addMultiOptions($array);
        $equipment->setLabel('Wyposażenie:');i
// model
public function getEqForForm(){
        $ret=array();
        foreach ($this->fetchAll(null, 'wDesc ASC') as $value){
            $ret[$value->value]=$value->wDesc;
        }
        return $ret;
    }

2012-05-29 22:03 nospor

No ale w obiekcie Zend_Form_Element_MultiCheckbox musisz w jakis sposób powiedzieć czy danych checkbox ma być znaznaczony czy nie. Jak pisałem nie jestem na bieżącą z Zend i tu ci nic nie powiem. Musisz zajrzeć do dokumentacji zenda.

2012-05-29 22:08 gość_gidaban

w kontrolerze daje sie $form->populate($daneZBazy) i mamy to w formularzu, ale nie jeśli chodzi o tą metodę właśnie :/ dlatego też chyba będę musiał przejść na viewScript.

Dodaj komentarz

 

Dostępne bbcode: b, u, i, url, code, php, css, html, sql, js

Skrypty użytkowników

  1. Klasa obsługi szablo... Lirdoner
  2. Sekcje user76
  3. Klasa walidująca for... user76
  4. Licznik Gości online korey
  5. Form Builder Comandeer
  6. Dynamiczny licznik z... korey
  7. Captcha Comandeer