Baza danych - pobieranie nazw tabeli

0

Target jest następujący: dodając użytkownika do bazy danych, muszę z listy rozwijanej wybrać jego grupę (jest to tabela w bazie danych, np. "grupa1", "grupa2", itd.). Zatem połączenie z bazą ma miejsce już w trakcie samego otwierania formularza dodawania użytkownika. I tutaj pojawiają się dwa zapytania:

  1. Jak poprawnie skonstruować pytanie, żeby wybrało wszystkie dostępne nazwy tabel z bazy danych o nazwie "baza1"?
  2. Jeśli już pobierzemy nazwy, jak załadować je do wybranej zmiennej? Wymyśliłem taką tabelę:

$wiersz = $rezultat->fetch_assoc();
 

gdzie "$rezultat" to nasze zapytanie o nazwy tabel. Natomiast pętla w formularzu trwałaby do tego momentu, aż byłyby dostępne jakiekolwiek nazwy w bazie.

0

Każda z grup bazy danych składa się z następujących pól: "name", "surname", "login", "password" (zahashowane), "birthDate". Jedyne, czym się różnią poszczególne grupy, to jedynie nazwami, na przykład moglibyśmy stworzyć podziały: "Profesorowie", "Uczniowie" i tak dalej. Nasz target, to dodać właśnie same nazwy grup do listy rozwijanej w formularzu i tutaj mam kilka problemów. Nawet jeśli wiedziałbym, jak zrobić zapytanie, nie do końca wiem, jak zgrabnie to załadować do zmiennych, które następnie będą wyświetlane w liście rozwijanej.

0

polecenie show tables.

0

Jezusie słodki, zastanów się głęboko nad swoim życiem i nie rób tego. Prawdopodobnie każdy przypadek, kiedy będziesz musiał po stronie aplikacji wykorzystywać show tables czy inne takie kombinacje, oznaczać będzie błędną architekturę aplikacji.

Przecież gdybyś miał na przykład sto grup, dodanie nowego pola oznaczałoby modyfikację stu tabel! I co z przypadkami, gdy masz przykładowo tabelę ustawienia oraz ktoś będzie chciał utworzyć grupę o nazwie ustawienia? Albo gdy ktoś będzie chciał mieć spację/znak Unicode/(...) w nazwie? Absolutnie wszystko jest źle przemyślane.

Dlaczego zwyczajnie nie zrobisz jednej tabeli użytkownicy z dodatkowym polem nazwa_grupy?

Albo jeszcze lepiej (normalizując): utwórz tabelę grupy_uzytkownikow z kolumnami id_grupy_uzytkownikow oraz nazwa i tabelę użytkownicy z tymi wszystkimi Twoimi wymaganymi polami oraz dodatkowo id_grupy_uzytkownikow.

0

Można też tak zrobić i wg mnie byłoby to najpraktyczniejsze. Problem w tym, że mam też do zrobienia polecenia takie jak dodawanie/zmiana nazwy/usuwanie/lista grup użytkowników. Jaki sens miałyby takie operacje, jeśli ręcznie moglibyśmy sobie ustawiać osobno każdą grupę użytkownika i wpisywać tam, co chcemy? Chyba, że dałoby się zdefiniować jakiegoś własnego enuma w obrębie SQLa? Ma ktoś jakieś pomysły, jak można to załatwić?

0

Przecież jeśli będziesz miał tabelę grupy_uzytkownikow, pobranie listy grup użytkowników to będzie zwyczajny jeden select, zmiana nazwy to pojedynczy update itd.

0

@Edit:

"Albo jeszcze lepiej (normalizując): utwórz tabelę grupy_uzytkownikow z kolumnami id_grupy_uzytkownikow oraz nazwa i tabelę użytkownicy z tymi wszystkimi Twoimi wymaganymi polami oraz dodatkowo id_grupy_uzytkownikow."

Dobry pomysł, tak będzie najlepiej :).

0

Zrobiłem dokładnie jak opisałeś i wszystko funkcjonuje jak należy. Dzięki za pomoc. Został tylko jeden problem:

 Birth date: <input type="date" name="userBirthDate" /><br />

Mam następujące pole, gdzie mogę w formacie DD.MM.YYYY wybrać określoną datę. Ma ktoś może pomysł, w jaki sposób dokonać walidacji tego? Na przykład sprawdzać, czy użytkownik przede wszystkim wybrał jakąkolwiek datę (isset?), a następnie pozwolić mu wybrać lata urodzenia np. tylko 1920-.

0

Poczytaj o klasie DateTime.

1

Jeżeli chcesz ograniczać dane w formularzu po stronie użytkownika to najlepszym rozwiązaniem będzie liznąć jeszcze trochę JSa. Ewentualnie możesz jakimś forem utworzyć kilka zwykłych list rozwijanych dla każdego pola (rok, miesiąc, dzień) i po później po stronie serwera sprawdzać najzwyczajniej te liczby jakimś ifologiem.
Chociaż znowu tutaj pojawiają się jeszcze większe problemy, ponieważ tworząc statyczne pola wyboru prosisz się np. o datę 31 lutego.

Oczywiście ifostworki są złe, jednak dla początkującej osoby (tak wnioskuje po samym pytaniu) wydaje mi się to spoko ćwiczeniem, jako mini rozrywka z algorytmów:) Napisz samemu taką funkcję do, której wrzucisz 3 zmienne, a ta zwróci Ci je w gotowym formacie do wrzucenia do bazy, albo false jeżeli dane będą niepoprawne :)

Jak nie chcesz sobie ćwiczyć, to do frontu użyj np. https://bootstrap-datepicker.readthedocs.io/en/latest/ , a po stronie serwera poczytaj o klasie DateTime tak jak sugerował Patryk27.

0

Dzięki wielkie za pomoc, wybiorę jedną z metod i powiem, jakie były rezultaty :). Póki co mam jednak inny, znowuż przedziwny problem: wpisując w zapytaniu w formie:

if ($connection->query("INSERT INTO users VALUES (NULL, NULL, '$user->getName(), '$user->getSurname()')"))
                {
                    $_SESSION['powodzenie']= "true";
                    echo "Poprawnie dodano osobę.";
                }

Pojawiają się przedziwne błędy, mianowicie zapytanie w ogóle nie rozpoznaje tych funkcji. Czy nie pozostaje nic innego, jak tylko przepisać je do zmiennych tymczasowych, co tylko zaburzałoby sens robienia jakichkolwiek obiektów? Kolejna, turbodziwna sprawa, to nie mogę połączyć się z bazą na poziomie funkcji. Ta wygląda następująco:

 function zmienId($groupName)
{
    try
    {
        $connection = new mysqli($host, $db_user, "", $db_name);

        if ($connection->connect_errno != 0)
            throw new Exception(mysqli_connect_errno());
    }

    catch (Exception $e)
    {

    }

    $connection -> close();

    return 0;
}

I perełeczka: jeśli to samo wypisuję poza obszarem funkcji, wszystko działa bez zarzutu. W innym wypadku kompilator nie widzi zupełnie zmiennych związanych z bazą.

0

To weź wywołaj to po za funkcją a jak będzie chciał używać w funkchach to użyj zmiennej globalnej

    $connection = new mysqli($host, $db_user, "", $db_name);

function funckja() {
global $connection;
}

1

Czy nie pozostaje nic innego, jak tylko przepisać je do zmiennych tymczasowych, co tylko zaburzałoby sens robienia jakichkolwiek obiektów?

No tak, przecież absolutnie jedynym powodem, dla których warto korzystać z obiektowości, byłaby możliwość interpolacji rezultatu wywołania metody do ciągu znaków ;-)

Pojawiają się przedziwne błędy, mianowicie zapytanie w ogóle nie rozpoznaje tych funkcji

Tak, ponieważ w PHP nie można interpolować wywołań metod (nie istnieje w ogóle taka składnia). Działa to tylko w przypadku zmiennych oraz afair funkcji. Tym niemniej, moim zdaniem, utrudnia to jedynie czytanie kodu - preferuję albo wykorzystywanie operatora konkatenacji (kropki), albo sprintf.

Poza tym Twoje podejście jest w ogóle złe:

1.Zmień zapytanie na bardziej przewidywalne - aktualnie jeśli ktoś doda nową kolumnę na początek tabeli users, musiałbyś każde miejsce w kodzie wykonujące to zapytanie odnaleźć i zmodyfikować. Dlaczego nie napiszesz po prostu INSERT INTO users(user_name, user_surname) VALUES (aaa, bbb);? Tak właściwie jestem w stanie nawet sam sobie odpowiedzieć: ano dlatego, że zabierasz się za naukę PHP oraz MySQL jednocześnie, zamiast najpierw ogarnąć podstawy funkcjonowania bazy danych.

2.Poczytaj o SQL Injection.

3.Dlaczego w funkcji zmienId łączysz się z bazą danych? :| Przecież wywołując ją na przykład tysiąc razy łączyłbyś się tysiąc razy z bazą danych, chociaż wcale nie ma takiej potrzeby.

4.Dlaczego funkcja, która coś zmienia (zmienId) przyjmuje tylko jeden argument? Zwyczajowo byłoby na przykład zmienNazweUzytkownika(idUzytkownika, nowaNazwaUzytkownika).

5.$_SESSION['powodzenie']= "true"; - samo true bez cudzysłowów wygląda za brzydko czy co? Po co opakowujesz to w ciąg znaków?

6.$connection->close(); powinno znajdować się w bloku finally, jeśli już masz taką potrzebę.

7.Nie mieszaj języka polskiego oraz angielskiego - pisz w całości po angielsku.

0
Patryk27 napisał(a):

Czy nie pozostaje nic innego, jak tylko przepisać je do zmiennych tymczasowych, co tylko zaburzałoby sens robienia jakichkolwiek obiektów?

No tak, przecież absolutnie jedynym powodem, dla których warto korzystać z obiektowości, byłaby możliwość interpolacji rezultatu wywołania metody do ciągu znaków ;-)

Pytałem o ten konkretny kontekst, mianowicie kiedy na potrzeby załadowania użytkownika do bazy danych tworzę tę małą strukturę danych, która póki co mi utrudnia tylko i wyłącznie sprawę.

Patryk27 napisał(a):

Pojawiają się przedziwne błędy, mianowicie zapytanie w ogóle nie rozpoznaje tych funkcji

Tak, ponieważ w PHP nie można interpolować wywołań metod (nie istnieje w ogóle taka składnia). Działa to tylko w przypadku zmiennych oraz afair funkcji. Tym niemniej, moim zdaniem, utrudnia to jedynie czytanie kodu - preferuję albo wykorzystywanie operatora konkatenacji (kropki), albo sprintf.

Niestety nadal bez zmian. Próbowałem wszystkiego: dodać do zapytania sprintf, usunąć enkapsulację i wprowadzić zmienne przez konkatenację. I faktycznie efekt jest, ale tym razem pojawia się następujący błąd: Catchable fatal error: Object of class user could not be converted to string in C:\xampp\htdocs\praktyki\users\addUser.php on line 46. Niestety nie mam pojęcia, jak to na stringa skonwertować. W obiekcie mam 5 zmiennych.

Patryk27 napisał(a):

Poza tym Twoje podejście jest w ogóle złe:

1.Zmień zapytanie na bardziej przewidywalne - aktualnie jeśli ktoś doda nową kolumnę na początek tabeli users, musiałbyś każde miejsce w kodzie wykonujące to zapytanie odnaleźć i zmodyfikować. Dlaczego nie napiszesz po prostu INSERT INTO users(user_name, user_surname) VALUES (aaa, bbb);? Tak właściwie jestem w stanie nawet sam sobie odpowiedzieć: ano dlatego, że zabierasz się za naukę PHP oraz MySQL jednocześnie, zamiast najpierw ogarnąć podstawy funkcjonowania bazy danych.

2.Poczytaj o SQL Injection.

3.Dlaczego w funkcji zmienId łączysz się z bazą danych? :| Przecież wywołując ją na przykład tysiąc razy łączyłbyś się tysiąc razy z bazą danych, chociaż wcale nie ma takiej potrzeby.

4.Dlaczego funkcja, która coś zmienia (zmienId) przyjmuje tylko jeden argument? Zwyczajowo byłoby na przykład zmienNazweUzytkownika(idUzytkownika, nowaNazwaUzytkownika).

5.$_SESSION['powodzenie']= "true"; - samo true bez cudzysłowów wygląda za brzydko czy co? Po co opakowujesz to w ciąg znaków?

6.$connection->close(); powinno znajdować się w bloku finally, jeśli już masz taką potrzebę.

7.Nie mieszaj języka polskiego oraz angielskiego - pisz w całości po angielsku.

Co do równoległej nauki PHP/SQL, to tak, od jakiegoś czasu to łączę, ale fakt, warto byłoby siąść nad SQLem porządnie na jakiś czas. Co do funkcji "zmienId", to otrzymuje ona nazwę grupy, w tym celu łącząc się z bazą, żeby zwrócić numer id do niej należący (który następnie wrzucam do rekordu użytkownika). Zestaw funkcji zrobiłem na potrzeby walidacji, żeby całe okno wyglądało nieco czytelniej, ale najpewniej wrzucę to po prostu jednorazowo do kodu.

0

Niestety nie mam pojęcia, jak to na stringa skonwertować.

Wrzuć kod jak próbowałeś.

Co do funkcji "zmienId", to otrzymuje ona nazwę grupy, w tym celu łącząc się z bazą, żeby zwrócić numer id do niej należący (który następnie wrzucam do rekordu użytkownika).

Nazwa funkcji powinna jak najdokładniej odwzorowywać to, co ona robi - skoro Twoja funkcja zmienId nic nie zmienia, dlaczego ma w nazwie zmień? getUserGroupIdByName i wszystko jasne.

0

Finalnie jest tak:

 $tmpGroupType = $user->getGroupType();
    $tmpLogin = $user->getLogin();
    $tmpPassword = $user->getPassword();
    $tmpName = $user->getName();
    $tmpSurname = $user->getSurname();
    $tmpBirthDate = $user->getBirthDate();

    try
    {
        $connection = new mysqli($host, $db_user, "", $db_name);

        if ($connection->connect_errno != 0)
            throw new Exception(mysqli_connect_errno());

        else
        {
            $result = $connection->query((sprintf("SELECT login FROM users WHERE login = '$tmpLogin'")));

            if ($result->num_rows > 0)
            {
                $_SESSION['loginRepeatingError'] = "This login exist in database yet.";
                $validateFlag = false;
            }

            if ($validateFlag)
            {
                $result = $connection->query(sprintf("SELECT groupId FROM groups WHERE name = '$tmpGroupType'"));
                $row = $result->fetch_assoc();
                $tmpGroupType = $row['groupId'];

                if ($connection->query("INSERT INTO users(userId, groupId, login, password,
                name, surname, birthDate) VALUES (NULL, '$tmpGroupType', '$tmpLogin', '$tmpPassword',
                '$tmpName', '$tmpSurname', '$tmpBirthDate')"))
                {
                    $_SESSION['succesfulJoin']= true;
                    echo "We added a new person to database succesfully.";
                }

I wszystko działa jak należy. Wrzuciłem jeszcze tutaj kod dobierający id grupy na podstawie jej nazwy (w miejsce uprzedniej biedafunkcji). Problem w tym, że samo istnienie obiektu pełni tylko funkcję dekoracyjną i mogłoby się obyć i bez niego: najpierw go tworzymy na podstawie danych z formularza, a potem od razu konwertujemy do zmiennych. Wcześniej usunąłem enkapsulację i wpisywałem metodą:

$connection->query("INSERT INTO users(userId, groupId, login, password,
                name, surname, birthDate) VALUES (NULL, '$user.groupType', '$user.login', '$user.password',
                '$user.name', '$user.surname', '$user.birthDate')") 

i wyskakiwał błąd, gdzie nie można potraktować obiektu jako stringa.

1

1.Po co Ci to sprintf tam? Dlaczego dopisujesz coś do kodu bo o tak se, zamiast przeczytać, pomyśleć oraz zrozumieć w jaki sposób to działa?
2.Nie wstawiaj zmiennych bezpośrednio do zapytania. - pisałem już o tym wcześniej.
3.Nie łącz się z bazą danych wewnątrz funkcji.
4.$_SESSION['succesfulJoin']= true; - success -> successful (dwa l).
5.This login exist in database yet. - w jakim to jest języku napisane?
6.We added a new person to database succesfully. -> New person has been added to the database.

Problem w tym, że samo istnienie obiektu pełni tylko funkcję dekoracyjną i mogłoby się obyć i bez niego: najpierw go tworzymy na podstawie danych z formularza, a potem od razu konwertujemy do zmiennych

Tak, ale dzięki temu nie musisz przekazywać miliona danych za pośrednictwem miliona parametrów, tylko tworzysz sobie jeden obiekt. Choć w Twoim przypadku wygodniej byłoby mieć klasę CreateUser z polami właśnie userName, userSurname itd., która dodawałaby użytkownika do bazy (i robiła tylko to!).

i wyskakiwał błąd, gdzie nie można potraktować obiektu jako stringa.

Skup się - skoro w PHP niemożliwa jest interpolacja wywołania metody obiektu do ciągu znaków, dlaczego nadal próbujesz to robić? Oprócz tego wstawiłeś kropkę do ciągu znaków, a nie wykorzystałeś operator konkatenacji, jak sugerowałem, przez co PHP próbuje przekonwertować instancję trzymaną w zmiennej $user na ciąg znaków (bo to, że sobie dopisałeś po $user kropkę absolutnie nic nie zmienia, ponieważ - jak wspomniałem - odpowiednia składnia do tego celu nie istnieje).

0
Patryk27 napisał(a):

1.Po co Ci to sprintf tam? Dlaczego dopisujesz coś do kodu bo o tak se, zamiast przeczytać, pomyśleć oraz zrozumieć w jaki sposób to działa?
2.Nie wstawiaj zmiennych bezpośrednio do zapytania. - pisałem już o tym wcześniej.
3.Nie łącz się z bazą danych wewnątrz funkcji.
4.$_SESSION['succesfulJoin']= true; - success -> successful (dwa l).
5.This login exist in database yet. - w jakim to jest języku napisane?

"Already" i "yet". Chyba nie przestanie mi się to mylić.

6.We added a new person to database succesfully. -> New person has been added to the database.

Problem w tym, że samo istnienie obiektu pełni tylko funkcję dekoracyjną i mogłoby się obyć i bez niego: najpierw go tworzymy na podstawie danych z formularza, a potem od razu konwertujemy do zmiennych

Tak, ale dzięki temu nie musisz przekazywać miliona danych za pośrednictwem miliona parametrów, tylko tworzysz sobie jeden obiekt. Choć w Twoim przypadku wygodniej byłoby mieć klasę CreateUser z polami właśnie userName, userSurname itd., która dodawałaby użytkownika do bazy (i robiła tylko to!).

i wyskakiwał błąd, gdzie nie można potraktować obiektu jako stringa.

Skup się - skoro w PHP niemożliwa jest interpolacja wywołania metody obiektu do ciągu znaków, dlaczego nadal próbujesz to robić? Oprócz tego wstawiłeś kropkę do ciągu znaków, a nie wykorzystałeś operator konkatenacji, jak sugerowałem, przez co PHP próbuje przekonwertować instancję trzymaną w zmiennej $user na ciąg znaków (bo to, że sobie dopisałeś po $user kropkę absolutnie nic nie zmienia, ponieważ - jak wspomniałem - odpowiednia składnia do tego celu nie istnieje).

Co do łączenia z bazą w funkcji, to jesteśmy w tym miejscu po prostu w obszarze walidacji formularza, a nie w funkcji. Aktualnie problem rozumiem w taki sposób: nie wstawiamy do zapytania ani metod, ani zmiennych, a sprowadzamy nasze dane do stringów. W tym celu można użyć albo sprintf, albo konkatenacji (którą pomyliłem z operatorem wyłuskania, ale mniejsza). Konkatenacją string przełożyć próbowałem to w następujący sposób:

 '$user->password'" . "

I faktycznie działa. Czy teraz składniowo jest to poprawnie? Jeśli jednak chcemy z tego skorzystać, musimy uniknąć enkapsulacji, więc czy da się to zrobić tak, żeby nie ograniczało funkcjonalności obiektu?

1

Co do łączenia z bazą w funkcji, to jesteśmy w tym miejscu po prostu w obszarze walidacji formularza, a nie w funkcji

Nie rozumiem tego zdania.

Aktualnie problem rozumiem w taki sposób: nie wstawiamy do zapytania ani metod, ani zmiennych, a sprowadzamy nasze dane do stringów.

Bezpośrednio do treści zapytania nie powinieneś w żaden sposób wprowadzać tego, co otrzymujesz od użytkownika. Przestałbyś błądzić, gdybyś wpisał w Google php sql injection, zamiast wszystko próbował zgadywać.

Czy teraz składniowo jest to poprawnie?

A bo ja wiem - wrzuciłeś jakiś kawałek kodu, który nie ma sensu.

Jeśli jednak chcemy z tego skorzystać, musimy uniknąć enkapsulacji,

Co ma do tego enkapsulacja? :|

więc czy da się to zrobić tak, żeby nie ograniczało funkcjonalności obiektu?

Przecież w każdej z wersji, które się tu przewinęły, Twój obiekt był modelem anemicznym - gdzie więc tu pojawia się jakaś utrata funkcjonalności?

0

W porządku, poczytałem nieco o wszystkim i poza wykonaniem samej walidacji sprawdzających np. alfanumeryczność zmiennych w obiektach albo, czy imiona składają się z dużych liter i czy mają odpowiednią długość. Potem wykonałem sanityzację z użyciem html_entities:

  $user->setLogin(htmlentities($user->getLogin(), ENT_QUOTES, "UTF-8"));
    $user->setPassword(htmlentities($user->getPassword(), ENT_QUOTES, "UTF-8"));
    $user->setName(htmlentities($user->getName(), ENT_QUOTES, "UTF-8"));
    $user->setSurname(htmlentities($user->getSurname(), ENT_QUOTES, "UTF-8"));

Samo wprowadzanie zmiennych w końcu udało mi się zrobić z wykorzystaniem konkatenacji i zachowaniem enkapsulacji. Co do modelu anemicznego, zastanawiam się, czy funkcji odpowiadających za walidację nie przenieść właśnie do klasy jako metody, póki co są osobno.

 if ($validateFlag)
            {
                $result = $connection->query("SELECT groupId FROM groups WHERE name = '".$user->getGroupType()."'");
                $row = $result->fetch_assoc();
                $user->setGroupType($row['groupId']);

                if ($connection->query("INSERT INTO users(userId, groupId, login, password,
                name, surname, birthDate) VALUES (NULL, '" . $user->getGroupType() . "', '". $user->getLogin() . "',
                '".$user->getPassword()."','".$user->getName()."','".$user->getSurname()."','".$user->getBirthDate()."')"))
                {
                    $_SESSION['succesfulJoin']= true;
                    echo "New user has been added to database.";
                }

                else
                {
                    throw new Exception($connection->error);
                }
            }

Sam kod powinien być zatem zabezpieczony, chociażby na to wstrzykiwanie SQL. I pojawia się pytanie: na ile bezpieczna jest w tym momencie całość i czy można to jeszcze usprawnić? Są zahashowane jeszcze hasła.

0

Czy gdybyś miał piętnaście pól do wypełnienia, nadal wszędzie kopiowałbyś ten sam kod htmlentities?
Poza tym w dalszym ciągu to jest tylko obejście problemu, a nie jego naprawienie - poczytaj o bindowaniu danych w PDO.

Co do modelu anemicznego, zastanawiam się, czy funkcji odpowiadających za walidację nie przenieść właśnie do klasy jako metody

Tak, wydziel tam.

pojawia się pytanie: na ile bezpieczna jest w tym momencie całość i czy można to jeszcze usprawnić?

Tak, zastosuj ORM ;-)

Albo przynajmniej wydziel odrębną warstwę dostępu do danych, cobyś nie musiał ręcznie klepać każdego zapytania (hasła kluczowe: data access object, table gateway pattern, orm, mvc).
Na przykład utwórz sobie obiekt UserTable (czy tam UserDAO, czy też jakakolwiek tam nazwa powoduje u Ciebie erek, ehm - zdania wśród programistów są podzielone), w którym to dopiero będzie istnieć metoda createUser wykonująca zapytania - dzięki temu nie będziesz musiał klepać zapytań w Twoich a'la serwisach.

Luźny przykład, aby pokazać o czym myślę:

<?php

class UserDao
	extends GenericDao {
	
	/**
	 * @param string $login
	 * @param string $password
	 * @return int|null
	 */
	public function createUser($login, $password) {
		$stmt = $this->db->prepare('INSERT INTO `users` (login, password) VALUES (:login, :password)');
		
		$stmt->bindValue('login', $login);
		$stmt->bindValue('password', $password);
		
		if ($stmt->execute()) {
			return $this->db->lastInsertedId();
		} else {
			return null;
		}
	}
	
}

/* ----- gdzieś dalej w kodzie ----- */

if ($validateFlag) {
	$result = $connection->query('...');
	
	// ...
	
	$userDao = new UserDao();
	
	if (!$userDao->createUser($user->getLogin(), $user->getPassword()) {
		throw new Exception('Nie udało się utworzyć użytkownika, szory.');
	}
	
	echo 'Cieszmy się i weselmy!';
}

Zauważ, że zmierzamy do rozbijania problemu na coraz mniejsze części - w mojej wersji na pierwszy rzut oka widać, co się dzieje, i jest - na oko - milion osiemset sześćdziesiąt trzy razy łatwiejsza do debugowania, ponieważ można skupić się na tym, co dany fragment kodu robi (widać, że tworzy użytkownika), a nie jak to w danym momencie się dzieje (wykonywane jest zapytanie).

Polecam poczytać właśnie o tym, jak poszczególne frameworki rozwiązują problem mapowania tabel na obiekty, zanim zabierzesz się za pisanie czegoś większego - zaoszczędzisz sobie wielu kłopotów :-)

PS dlaczego w Twoim zapytaniu jest groupId, lecz już metoda brzmi getGroupType? Wszystko powinno mieć wspólne nazewnictwo - zmniejsza to szansę na pomylenie metod oraz kolizję nazw.

PPS bardziej haxi0rskie byłoby dodatkowo nie tworzenie ręcznie zapytania w ogóle, tylko napisanie sobie klasy która potrafi robić to sama - ale to zostawiam Ci jako zadanie ;-)

0

Dzięki wielkie za pomoc:). Zapoznam się z tym wszystkim. Walidację dodam do klasy użytkownika. Co do metod tworzących zapytania, nie przekraczałoby to już SRP, jeśli wrzuciłbym to do użytkownika? Lepiej chyba stworzyć nową? I ostatnia sprawa: mógłbyś polecić jakieś konkretne książki odnośnie PHP/SQL?:)

0
Patryk27 napisał(a):

Czy gdybyś miał piętnaście pól do wypełnienia, nadal wszędzie kopiowałbyś ten sam kod htmlentities?
Poza tym w dalszym ciągu to jest tylko obejście problemu, a nie jego naprawienie - poczytaj o bindowaniu danych w PDO.

Co do modelu anemicznego, zastanawiam się, czy funkcji odpowiadających za walidację nie przenieść właśnie do klasy jako metody

Tak, wydziel tam.

pojawia się pytanie: na ile bezpieczna jest w tym momencie całość i czy można to jeszcze usprawnić?

Tak, zastosuj ORM ;-)

Albo przynajmniej wydziel odrębną warstwę dostępu do danych, cobyś nie musiał ręcznie klepać każdego zapytania (hasła kluczowe: data access object, table gateway pattern, orm, mvc).
Na przykład utwórz sobie obiekt UserTable (czy tam UserDAO, czy też jakakolwiek tam nazwa powoduje u Ciebie erek, ehm - zdania wśród programistów są podzielone), w którym to dopiero będzie istnieć metoda createUser wykonująca zapytania - dzięki temu nie będziesz musiał klepać zapytań w Twoich a'la serwisach.

Luźny przykład, aby pokazać o czym myślę:

<?php

class UserDao
	extends GenericDao {
	
	/**
	 * @param string $login
	 * @param string $password
	 * @return int|null
	 */
	public function createUser($login, $password) {
		$stmt = $this->db->prepare('INSERT INTO `users` (login, password) VALUES (:login, :password)');
		
		$stmt->bindValue('login', $login);
		$stmt->bindValue('password', $password);
		
		if ($stmt->execute()) {
			return $this->db->lastInsertedId();
		} else {
			return null;
		}
	}
	
}

/* ----- gdzieś dalej w kodzie ----- */

if ($validateFlag) {
	$result = $connection->query('...');
	
	// ...
	
	$userDao = new UserDao();
	
	if (!$userDao->createUser($user->getLogin(), $user->getPassword()) {
		throw new Exception('Nie udało się utworzyć użytkownika, szory.');
	}
	
	echo 'Cieszmy się i weselmy!';
}

Zauważ, że zmierzamy do rozbijania problemu na coraz mniejsze części - w mojej wersji na pierwszy rzut oka widać, co się dzieje, i jest - na oko - milion osiemset sześćdziesiąt trzy razy łatwiejsza do debugowania, ponieważ można skupić się na tym, co dany fragment kodu robi (widać, że tworzy użytkownika), a nie jak to w danym momencie się dzieje (wykonywane jest zapytanie).

Polecam poczytać właśnie o tym, jak poszczególne frameworki rozwiązują problem mapowania tabel na obiekty, zanim zabierzesz się za pisanie czegoś większego - zaoszczędzisz sobie wielu kłopotów :-)

PS dlaczego w Twoim zapytaniu jest groupId, lecz już metoda brzmi getGroupType? Wszystko powinno mieć wspólne nazewnictwo - zmniejsza to szansę na pomylenie metod oraz kolizję nazw.

PPS bardziej haxi0rskie byłoby dodatkowo nie tworzenie ręcznie zapytania w ogóle, tylko napisanie sobie klasy która potrafi robić to sama - ale to zostawiam Ci jako zadanie ;-)

Można to samo wykonać za pomocą konstruktora.

class AddUserToDb
{

protected $login;
protected $pass;
function __contruct($login, $pass)
{
    $this->login = $login;
    $this->pass = $pass;
}

public function addToDB
{
           $stmt = $this->db->prepare('INSERT INTO `users` (login, password) VALUES (:login, :password)');
 		$stmt->bindValue('login', $this->login);
 		$stmt->bindValue('password', $this->pass);
 		
 		if ($stmt->execute()) 
               {
 			return $this->db->lastInsertedId(); 		
                } else {
			return null;
		}
             }

}

$add = new AddUserToDb($login, $haslo)
$add-> addToDB();
0

Prosiłbym o odpowiedź odnośnie tego SRP i klasy przechowującej pytania. Generalnie stworzyłbym wówczas obiekt, który przechowuje same metody (trochę przeciwieństwo modelu anemicznego). Czy jest to w ogóle poprawne z obiektowego punktu widzenia?

1 użytkowników online, w tym zalogowanych: 0, gości: 1