Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: DbM Framework - Autorska aplikacja frameworka opartego na wzorcu MVC
Forum PHP.pl > Inne > Oceny
Stron: 1, 2
Malinaa
Witajcie,
miałem chwilę i usiadłem do autorskiego frameworka opartego na wzorcu MVC.
Chciałbym go dopracować, utworzyć wersje stabilną.

Kod frameworka jest dostępny pod adresem:
https://github.com/artimman/dbmframework

Zakończyłem pierwszy test aplikacji na serwerze zdalnym - powodzeniem.
Wydaje się, że już jest całkiem Ok i ciekawe, czy ktoś się ze mną zgodzi?
nospor
ok, to na plus:
+ znajomosc jako tako klas
+ uzywanie typowania w wiekszosci miejsc.
+ prawie uzywanie najnowszej wersji php wink.gif


a teraz troche krytki:
w ogole na poczatek to zaprzyjaznij sie z takmi narzedziami jak :
- php-cs-fixer
- phpstan
- inne do statycznej analizy kodu
One wylapia ci na dzien dobry naprawde duzo bledow
I generalnie mowie tutaj o bledach ktore nie sa moze jakos krytyczne, ale w dluzszej perspektywie beda uciazliwe do poprawnej pracy z twoim kodem.


NIe wiem jak planujesz docelowo dostarczac swoj FW, ale na chwile obecna widze wrzuciles go fo VENDOR a ten katalog jest zastrzezony dla COMPOSER. wywal go wiec stamtad i wsadz nie wiem, np do LIBS.

No i jesli twoj kod uzywa np phpmailer, ktory jest zapisany w composer.json to nie zapisuj go w GIT. Katalog VENDOR generalnie w GIT ma sie nie znalezc w ogole. po to jest composer

plik config.php rowniez powinien nazywac sie np config.php.dist i dopiero ludzie kopiuja go sobie jako config.php lokalnie. Dlaczego? bo z kazdym updatem z twojego gita, ludzie straca swoje zmiany gdy to zostanie jak teraz

declare(strict_types=1); ma byc w kazdym pliku php a nie w co drugim

Potworki w stylu
IF
IF
IF
IF
IF
az oczy bola wink.gif NIe bede omawial wszystkich bo w pyte tego masz, ale przyklad jak to sie poprawia
Jesli masz kod
IF (costam) {
//blabla
return 'cos tam'
}

return null;

To zeby uniknac zagniezdzenia duzego to sie robi poprostu negacje na pocatku, wali nullem na poczatku a reszta duzego kodu leci juz bez zagniezdzenia czyli:
IF (!costam) {
return null;
}
//blabla
return 'cos tam'

Jak widzisz w zagniezdzeniu jest tylko return null a nie milion linijek

public function __construct()
{
try {
$this->connect = new PDO("mysql:host=" . DB_HOST . ";dbname=" . DB_DATABASE, DB_USER, DB_PASSWORD, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_WARNING));
$this->connect->exec("SET NAMES utf8");

return $this->connect;
} catch (PDOException $exception) {
throw new DbmException($exception->getMessage(), $exception->getCode());
}
}
No przeciez konstruktow nigdy nic nie zwraca wiec po grzyba tam return? konstruktor sam w sobie jest "returnem" wink.gif

public function querySql(string $sql, ?string $fetch = null): PDOStatement
{
if ($fetch == 'assoc') {
$stmt = $this->connect->query($sql, PDO::FETCH_ASSOC);
} else {
$stmt = $this->connect->query($sql);
}

if (!$stmt) {
throw new DbmException($this->connect->errorInfo()[2], $this->connect->errorInfo()[1]);
} else {
return $stmt;
}
}

po co tu ten fetch jest raz ze stringiem a na dodatek nullem? skoro on odpowiada tylko za dwie mozliwosci, to zrob z niego boola i juz. Dodatkowo ten drugi ELSE na dole jest totalnei zbedny. :

public function querySql(string $sql, bool $fetch = false): PDOStatement
{
if ($fetch) {
$stmt = $this->connect->query($sql, PDO::FETCH_ASSOC);
} else {
$stmt = $this->connect->query($sql);
}

if (!$stmt) {
throw new DbmException($this->connect->errorInfo()[2], $this->connect->errorInfo()[1]);
}
return $stmt;

}
Analogicznie cala masa innych funkcji tam

public function requestData(string $fieldName)
{
if ($_SERVER['REQUEST_METHOD'] == "POST" || $_SERVER['REQUEST_METHOD'] == 'post') {
if (array_key_exists($fieldName, $_POST)) {
return trim($_POST[$fieldName]);
}
} elseif ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'get') {
if (array_key_exists($fieldName, $_GET)) {
return trim($_GET[$fieldName]);
}
}
}
To ze ktos wyslal dane POSTem, nie znaczy ze dane nie znajduja sie tez w GET. wlasnie ta funkcja zlikwidowales polowe funkcjonalnosci dla ludzia.

public function setDataToDB($value)
{
$value = strip_tags($value);
$value = htmlspecialchars($value);

return $value;
}
A co ty mi tutaj kasujesz tagi z pola co chce wlozyc do bazy? Jak bede chcial skasowac to sam sobie skasuje. poza tym uzywasz bindowania wiec po co htmlspecialchars? To sie uzywa podczas wyswietlania a nie przed wkladaniem do bazy. Ta cala funkcja jest totalnie zbedna

public function userPermissions(int $user): string
{
$database = new DbmDatabase();

$query = "SELECT roles FROM dbm_user WHERE id = ?";

if ($database->queryExecute($query, [$user])) {
if ($database->rowCount() > 0) {
$data = $database->fetchObject();

return $data->roles;
} else {
return 'dataNotFound';
}
} else {
return 'dataQueryError';
}
}
Jesli funkcja zwraca role, to ma zwracac role a nie komunikaty bledow. Od bledow masz wyjatki.I znowu wpyta zagniezdzen tutaj


public static function temp_htmlUser($sessionUserId, $module = null): void
{
$database = new DatabaseClass();
$userId = (int) $sessionUserId;

$query = "SELECT user.login, user.avatar, user_details.fullname FROM dbm_user user"
. " INNER JOIN dbm_user_details user_details ON user_details.user_id = user.id"
. " WHERE user.id = '$userId'";

if ($database->queryExecute($query)) {
$data = $database->fetchObject();
Czemu ta funkcja radosnie tworzy polaczenie do bazy i jeszcze sama z siebie pobiera usera? polaczenie z baza ma byc stworzone rac w calej aplikacji i przekazywane potem do odpowiednich klas. W tym momecnie wczasie jednego request ty generujesz mase polaczen do bazy.
Rowniez obiekt usera ma byc pobrany raz i przekazywane do odpowiednich klas.

Klasa TranslationClass. Raz ze te Class w nazwie jest zbedne, a dwa raz funkcje z malej raz z z duzej... generalnie maja byc z malej.

W klasie DatabaseClass, znowy Class zbedne ale:
public function __construct()
{
try {
$this->connect = new PDO("mysql:host=" . DB_HOST . ";dbname=" . DB_DATABASE, DB_USER, DB_PASSWORD, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_WARNING));
$this->connect->exec("SET NAMES utf8");

Ty tutaj znowu tworzyc nowy obiekt PDO, czyli nowe polaczenia. Kazdy model z tego dziedziczy, wiec jak odpalisz 3 modele to masz juz 3 nowe polaczenia do bazy. No tak sie nie robil .Jak pisalem wczesniej, jedno polaczenia do bazy masz tworzyc i ono ma byc przekazywan tam gdzie trzeba

public function getSection(int $id): object
{
$query = "SELECT * FROM dbm_article_sections WHERE id = '$id'";

$this->queryExecute($query);

if ($this->rowCount() > 0) {
return $this->fetchObject();
}

return (object) [];
}
I znowy strasznie mieszasz style. Raz jak nie ma rekordu to zwracasz NULL a tu radosnie zwracasz pusty obiekt. No sie zdecyduj na jedno i sie tego trzymaj


public function userSigninCorrect(array $params, string $password): ?string
{
$query = "SELECT * FROM dbm_user WHERE (login=:login OR email=:email) AND verified=true LIMIT 1";

if ($this->queryExecute($query, $params)) {
if ($this->rowCount() > 0) {
$result = $this->fetchObject();

if (password_verify($password, $result->password)) {
return $result->id;
} else {
return self::VALID_PASSWORD;
}
} else {
return self::VALID_LOGIN;
}
} else {
return null;
}
}
I tutaj znowu, funkcja ktora powinna zwracac info czy user sie zalogowal czy nie to zwraca albo jako text id usera albo komunikaty bledow... No prosze cie wink.gif

public const VALID_LOGIN = 'loginNotFound';
public const VALID_PASSWORD = 'passwordNotMatched';
Chyba sie to powinno nazywac INVALID a nie VALID


Jeszcze tego tam jest torche ale juz mi sie nie chce sprawdzac. Generalnie idziesz w dobrym kierunku powiedzmy, ale musisz troche popracowac jeszcze
Malinaa
Dzięki bardzo za sprawdzenie kodu.

Narzędzia były tu zaprzyjaźnione:
php-cs-fixer - przeleciał kod bez błędu

jako że fixer naprawdę nie pokazał żadnego błędu to phpstan sobie odpuściłem
nie wiem co w tym uciążliwego, chyba że mowa tu o doskonałym kodzie, ale o takim nie słyszałem,
co najwyżej jest idealny, gdzie po jakiejś chwili pojawia się kolejna wersja jakże doskonałego kodu.

Z katalogiem vendor ta mam taką rozkminkę co, jak? Z tego co widzę Symfony jest w /vendor, więc dlaczego chcesz wsadzić tego frameworka do /libs? Jak idealnie poukładać te katalogi?
Tutaj pojawia się więcej znaków zapytania, co kiedy zaktualizuje silnik aplikacji, przydałby się jakiś mechanizm dla aktualizacji, tylko jak go zrobići tak, aby świetnie współpracował z Composer itd.?
Katalogu vendor generalnie nie powinno być w ogóle na Gicie. W takim przypadku jak załadować silnik frameworka najlepiej do katalogu vendor? Podobnie jak w Symfony.

Plik config.php na config.php.dist - faktycznie, racja, jakoś jeszcze nie pomyślałem o tym (nawet jeszcze nie testowałem, czy Composer działa na zdalnym, skopiowałem projekt z Gita i wykonałem pierwsze uruchomienie)

declare(strict_types=1); - no to muszę jeszcze poprzeglądać plik po pliku

Milion linijek if'ów już nie dawało mi dostać się do snu w nocy - zajrzę na to, może teraz coś mi się lepszego przyśni

Z $this->connect i dalej $database->queryExecute($query) tu coś się zamotałem, kur.de jak poprawić te połączenia? Ma być jedno połączenie i pozostałe... mają z takiego korzystać.

Aby przejść dalej to muszę poprawić powyższe... na tym połączeniu z bazą danych itp. zamotałem się! Jak to poprawić?

P.S. Czy musisz rozpier.dzielać mi serducho z tym radośnie zaś?
Czuje się jak Wesoły Romek, może to lepiej niż jakiś Zenek, albo Ziutek, ale generalnie to jeden czort,
może by tak chociaż od Święta zamiast Jasiu pomyśleć Jan Kowalski, chyba widać tu różnicę smile.gif
nospor
phpstan sprawdza innego rodzaju rzeczy wiec polecam mimo wszystko

Cytat
nie wiem co w tym uciążliwego, chyba że mowa tu o doskonałym kodzie, ale o takim nie słyszałem,
co najwyżej jest idealny, gdzie po jakiejś chwili pojawia się kolejna wersja jakże doskonałego kodu.

Jesli wywoluje twoja metode ktora powinny mi zwrocic string, a ona jako string zwraca mi jeszcze bledy i ja musze znac kod tych bledow i je obslugiwac, to jest to super uciazliwe.
Jesli odpale x modeli i one wszystkie tworza mi nowe polaczenie i mam wielu klientow na raz, to nagle baza mi zacznie mulic. znowu uciazliwe.
Jesli bede chcial z toba wspolpracowac i musial poprawiac cos w twoim kodzie, to sie zachlaszcze po dwoch godzinach wink.gif
Ja sam nie pisze idealnego kodu, zawsze jest cos do poprawki. Ale jak ktos pokazuje sensowne bledy to nie lece po ambicji.

Jak juz mowilem: VENDOR jest zarezerwowany dla COMPOSER. Twoj lib nie idzie przez composer, ty go wsadzasz na sile w GIT do VENDOR i to jest zle. Tak, Symfony jest w vendor, ale on tam wpada z composer.
Ja VENDOR moge skasowac, potem odpalic composer install i mi sie wszystko odbuduje samo. W twoim wypadku, ja skasuje VENDOR i szlag trafil projekt.
Jak mowilem, VENDOR ma nie byc w GIT. VENDOR sam sie buduje jak odpalisz composer install. Na tym to wlasnie polega a ty tego nie rozumiesz.

Co do polaczen to poczytaj o DI (dependency injection). Ewentualnie zastosuj SINGLETON - generalnie sie tego nie poleca, ale w twoim wypadku poprawi funkcjonalnosc


Cytat
P.S. Czy musisz rozpier.dzielać mi serducho z tym radośnie zaś?

Sluchaj, ja ci tego nie pisze ze zlosci, z mysla "o, kolejny koles ktoremu dopieke"...
Poswiecilem troche czasu by przejrzec twoj kod i ci pomoc przez konstruktywna krytyke.
Ale jesli zle to odbierasz to skasuj temat, zapomnij o sprawie i pisz dalej po swojemu. Tylko nie pisz wiecej ze napisales juz zajebisty kod i kto sie z toba zgadza wink.gif
Malinaa
Kod
Na tym to wlasnie polega a ty tego nie rozumiesz.

Oj, rozumiem, co nie oznacza że już wiem jak prawie idealnie zakodować.

Trochę obracasz kota ogonem. Napisałem: "Wydaje się, że już jest całkiem Ok", czy znaczy to samo jak piszesz: "ze napisales juz zajebisty kod". Nie, ale rozumiem.
Pewnie po prostu tak masz. Wierzę, że nie piszesz po złości, gdyby było inaczej nie prosiłbym o pomoc w napisaniu bezbłędnego kodu.
Z lekka irytuje mnie radośnie jak Wesoły Romek, ale nikt nie musi o tym wiedzieć, pewnie moja zasługa/wina, że jest tak radośnie i coś dziwnie odbieram.

Dzisiaj to już nie za bardzo jest czas, przed świętami raczej nie usiądę do poprawiania.

Wesołych Świąt.
Dziękuje za pomoc.
nospor
A ,teraz kumam do czego piles piszac te "radosnie" .Nie zakumalem ze to do mnie biggrin.gif
poprostu tak pisze. Jesli ktos robi cos w jednym schemacie, a potem nie z gruszki ni z pietruszki zmienia na cos innego to pisze po prostu "radosnie" . Bez zlosliwosci, ot takie powiedzonko.Tak samo pisze, gdy oceniam komus kod w firmie.
Tak jak ty zawsze zwracales NULL gdy nie bylo rekordu, a potem w jednej funkcji radosnie zwrociles pusty OBJECT.

Jak nie chcesz swojego liba wrzucac do katalug LIB, tylko twardo sie trzymasz VENDOR, to zajrzyj do composera dokumentacji, tam masz podane jak sie importuje prywatne repozytoria z github przez composer. I juz. Ale wywal ten folder VENDOR i wszystko co w nim masz, tak samo jak phpmailer. On jest w composer.json i juz go nie nie powiniinies trzymac w swoim git.
netir
Jak zobaczyłem w model raw query bez bindowania to już przestałem dalej sprawdzać (model nie powinien wiedzieć tyle o implementacji warstwy danych) smile.gif Na pewno jest to ciekawe ćwiczenie do zrozumienia wielu aspektów budowania frameworka i chyba jako ćwiczenie należy to oceniać tongue.gif
  1. $query = "SELECT article.id AS aid, article.image_thumb, article.page_header, article.page_content, section.id AS sid, section.section_name, details.user_id AS uid, details.fullname"
  2. ." FROM dbm_article article"
  3. ." JOIN dbm_article_sections section ON section.id = article.section_id"
  4. ." JOIN dbm_user_details details ON details.user_id = article.user_id"
  5. ." ORDER BY article.created DESC LIMIT $limit";
  6.  
  7. $this->queryExecute($query);
Malinaa
Cytat(nospor @ 21.12.2023, 09:42:45 ) *
1. w ogole na poczatek to zaprzyjaznij sie z takmi narzedziami jak :
- php-cs-fixer
- phpstan
- inne

2. NIe wiem jak planujesz docelowo dostarczac swoj FW, ale na chwile obecna widze wrzuciles go fo VENDOR a ten katalog jest zastrzezony dla COMPOSER. wywal go wiec stamtad i wsadz nie wiem, np do LIBS.

3. No i jesli twoj kod uzywa np phpmailer, ktory jest zapisany w composer.json to nie zapisuj go w GIT. Katalog VENDOR generalnie w GIT ma sie nie znalezc w ogole. po to jest composer

4. plik config.php rowniez powinien nazywac sie np config.php.dist i dopiero ludzie kopiuja go sobie jako config.php lokalnie. Dlaczego? bo z kazdym updatem z twojego gita, ludzie straca swoje zmiany gdy to zostanie jak teraz

5. declare(strict_types=1); ma byc w kazdym pliku php a nie w co drugim

6. Potworki w stylu IF...

7. public function __construct()

8. public function querySql(string $sql, ?string $fetch = null): PDOStatement

9. public function requestData(string $fieldName)

10. public function setDataToDB($value)

11. public function userPermissions(int $user): string

12. public static function temp_htmlUser($sessionUserId, $module = null): void

13. W klasie DatabaseClass
Ty tutaj znowu tworzyc nowy obiekt PDO, czyli nowe polaczenia.

14. public function getSection(int $id): object

15. public function userSigninCorrect(array $params, string $password): ?string

16. public const VALID_LOGIN = 'loginNotFound';


1.
a) php-cs-fixer - jest zainstalowany - pokazuje bez błędów
b ) phpstan - doinstalowałem - pokazuje błąd

Line Controller\IndexController.php
------ ------------------------------------------------------------------------------------
:45 Access to constant BLOG_INDEX_ITEM_LIMIT on an unknown class App\Config\Constants.
💡 Learn more at https://phpstan.org/user-guide/discovering-symbols
------ ----------------------------------------------------------------------------

nie wiem o co chodzi z tym błędem?

c) inne - jakie to jeszcze inne narzędzia

2 i 3. FW dałem do katalogu library.
Usunąłem vendor -> wykonałem composer update i się załadował nowy vendor, czyli powinno być Git (do przetestowania na zdalnym).

Z katalogiem vendor jest pytanie.
Nie jest potrzebny na Gicie, composer go tworzy - Ok, ale co kiedy kod jest w wersji CMS czyli dla zielonych, kiedy zostawię vendor uruchomią aplikacje bez problemu, ale jeśli usunę to nie wykonają polecenia composer i aplikacja nie zadziała. Nie odpalą composera tym bardziej na zdalnym serwerze, ba zwykle taki user nie ma na serwerze SSH, a na pewno nie wie po co to. Zostawiam vendor i problem z głowy, zadziała nawet bez SSH.

4. Dodałem config.php.dist teraz zastanawiam się, czy to coś dało kiedy po zmianie nazwy z config.php.dist na config.php Git i tak będzie widzieć taką zmianę itd. Tu raczej jakiś git ignore config.php trzeba by wstawić?

5. declare(strict_types=1); dopisałem, ale ma być w każdym pliku .php, chyba nie w tempates np. base.html.php ?

6. IFy, może np. tak:

Kod
public function getSections(): ?array
    {
        $query = "SELECT * FROM dbm_article_sections ORDER BY id ASC";

        $this->queryExecute($query);

        if ($this->rowCount() > 0) {
            return $this->fetchAllObject();
        }

        return null;
    }


ponieważ według tego co napisałeś:

Kod
public function getSections(): ?array
    {
        $query = "SELECT * FROM dbm_article_sections ORDER BY id ASC";

        $this->queryExecute($query);

        if ($this->rowCount() == 0) {
            return null;
        }

        return $this->fetchAllObject();
    }

z taką negacją na początku - jasne, że tak się robi, tylko w tym przypadku jakoś mi nie pasuje i nie wygląda najlepiej if count == 0 ? Tu zawsze było if count > 0 !
Jak powinna wyglądać więc ta metoda, tak aby było super git?

7. Nie wiem skąd ten return w konstruktorze - usunąłem.

class DatabaseClass {}

Konstruktor zmieniony, ale czy nie będzie bardziej poprawnie kiedy zamiast DB_HOST odznaczę private $dbHost = DB_HOST; itd. czy bez różnicy, tak i tak jest ok?
Przypomniało mi się, że gdzieś czytałem o exec(); że należy do metod niebezpiecznych i nie raz jest wyłaaczone na serwerze, więc raczej lepiej napisać w wersji z $options = []; ?

8. Ten $fetch wolałbym zostawić, ponieważ przy rozbudowie to nie będzie boolean, można dodać tu więcej opcji niż dwie true/false.

9. public function requestData(string $fieldName) może jakiś pomysł jak poprawić, aby było na 100%?

10. public function setDataToDB($value) czyli do usunięcia.
Czy to tak można zezwalać na zapisywanie wszystkiego do bazy danych co user wklepie w formularz?

11. public function userPermissions(int $user): string - tylko rola, więc komunikaty usuwam.

12. public static function temp_htmlUser($sessionUserId, $module = null): void
Jest oznaczone "temp" czyli tymczasowe do napisania od nowa.
Nie wiem jak wykonać tu połączenie z bazą danych w inny sposób, tzn. pojedyncze?

13. Nie za bardzo wiem jak poprawić całość na takie jedno połączenie z bazą danych?

14. Widzę, że return (object) [] to już kombinacja alpejska, ale

if ($this->rowCount() == 0) {
return null;
}
return $this->fetchObject();

też świetne nie będzie, czy można jeszcze inaczerj (świetnie)?

15. Ta funkcja nie sprawdza czy user zalogowany, a zwraca jesli wystąpi bład komunikat do formularza logowania, czyli jest tu potrzebny string.

16. Miało nazywać się VALIDATION_LOGIN walidacja loginu, ale skróciłem na VALID_LOGIN, zmienione na VALIDATION_LOGIN itd.
Short -> full name - to kosmetyka, czy jest uciążliwe?
nospor
ad1) Nie widzi klasy App\Config\Constants
Jeszcze inne? np. psalm

ad2,3
No niestety, na super zielonych i swiety boze nie pomoze.
Jak bardzo chcesz to dodaj instrukcje skad wziasc biblioteki takie jak phpMailer i zeby wgrac je do katagu vendor. No ale i wowczas caly szlag trafi autoloading itp. wiec generalnie nie przejmuj sie tym.

ad4 tak, config.php ma byc w .gitignore.

ad5) no tylko w plikach klas

ad6 ja podalem ci negacje IFow gdy masz duzy blok kodu w IF. Przyklad co tu pokazales nie lapie sie do tego

ad7. Troche sie zgubilem. Co ma do tego exec() ?

ad9 No nie zakladaj, ze skoro metoda poszla POST, to ze tytko masz dane w post. Jesli metoda POST, to szukaj najpierw w POST, a jak nie ma to zajrzyj tez do GET.

ad10
Jak pisalem, uzywasz bindowania wiec baza jest bezpieczna.
htmlspecialchars() sie uzywa przed wywsietleniem danych a nie przed wlozeniem ich do bazy.
Jesli zas bedziesz mial jakies krytyczne pola, gdzie nie moga pojsc konkretne rzeczy, to tam przed zatwierdzeniem forma, dodajesz VALIDACJE, czy dane sa w porzadku.

ad12,13
Uzyj wzorca SINGLETON na klasie DatabaseClass. I wywal te "Class" z tych wszystkich nazw

ad14
No a co jest zlego w tym?
if ($this->rowCount() == 0) {
return null;
}
return $this->fetchObject();

Jak nic nie ma to zwracasz NULL a jak jest to zwracasz obiekt co chciales. Wiec chyba ok tak?

ad15
No ale to albo zwraca userId albo zwraca komunikat bledu. Wszystko to jest tekstem. Skad ja mam wiedziec czy otrzymany tekst to id uzytkownika i tym samym ok, czy moze to jednak komunikat bledu? No to nie ma sensu. A co oznacza NULL?
Przerob to na funkcje ktore zwraca ID zalogowanego usera albo wyjatek gdy cos nie tak

  1. <?php
  2. public function getSignedUserId(array $params, string $password): int
  3. {
  4. $query = "SELECT * FROM dbm_user WHERE (login=:login OR email=:email) AND verified=true LIMIT 1";
  5.  
  6. $res = $this->queryExecute($query, $params);
  7. if (!$res) {
  8. throw new \Exception('Something went wrong');
  9. }
  10.  
  11. if ($this->rowCount() == 0) {
  12. throw new \Exception('Invalid login or email');
  13. }
  14.  
  15. $result = $this->fetchObject();
  16.  
  17. if (!password_verify($password, $result->password)) {
  18. throw new \Exception('Invalid password');
  19.  
  20. }
  21.  
  22. return (int) $result->id;
  23. }
  24. ?>

Zwroc tez uwage jak pozbylem sie tych duzych zagniezdzen co miales. u mnie masz tylko jedno zagniezdzenie a u ciebie byly az 3 podzagniezdzenia. Kod teraz wyglada o niebo czytelniej

ad16
Twoj skrot jest uciazliwy bo tak go skrociles ze nadale przeciwne znaczenie.
Malinaa
1. Jak sprawić, aby widział klasę App\Config\Constants, czy takie umieszczenie stałych w tym pliku jest ok?
Czy plik może zostać w katalogu, w którym się znajduje, czy należy przenieść do katalogu application (autoloader). Wówczas będzie widoczny i wszystko ok.

2 i 3. w katalogu /vendor/ zostawię tylko autoloading i dodałem informacje co jak w README.md

4 - 9.. zrobione

10. sprawdziłem metoda nie była w ogóle używana, więc została usunięta

12 i 13 Jeżeli SINGLETON nie jest zalecane, zróbmy tak jak powinno być z Dependency Injection
Próbowałem zrobić, ale coś nie za bardzo idzie, zacząłem poprawiać od:

Kod
class DatabaseClass extends PDO
{
    //private $connect;
    private $result;
    //public $pdo;
    
    public function __construct() // __construct(PDO $pdo)
    {
        try {
            $dbDSN = "mysql:host=" . DB_HOST . ";dbname=" . DB_DATABASE;
            $dbOptions = [
                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8",
            ];

            //$this->connect = new PDO($dbDSN, DB_USER, DB_PASSWORD, $dbOptions);
            parent::__construct($dbDSN, DB_USER, DB_PASSWORD, $dbOptions);
        } catch (PDOException $exception) {
            throw new DbmException($exception->getMessage(), $exception->getCode());
        }
    }
...
}


Jedno połączenie wszędzie gdzie tylko jest potrzebne wykonanie zapytania.
Pytanie jak byś to zrobił, aby wstrzyknąć połączenie w plikach i metodach:

Kod
class FrameworkClass
{
...

    // User permissions
    public function userPermissions(int $id): ?string
    {
        $database = new DbmDatabase(); // TODO! Jak zmienic, aby bylo OK?

        $query = "SELECT roles FROM dbm_user WHERE id = ?"; // TODO! Jak to jest z :id lub znakiem zapytania, czy tak samo jest bezpieczne?

        $database->queryExecute($query, [$id]);

        if ($database->rowCount() == 0) {
            return null;
        }

        $data = $database->fetchObject();

        return $data->roles;
    }
}


Kod
class TemplateClass
{
...

    /* TODO! Temporary. Change to full htmlUserNavigation() ? */
    public static function temp_htmlUser($sessionUserId, $module = null): void
    {
        $database = new DatabaseClass();
        $userId = (int) $sessionUserId;
        ...
    }
}


Te Class to trochę tak celowo zostawiłem, aby nad tym chwilę pomyśleć jak powinny nazywać się te klasy oraz folder(y) w obecnym /library/dbmframework/ (folder classes, methods) mając na względzie, że może dodałbym zaciąganie tych klas i kodu do katalogu /vendor/. Poza tym np. ExceptionClass.php nie pasuje zmienić na Exception.php -> class Exception {} podobnie też class Database {} i pozostałe miałby zbyt ogólne nazwy, nie za bardzo to mi się podoba, ponieważ trzeba wówczas dodawać aliasy np. Exception as MyException;. Dodatkowo, czy trzymać wszystko w jednym katalogu, czy może lepiej podzielić te pliki i klasy do subkatalogów i dalej co z namespace też zmienić odpowiedni w zależności, czy dzielimy klasy i kod na subkatalogi? Trochę zastanawiające jak poukładać te pliki i klasy w dobrą całość.

14, Jakoś miałem wrażenie, że
if ($this->rowCount() > 0) { }
jest Ok, bynajmniej logicznie nadal mam takie wrażenie, chociaż bez zagnieżdżenia wygląda lepiej.

15. Metoda ma zwrócić string, nie int i służy do wyświetlania komunikatów w formularzu, więc nie może być throw.
Pozbyłem się tych zagnieżdżeń i wygląda lepiej.

16. Dla jasności zmienione na bez skrótów, które jak się okazuje mogą być mylące.

Mam prośbę o pomoc w ogarnięciu Dependency Injection w projekcie, bo się przy tym już pogubiłem.
nospor
ad1 Klasy maja byc widoczne w autoloading i wtedy powinny byc widoczne przez analizatory.
Swoja droga pisales ze zadnych innych bledow ci nie pluly. Troche dziwne, bo przegldajac twoj kod powinno wypluc wiecej bledow. Na pewno dobrze to skonfigurowales by patrzylo na wszystkie katalogi/pliki?

ad15
Jesli twoja metoda jako tekst zwraca albo id uzytkownika, albo komunikat bledu, to jest to zle zaprojektowana metoda. juz ci to pisalem. wiec sie zdecyduj co ona ma zwraca, albo komunikat bledu, albo id uzytkownika.
Zas co do throw to po to masz TRY CATCH by to wlasnie tam zlapac

ad13:
no Singleton w twoim miejscu bylby najlepszy. Najszybciej bys go wdrozyl. Ale jesli nie chcesz to o to:
$database = new DbmDatabase();
masz zrobic tylko raz w swojej aplikacje, w jakims glownym core, chociazby w index.php i potem te $database masz przekazywac do kazdych innych klas (w konstruktorze) ktore tego potrzebuja. Ale twoj kod nie jest na to przygotowany wiec dlatego juz lepiej bys uzyl Singleton
Malinaa
1. Klasa przeniesiona i widoczna - całość bez błędów.

Narzędzia sprawdzające jakość kodu i błędy nie pluły mi błędów poza tym jednym co się powtarzał x-razy o klasie która jest nie widoczna
oraz drobiazg, o którym nie pisałem, bo ogólnie wystarczyło przenieść echo() do nowej linii.

15. Ok, ale zostawiam tę metodę, aby nie musieć pisać dwóch, ponieważ to id jest używane tylko w session value i jest stringiem.
Taka nie typowa metoda, na pewno słyszałeś 2 in 1 smile.gif

13. Rozumiem, że byłby lepszy, ale to powinno być po prostu super dobrze.

Czyli w pliku głównym index.php tu gdzie mam kod Routa dodaję Database:

Kod
### RENDER PAGE ###
use Dbm\Classes\RoutClass;
use Dbm\Classes\DatabaseClass; // as DbmDatabase;

new RoutClass();

$database = new DatabaseClass();


i jak dalej przygotować ten mój kod pod DI, ponieważ nie pomyślałem o tym na początku, a teraz przy tym DI to już się zamotałem.
nospor
Cytat
ale to powinno być po prostu super dobrze.

Z jednej strony nalegasz na super dobrze, a z drugiej strony piszesz metode ktora zwraca albo ID albo komunikat bledu, wszystko jako tekst i czort wie czy to co zwrocilo to id czy moze jednak error i sie upierasz ze tak ma byc wink.gif

Singleton u ciebie bedzie OK bo caly kod nadal nie jest super dobrze.

No ale jak sie upierasz to w FrameworkClass w metoddzie model() masz
return new $modelNamespace();
tam wiec do constructora masz przekazac $database
A skad FrameworkClass ma miec $database? No to widze kontroller dziedziczy po FC wiec w RoutClass masz przekazac do kontrolera w konstruktorze $database.
A skad RoutClass ma miec $database? No widze ze w index.php tworzysz obiekt RoutClass wiec tam masz przekazac jeszcze $database

I tak z kazda sciezka gdzie $database jest wykorzystywane

  1.  
  2. $database = new DatabaseClass();
  3. new RoutClass($database);




Albo zaimplementuj Registry, wloz raz $database do registry i mozesz pominac pare krokow.
Albo zastosuj singleton wink.gif

edit: wlasnie sobie uswiadomilem ze i tak ta cala sciezka z $database co ci teraz podalem jest o kant 4 liter skoro u ciebie kazdy model dziedzicy po DatabaseClass a ta w konstruktorze na dzien dobry tworzy nowe polaczenie z baza
Dlatego nic juz niekombinuj, tylko utworz ten singleton na klasie DatabaseCLass i problem z glowy
Tylko zeby zrobic z tego Singleton, to wywal to dziedziczenie po PDO co widze dodales ostatnio w klasie DatabaseClass rob normalnie new PDO itp. Oczywiscie okraszone juz Singletonem


edit2:
A tu masz pokaze ci jeszcze jak sie pozbywac tych nieszczesnych zagniezdzen
Aktualnie masz taka metode (przeczytaj komentarze co tam wlozylem)
  1. public function queryExecute(string $query, ?array $params = [], bool $reference = false): bool
  2. {
  3. try {
  4. $this->result = $this->prepare($query);
  5.  
  6. if (empty($params)) {
  7. return $this->result->execute();
  8. } else {
  9. // PO CO TEN ELSE? Przeciez IF mial RETURN wiec ELSE NIEPOTRZEBNY
  10. $first = array_key_first($params);
  11.  
  12. if (is_string($first)) {
  13. // PO CO ten dlugi kod w tym IF? Nie lepiej zrobic negacje i w IF tylko wlozysz jeden prosty return?
  14. foreach ($params as $key => &$value) {
  15. is_int($value) ? $type = PDO::PARAM_INT : $type = PDO::PARAM_STR;
  16.  
  17. if (!$reference) {
  18. $this->result->bindValue($key, $value, $type);
  19. } else {
  20. $this->result->bindParam($key, $value, $type);
  21. }
  22. }
  23.  
  24. return $this->result->execute();
  25. }
  26.  
  27. return $this->result->execute($params);
  28. }
  29. } catch (PDOException $exception) {
  30. throw new DbmException($exception->getMessage(), $exception->errorInfo[1]);
  31. }
  32. }


A tu po poprawkach, Zniknely dwa zbedne zagniezdzenia i od razu czytelniej.
  1. public function queryExecute(string $query, ?array $params = [], bool $reference = false): bool
  2. {
  3. try {
  4. $this->result = $this->prepare($query);
  5.  
  6. if (empty($params)) {
  7. return $this->result->execute();
  8. }
  9.  
  10. $first = array_key_first($params);
  11.  
  12. if (!is_string($first)) {
  13. return $this->result->execute($params);
  14. }
  15.  
  16. foreach ($params as $key => &$value) {
  17. is_int($value) ? $type = PDO::PARAM_INT : $type = PDO::PARAM_STR;
  18.  
  19. if (!$reference) {
  20. $this->result->bindValue($key, $value, $type);
  21. } else {
  22. $this->result->bindParam($key, $value, $type);
  23. }
  24. }
  25.  
  26.  
  27. return $this->result->execute();
  28.  
  29. } catch (PDOException $exception) {
  30. throw new DbmException($exception->getMessage(), $exception->errorInfo[1]);
  31. }
  32. }
Malinaa
Cytat
Z jednej strony nalegasz na super dobrze, a z drugiej strony piszesz metode ktora zwraca albo ID albo komunikat bledu...


Kod znajdujący się w folderze /library/dbmframework/ oraz bezpośrednio z nim powiązany nalegam, aby napisać super dobrze.
Metoda o której piszesz bardziej jest związana z wersją demo (cms), nie jest jakaś super kluczowa, to tylko demo, jak coś będzie tu zakombinowane w stylu 2w1 - no problem.
Element demo cms - na luzie. Jak to wytłumaczyć, może spójrz na to w ten sposób, że przy kolejnym projekcie opartym o dbmframework folder /application/ będzie pusty, wszystko co jest w tym folderze będzie od nowa tworzone w nowej wersji (nie cms).
P.S. Przykładowo mam skrypt płatności, który napisałem 10 lat temu, przydałoby się go napisać od nowa i chciałbym oprzeć projekt od library ->dbmframework. Czy teraz kaman? Kaman beauty smile.gif

Uparłeś się na Singleton, więc zacząłem pisać pod ten Singleton:

Kod
class DatabaseClass // implements SingletonInterface - * Przyszły mi tu na myśl interfejsy, fajnie byłoby dodać takie do aplikacji np. w /library/dbmframework/interfaces/ pytanie jak tworzyć interfejsy, które później można fajne wstrzykiwać np. do konstruktora itp. itd.
{
    private static $instance = null; // static - po dodaniu pierwszego elementu dla Singletona zaczyna się już jakaś katastrofa !?
    private $connect;
    private $statement;

    //private function __construct() // po zmianie na private - wysypie się
    public function __construct()
    {
        try {
            $dbDSN = "mysql:host=" . DB_HOST . ";dbname=" . DB_DATABASE;
            $dbOptions = [
                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8",
            ];

            $this->connect = new PDO($dbDSN, DB_USER, DB_PASSWORD, $dbOptions);
        } catch (PDOException $exception) {
            throw new DbmException($exception->getMessage(), $exception->getCode());
        }
    }

    public static function getInstance() //: Result ?
    {
        if (!self::$instance) {
            self::$instance = new DatabaseClass();
        }

        return self::$instance;
    }

    public function getConnection() //: Result ?
    {
        return $this->connect;
    }
}


Przy Singleton o ile widzę tworzymy tu zmienne globalne - to nie może tak być, okropnie wygląda, nie róbmy tego.

Modele, o których piszesz jak widzę i tak muszą zostać poprawione (przerobione), coś nie sposób w nich wstawić chociażby konstruktora.

Kod
class BlogModel extends DatabaseClass // TODO! Remove extends DatabaseClass
{
    /* TODO! private $database;

    public function __construct(DatabaseClass $database)
    {
        $this->database = $database;
    } */
..
}


W kontrolerach jest podobnie lipa, brak możliwości wstrzykiwania do konstruktora

Kod
class IndexController extends FrameworkClass
{
    private $blogModel;
    private $translation;

    /*
     * TODO! public function __construct(TranslationClass $translation)
     */
    public function __construct()
    {
        $this->blogModel = $this->model('BlogModel'); // TODO! Zmienic sposob ladowania ClassModel ?!

        $translation = new TranslationClass();
        $this->translation = $translation;
    }
...
}


gdzie np. w Symfony jest AbstractController i można do konstruktora wstrzykiwać co dusza zapragnie - super.

Prośba, nalegam wink.gif zróbmy Dependency Injection.

Dzięki za poprawki i komentarze w queryExecute().
Przy if ($this->rowCount() == 0) {} miałem mieszane wrażenia, zawsze bardziej pasowało mi tu if ($this->rowCount() > 0) {} ale bez zagnieżdżeń jest lepiej.
W przesłanym przykładzie akurat bez dwóch zdań po co te Ify teraz jest dobrze smile.gif
nospor
NIe wiem o co ci chodzi z zmiennymi globalnymi w SINGLETON, skoro SINGLETON nie tworzy zmiennych globalnych


Olej singleton, popraw sobie troche te DatabaseClass na
  1. class DatabaseClass
  2. {
  3. protected static $connect;
  4.  
  5.  
  6. public function __construct()
  7. {
  8. try {
  9.  
  10. if (!self::$connect) {
  11. $dbDSN = "mysql:host=" . DB_HOST . ";dbname=" . DB_DATABASE;
  12. $dbOptions = [
  13. PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
  14. PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8",
  15. ];
  16.  
  17. self::$connect = new PDO($dbDSN, DB_USER, DB_PASSWORD, $dbOptions);
  18. }
  19. } catch (PDOException $exception) {
  20. throw new DbmException($exception->getMessage(), $exception->getCode());
  21. }
  22. }
  23. // reszta co miales gdzies tam
  24.  
  25. }

I juz. Teraz sobie mozesz robic i milion razy new DatabaseClass() i Modeli z tego dzieciczacych a i tak ci zrobi tyklo jedno polaczenie PDO. I juz

Co do prawidlowego DI to trzeba by u cibie w pyte zmieniac a ja nie mam czasu teraz nad tym myslec. Chyba ze inna dobra dusza sie zdecuduje za to brac
Malinaa
Z protected static $connect to takie zakombinowane, lepiej bo jak rozumiem mamy teraz jedno połączenie, ale czy jest dobrze?!

Innych dusz kumatych to coś nie widać, więc daj znać jakbyś znalazł trochę czasu.
nospor
Cytat
Z protected static $connect to takie zakombinowane, lepiej bo jak rozumiem mamy teraz jedno połączenie, ale czy jest dobrze?!

No jest troche zakombinowane, ale czasami trzeba podejsc do tematu pragmatycznie. Na chwile obecna to bedzie dobrze, bo dzieki temu unikasz tworzenia kilku polaczen do tej samej bazy danych wiec maszz poprawie o 470%* w porownaniu do tego co bylo wink.gif


Cytat
nnych dusz kumatych to coś nie widać, więc daj znać jakbyś znalazł trochę czasu.

ok



*tak wiem, wartosc wzialem z powietrza ale poprawa i tak jest
viking
https://github.com/artimman/dbmframework/bl...config.php.dist
Dlaczego zamiast użyć https://github.com/vlucas/phpdotenv to masz tego potwora?

w .gitignore masz vendor a jednak jest na serwerze.
Trochę mi się nie podoba że kontrolery nic nie zwracają, a sama metoda view robi include i na tym koniec. Takie wrażenie niezamkniętego requestu.
Malinaa
Cytat(nospor @ 10.01.2024, 09:55:45 ) *
No jest troche zakombinowane, ale czasami trzeba podejsc do tematu pragmatycznie...


Podejście pragmatyczne w programowaniu, brzmi dość filozoficznie, być może przekracza moje doświadczenia. Wystarczy, że skoncentrujemy się na wspomnianej abstrakcji smile.gif

* z powietrza? To chyba jakiś chwyt marketingowy, 470% kiedy 100% to max, może 47%, ewentualnie 4,7 tzn. 5 razy lepiej
i poprawa widoczna gołym okiem smile.gif

Cytat(viking)
config.php.dist - potwór?


1. Przy instalacji należy zmienić nazwę na config.php - nie wiem dlaczego to jest potwór?
2. O ile rozumiem chcesz zamienić config.php.dist na .env
Podałeś jednak od razu link na jakąś petardę, może jakiś przykład dla zielonych (nie git gotowiec, a czysty kod), bo mam mieszane uczucia, nie wiem co chcesz zrobić.
3. Tak racja (musiałem podejść do tematu pragmatycznie), z katalogiem vendor rzecz zrobiła się bardziej złożona, mogę próbować wytłumaczyć jeśli trzeba, ale przeczytaj README.md co powinno rozjaśnić kłopot. którym teoretycznie można by się nie przejmować... ale odbiorca (klient) jest bardzo istotny.

Też mi się trochę nie podoba rozwiązanie z kontrolerami i metodami (do poprawki), ale nie mam coś pomysłu na lepsze.
Jak masz pomysł na poukładanie kodu w stabilną całość - podaj koniecznie rozwiązanie problemu, a będę mówił Ci Królu przez cały tydzień.
nospor
Cytat
Podejście pragmatyczne w programowaniu, brzmi dość filozoficznie,

A ja jakos w robocie dosc czesto musze do tematu podchodzic pragmatycznie bo zrobienie czegos w sposob podrecznikowy, poprostu zajmie 10x dluzej czasu, albo bedzie wolniejsze albo to albo tamto.Takze wiedza wiedzą ale umiejetnosc adaptacji do panujacych warunkow tez wazna wink.gif
Malinaa
Cytat(nospor @ 11.01.2024, 12:03:10 ) *
A ja jakos w robocie dosc czesto musze do tematu podchodzic pragmatycznie...

Z filozoficznego punktu widzenia:
" Wyobraź sobie że życie polega na żonglowaniu pięcioma piłkami. Ich nazwy to praca, rodzina, zdrowie, przyjaciele i prawość. Wszystko udaje ci się utrzymywać w powietrzu. Ale pewnego dnia wreszcie do ciebie dociera, że praca jest gumową piłką. Jeżeli ją upuścisz, odbije się i wróci. Pozostałe cztery piłki - rodzina, zdrowie, przyjaciele, prawość - to szklane kule. Jeśli się którąś upuści, może się obić, wyszczerbić lub nawet roztrzaskać.
smile.gif

No, ale wracamy na polską ziemię 10x szybciej, jeśli środowisko tego wymaga itp. itd. Jasne.
viking
Cytat(Malinaa @ 11.01.2024, 11:55:06 ) *
1. Przy instalacji należy zmienić nazwę na config.php - nie wiem dlaczego to jest potwór?
2. O ile rozumiem chcesz zamienić config.php.dist na .env
Podałeś jednak od razu link na jakąś petardę, może jakiś przykład dla zielonych (nie git gotowiec, a czysty kod), bo mam mieszane uczucia, nie wiem co chcesz zrobić.
3. Tak racja (musiałem podejść do tematu pragmatycznie), z katalogiem vendor rzecz zrobiła się bardziej złożona, mogę próbować wytłumaczyć jeśli trzeba, ale przeczytaj README.md co powinno rozjaśnić kłopot. którym teoretycznie można by się nie przejmować... ale odbiorca (klient) jest bardzo istotny.

Też mi się trochę nie podoba rozwiązanie z kontrolerami i metodami (do poprawki), ale nie mam coś pomysłu na lepsze.
Jak masz pomysł na poukładanie kodu w stabilną całość - podaj koniecznie rozwiązanie problemu, a będę mówił Ci Królu przez cały tydzień.


Większość osób które chciałyby wrzucić taki config na swojego gita pewnie puści to jak leci zapisując w nim wszystkie hasła do systemu. .env jest uniwersalne, powinno być wykluczone z commita. Są też różne środowiska. Np osoba pracująca z kontenerami może chcieć zaczytać env do kontenera podczas uruchamiania swojego stacka. Poza tym nie lubię jak wszędzie pałętają się jakieś stałe.
Przykładów jak używać masz pełno, np https://github.com/vlucas/phpdotenv#immutab...y-customization

Dlaczego mam czytać readme żeby dowiedzieć się coś o vendor? Tego folderu nie ma prawa być. Są różne wersje php, OS, różne zależności. Tych plików nie wrzuca się ot tak.

Poprawny kod powinien być zgodny z https://www.php-fig.org/psr/psr-15/

Nie rozumiem nigdy tego pisania własnego FW przez początkujących. Nie, nie jest to dobra metoda bo nabierasz złych nawyków, nie masz kogoś, kto nad tobą stoi i wytyka cały czas błędy. Poużywaj trochę mainstreamowe fwameworki, zobacz jak w nich robi się pewne rzeczy. A jak już będziesz na poziomie pro wtedy można coś myśleć (chociaż i tak nie ma to sensu).
Malinaa
Cytat(viking @ 11.01.2024, 12:39:55 ) *
Większość osób które chciałyby...


Aby większość osób nie wrzuciła config z hasłami na gita dodany został plik config.php.dist natomiast config.php jest .gitignore, więc nie wiem dlaczego - potwór.
Na pewno lepiej będzie przerobić na .env - dzięki za info.

Nie chcesz przeczytać, ok. Przecież nie spodziewałem się, że chcesz, więc tłumaczenie mamy z głowy.

Co tu rozumieć, potrzebny jest kod w czystym PHP do prostych aplikacji, czyli wzorzec MVC (frameworkowy) do takich systemów jest lux, nadaje się do systemu CMS.
Poziom pro, ponownie nie wiem co masz na myśli, czy też co chcesz zrobić, albo czego nie chce Ci się robić, poza tym co lub kogo lubisz, może nie lubisz... "chociaż i tak nie ma to sensu",
więc abyśmy nie pisali bez sensu, może zapytam krótko: co Twoim zdaniem ma sens?
viking
Przeczytać przeczytałem ale napisałem dlaczego to jest bez sensu. Vendor i zależności tworzone są w zależności od OS i wersji php. To że sobie coś wrzucisz u kogoś innego nie oznacza z góry że to zadziała. Sam php mailer ma np zależności
Cytat
"ext-ctype": "*","ext-filter": "*","ext-hash": "*"
U kogoś nie będzie i już nie działa. Nie dowiesz się tego bez instalacji, sypnie błędem w którymś momencie wykonywania kodu.

Wzorzec MVC jest standardem i owszem wszędzie się nada. Ale jego implementacja robi różnicę. Jest od groma różnych frameworków. Przykładowo https://www.slimframework.com/ wchodzę na stronę i widząc go pierwszy raz wiem jak dodać kolejną podstronę. A to dlatego że przestrzega reguł (psr). Wiem że ma testy i dużo osób od lat go poprawia. U Ciebie nie dość że trzeba się przekopać przez kod który tylko Ty rozumiesz to nie ma żadnej gwarancji że on działa poprawnie.

Laravel 11 też dąży do tego aby na start było jak najmniej, do tego ma gigantyczną społeczność i pełną integrację z różnymi projektami zewnętrznymi (alpine, tailwind itp). Znów ogromna ilość testów, osób które nad nim pracują i fajne rozwiązania których nigdy nie wdrożysz u siebie (nawet to ograniczenie php 7.3 gdzie mamy już 8.3).

To tylko dwa przykłady. I żeby nie było, dobrze że piszesz coś tylko IMO najpierw popracuj z innymi FW, zobacz jak coś jest zrobione i na pewno dojdziesz do wniosku że to co napisałeś jest do zaorania (też dobrze).
Malinaa
Rozumiem, mimo to chciałbym opracować mechanizm (w wersji stabilnej) oparty na wzorcu MVC (chyba już z czystej ciekawości), ale dzięki za wytykanie błędów.
IMO? Wyobraźnia jest nieograniczona, reszta to taki chwyt marketingowy, w którym nowości zawsze wygrywają (to kwestia czasu kiedy inne FW też zostaną zaorane) wink.gif
viking
To na początek ja bym spróbował ogarnąć temat z którym masz tutaj taki problem czyli rozwiązanie z singletonem. Spróbuj tak przepisać kod żeby zaimplementować jakiś gotowy system dependency injection np https://php-di.org/ (propozycja losowa). I poczytaj chociaż dokumentację innych fw żeby zobaczyć co można robić i w jaki sposób.
Malinaa
Wydawało mi się, że takie powszechne rozwiązanie jak framework oparty na wzorcu MVC na moje potrzeby (wspomniany CMS i proste aplikacje) będzie najlepszym rozwiązaniem, a teraz to już nie wiem,
tzn. wiem, że nic innowacyjnego nie wymyślam i pewnie nic innowacyjnego tu już nie wymyślę, jeżeli masz jakiś genialny pomysły to fajnie byłoby zastosować, nie wiem co mam powiedzieć -> łap okazje -> będzie można się czymś wyróżnić.

Problematyczny temat to już próbowałem ogarnąć, nie był to początek, bardziej wygląda na koniec, ale tak jak będzie jeszcze na to czas, spróbuję z dependency injection,
wszak chciałbym wiedzieć jak to się dzieje, że taka "żarówka" świeci i ją zbudować, chociaż większości osób wystarcza on/off i też są happy.

P.S. Dokumentacje w j. ang. można czytać, jeśli ma być ze zrozumieniem to na 50% zobaczę co można robić i w jaki sposób, czyli trafię bankowo w najciekawsze kawałki.
com
Malinaa musisz sobie postawić zasadnicze pytanie poco to tworzysz? Kiedy będziesz szukał potencjalnej pracy kiedyś zakładam na pewno to nastąpi zapytają Cie jakie frameworki znasz, nie powiesz im przecież, że tylko "DbM Framework" bo nikt tego poza Tobą nie zna. Dziś startując na rynku pracy większość ofert wymaga od pracownika znajomości jednego z fw: Symfony, Laravel itp. Jakaś bazę wiedzy już zebrałeś i większość z nas pisała kiedyś własny framework albo swojego cmsa, bo kiedyś to było modne, czasy się zmieniły, dziś nie ma to już sensu, a tworzenie takiego czegoś często uczy Cie od razu z automatu złych praktyk, bo nie masz żadnego mentora który wytyka błędy, nospor i viking dotknęli tylko szczytu góry lodowej przeglądając to w mniej czy bardziej dokładny sposób, ale dziś to nie wystarczy. Podstawami do nauki PHP od zawsze była dokumentacja, ale oprócz tego przez lata wypracowane zostały pewne standardy oznaczone jako PSR https://www.php-fig.org/psr/ i jeśli tworzysz oprogramowanie i się do nich nie stosujesz to od początku popełniasz błąd, który w próżniejszym czasie będzie Cie kosztował nauka złych nawyków których nie będziesz się w łatwy sposób w stanie pozbyć. Polecałbym poczytać np coś takiego https://phptherightway.com/ i zamiast przepalać własne godziny na tworzenie własnego frameworka bez wiedzy i doświadczenia, skupić się na próbie zrozumienia jak działa jeden z powszechnych i dostępnych fw na rynku. A jeśli masz ambicja do tego żeby stworzyć własnego CMSa jako taki pet project dla samorozwoju, to właśnie oprzyj go na takim Symfony czy Laravel, dzięki temu uda Ci się zrozumieć jak to działa i nie będziesz uczył się złych praktyk, a poznasz wiele dobrych praktyk, szczególnie jeśli chodzi o Symfony to nie ma tam antywzorców itp Troche gorzej jest w Laravel, oczywiście da się je wyeliminować ale to trzeba być już na wyższym poziomie wtajemniczenia, niemniej jednak nawet użycie Laravel będzie miało równie wymierne korzyści(po prostu Laravel posiada/posiadał takie anty wzorce jak Active Record(można go zastąpić przez jakiś Data Mapper np Doctrine) oraz nadmiernie wykorzystywał wzorzec Fasady, ale pozostałe kwestie są tam na najwyższym poziomie). Do nauki polecam https://symfonycasts.com/ lub https://laracasts.com/. Na przyszłość jak już tworzysz własny Fw to jest coś takiego jak https://symfony.com/doc/current/create_framework/index.html i należało by się zastosować do tych zasad opisanych tam żeby to miało jakikolwiek sens smile.gif

Kiedy już opanujesz podstawy wybranego przez siebie fw, bez problemu jeśli trafisz na jakiś problem przy tworzeniu tego własnego CMSa znajdziesz tutaj na forum i na innych masę osób które znają ten fw na wylot i beda w stanie Ci pomoc, nakierować itp, nikt tego nie napisze za Ciebie ale to będzie dla Ciebie merytorycznie znacznie korzystniejsze niż ocenianie wielu godzin twojej pracy nad "DbM Framework", bo jakby się defakto nad tym mocno zastanowić i zastosować do PSR i innych dobrych praktyk to ten kod cały by trzeba napisać na nowo smile.gif Nie chcę Cie zrazić i nie odbierz tego jako hejt, to normalne kiedy osoba która się uczy zabiera się za tworzenie FW/CMS, a na jej kod spojrzy ktoś z dużo większym stażem, tez kiedyś zaczynałem i popełniłem taki sam projekt, zarówno robiłem własnego CMSa jak i fw w swojej karierze(ale dopiero pierwszy komercyjny projekt zrobiony w Symfony, nawet po latach jak do niego zajrzałem, to mimo iż dziś posiadam o wiele więcej doświadczenia niż wtedy, ale budowałem go zgodnie z dokumentacja na SynfonyCast wtedy defa kto nazywało się jeszcze KnpUniversity, to jak patrze na ten kod po latach to on nadal nie wymaga zmian, no możne poza tym że dziś bym dodał typy zmiennych wszędzie gdzie się tylko da, za to jak zaglądam do swojego cmsa/fw to widzę jak mało jeszcze wtedy znałem te technologie), ale to było ponad 15 lat temu, dziś bym się tego nie podjął a od początku po przestudiowaniu dokumentacji dla PHP zacząłbym eksperymenty pewnie z Symfony smile.gif Tobie również życzę by "DbM Framework" pozostało historia do której wrócisz za 10 lat i zobaczysz jaki przeskok w swojej wiedzy za ten czas zyskałeś i żeby pierwszy twój projekt w fw jaki sobie wybierzesz nadal za te 10 lat cieszył oko, a nawet jakby było tam cos do poprawy to żebyś mimo wszytko dostrzegał to jaka przepaść będzie dzielić cms na fw "DbM Framework" a na ogólnodostępnym fw, ale to myśle już teraz zauważysz jeśli spróbujesz pójść w te stronę smile.gif Bo jeszcze przed Tobą poznanie czym jest DDD i tworzenie kody który będzie Framework-agnostic, bo fw to jest taki Ninja Master toolbox(scyzoryk, pila, klucze w jednym) i jest on w miarę uniwersalny ale on powinien być tylko jednym z narzędzi ułatwiającym prace tak jak IDE jest dla pisania kodu i powinien pomagać a nie nas ograniczać smile.gif ale to gdzieś tam daleko w przyszłości zrozumiesz o czym mówię smile.gif

PS na koniec dodam jeszcze że w protokole HTTP nie da odzwierciedlić wzorca MVC, tutaj tworzona jest tylko jedna z wariacji bazująca na tej idei, ale nigdy nie będzie to pełnoprawny MVC, wiec w sumie powoli przestaje się tak nawet nazywać te fw(Jeśli przeczytasz o Symfony na nie polskiej stronie Wikipiedii, bo tam nikt tego nie redaguje to nie ma już nic wzmianki o MVC) wink.gif
Malinaa
Cytat(viking @ 11.01.2024, 14:32:23 ) *
Spróbuj tak przepisać kod żeby zaimplementować jakiś gotowy system dependency injection

viking piszę, że nie chcę żadnego gotowca, a na siłę podajesz gotowca za gotowcem.

Potrzebuję mechanizm, który działa bez Composera, Composer ma być opcjonalny, można użyć, ale nie ma takiej konieczności, aby uruchomić aplikacje typu CMS, albo coś prostszego ma wystarczyć wypełnienie formularza instalacyjnego z danymi typu login, hasło, serwer, baza danych -> klikamy Go i gotowe, aplikacja śmiga (bez żadnego composer install). W przypadku części kodu napisanej pod Landingpage obyłoby się też bez wypełniania formularza instalacji.
Co mi tu brakuje, aby poprawnie poukładać tych kilka plików w folderze library/dbmframework:
1. Wspomniane DI, które nie za bardzo wiem jak napisać dobrze w czystym kodzie (bez gotowca) tak, aby dało się używać w całej aplikacji.
2. Problem z kontrolerami i modelami, przydałoby się więcej abstrakcji i wstrzykiwanie, ale to jest powiązane z DI.

Wspomniałeś o katalogu vendor, że nie może w nim być nawet autoloadingu, nie ma go być w ogóle - kod poprawiony vendor usunięty, aplikacja działa bez vendora i Composera i już jest tak jak chciałem, a jak zechcesz użyć Composera to też wystarczy, że wykonasz composer install i będzie chodzić z Composerem.
Usunięty katalog vendor i var dodane do gitignore (program utworzy sobie var'a a composer vendor).

config.php - nie jest błędem, więc na ten czas podarujmy sobie .env, oki.

PSR 15 i Interfejsy - Królu naucz pisać porządne interfejsy, bo z interfejsami to mam zielono.
Czy takie tam Psr\Http\Server\RequestHandlerInterface można zastosować bez Composera? Jak to, kiedy musi być bezbłędnie smile.gif

SlimFramework jest Ok, bliski temu co przyszło mi na myśl, ale Composer jest tu niezbędny podobnie jak w każdym innym FW co nie spełnia mini wymogu - Mechanizm (DbM Framework) ma działać na czystym kodzie bez pakietów, bibliotek, Composera itd.
Poza tym SlimFramework pisany i poprawiny jest od kilkunastu lat, ma swoją społeczność itd. przy kodzie DbM FW posiedziałem w zeszłym roku przez jakiś miesiąc tworząc v1 i teraz drugie podejście i powstało v2 - no bez sensu byłoby zabierać się dzisiaj za kolejny framework i liczyć na oklaski, ale potrzebny jest wspomniany mechanizm na minimalistycznym, bezbłędnym kodzie.

Cytat
Malinaa musisz sobie postawić zasadnicze pytanie poco to tworzysz?

Pan Bóg stworzył istotę dla hecy, z tyłu plecy, z przodu plecy. A jednak po niej przyszedł ten, który był zrodzony, a nie stworzony smile.gif
Chcesz pomóc? Napisz jak mam zakodować DI i inne drobiazgi, o których pisałem wyżej.
Salvation
Cytat(Malinaa @ 18.01.2024, 21:38:13 ) *
(...) ma wystarczyć wypełnienie formularza instalacyjnego z danymi typu login, hasło, serwer, baza danych -> klikamy Go i gotowe, aplikacja śmiga (...)

No to wrzuć vendora do paczki instalacyjnej od razu. Tak robi wiele "gotowych" systemów. A composera i tak wdróż, bo niepotrzebnie wymyślasz koło na nowo.
Chyba, że chcesz się jedynie nauczyć tego co "pod maską", bo w przeciwnym razie ten autorski framework będzie tylko do szuflady.

Już znam firmy co wrzucają klientów na własny fw (swoją drogą, ciekawy model biznesowy), bo tworzenie go zajęło tyle, że jeszcze się nie spłacił.
Tomplus
Ja osobiście rozumiem dlaczego ktoś tworzy i stosuje własne FW. Mają kilka zalet:
- na początku są proste w obsłudze
- są lekkie
- uwzględniają specyfikę hostingu
- są szyte na miarę umiejętności twórcy.

Jednak problemy przychodzą gdy, projekt się rozrasta i różnych powiązań modułów jest coraz więcej. Zaczynają pojawiać się zbędne powtórzenia, blędy tam gdzie nie powinno ich być.
Malinaa
Mam chwilę, więc usiadłem do projektu. Dependency injection z tego co widzę tak szybko nie zrobię, właściwie to trzeba przerobić całość w katalogu /library/dbmframework/
https://github.com/artimman/dbmframework a następnie kontrolery itd.
a co gorsza nie mam pomysłu jak zrobić, aby było Git.

Cytat(Salvation @ 23.01.2024, 10:21:20 ) *
No to wrzuć vendora do paczki instalacyjnej od razu. Tak robi wiele "gotowych" systemów. A composera i tak wdróż, bo niepotrzebnie wymyślasz koło na nowo.
Chyba, że chcesz się jedynie nauczyć tego co "pod maską", bo w przeciwnym razie ten autorski framework będzie tylko do szuflady.
Już znam firmy co wrzucają klientów na własny fw (swoją drogą, ciekawy model biznesowy), bo tworzenie go zajęło tyle, że jeszcze się nie spłacił.


Z informacji ma być bez katalogu vendor!?
Zrobiłem tak, że w pliku index.php dodałem funkcje autoloadingWithWithoutComposer($pathAutoload); i rozpoznaje, czy został uruchomiony Compser, jeśli tak to autoloading leci z Composera, jeśli nie to dopisałem własny autoloadnig, któet wczytuje wszytsko co potrzeba bez Composera. Takie rozwiązanie nie jest chyba wymyślaniem koła od nowa? Jeżeli w tym rozwiązaniu coś nie gra, no to pytanie jak wrzycić vendora do paczki instalacyjnej, mając na względzie, ze pewnie ten vendor będzie generowany innaczej w zależości o wersji PHP.

Projekt ten ma charakter takiego "poligonu ćwiczebnego", nauczenia się tego co jest "pod maską", ale będzie super Git jeśli uda się wyciągnąć z niego coś więcej niż kod zaszufladkowany tym bardziej, że po prostu jest mi taki kod potrzebny, problem, aby napisać go bezbłędnie smile.gif

Tak daleko nie patrzyłem, ale ciekawy model biznesowy.

Cytat
Ja osobiście rozumiem dlaczego ktoś tworzy i stosuje własne FW.


Pocieszające słowa, bo już myślałem, że porywam się na coś co każdemu wydaje się być bez sensu i głupie, że aż głupio gadać.
Jeden poza oczywiście nosporem, który potrafi motywować smile.gif (nie zniechęcać).

Usiadłem do tego DI, ale już przy pierwszym uruchomieniu PHP-CS-Fixer pojawił się kłopot z szablonami, doszedłem do wniosku, ze projekt prosi się, aby dla templates utworzyć osobny katalog, więc tak też zrobiłem.
Wydaje się, że teraz jest Git, chociaż zamiast MVC i katalogów w application/ Ciontroller, Model, View mam teraz Controller, Model i ../templates/ .

Tu pojawia się kolejne pytanie, np. w IndexController miałem linie
$this->view("blog/index.html.php", $data); gdzie template był w index.html.php - tak to jakoś wymyśliłem na początku, ale nie widziałem takich nazw plików
i tak teraz sobie przypomniałem, czy nie lepiej aby zamiast index.html.php był plik index.phtml i tak należałoby przerobić wszystkie pliki w katalogu templates?

Wracając do DI i więcej abstrakcji w projekcie.

Plik np. IndexController jak mam tutaj zrobić wstrzykiwanie przy konstruktorze i metodach:
public function __construct(DatabaseClass $database, TranslationClass $translation)
public function index(TranslationClass $translation, etc...)

Plik RoutClass:
linia 41: $controllerNamespace = 'App\\Controller\\' . $this->controller;
linia 42: $this->controller = new $controllerNamespace;

oraz model, plik FrameworkClass:
linia 76: return new $modelNamespace;

Jakiś pomysł jak poskładać to co jest "pod maską" w katalogu /library/dbmframework/ ?
Ponieważ z tego co widzę obecnie wyszedł dwusuw, a potrzebny jest czterosuw ekonomiczny 2.0 200KM smile.gif
viking
Kontroler to generalnie nie jest miejsce na wciskanie całej logiki i wszystkich zależności. Gdybyś użył jakiegoś kontenera (jak podałem przykładowy php-di) to mógłbyś wtedy wykorzystać https://www.php-fig.org/psr/psr-11/ i np w jakimś swoim service używać $container->get(MyClass::class) żeby wyciągnąć instancję klasy. Trzeba by poczytać dokumentację bo ma kilka ciekawych rzeczy.
Malinaa
Cytat(viking @ 29.01.2024, 11:42:03 ) *
jak podałem przykładowy php-di

Przeglądałem podane przykładowe PHP-DI, ale wymaga użycia Composera i wówczas pewnie można by zrobić coś na kształt Slim framework,
ale jak już pisałem powinno funkcjonować bez konieczności użycia Composera, który jest tu opcjonalny, jeśli projekt wymagałby większej rozbudowy itd.

Na potrzeby obecnego projektu "maluszka" mogłoby wystarczyć to co jest, ale potrzebuję zastosować w kodzie DI (wstrzykiwanie) tylko bez żadnych gotowców,
gdyż bez tego o ile dobrze widzę jakakolwiek nieco większa rozbudowa nie ma sensu, ponieważ idąc już parę kroków dalej koło się zamyka, czyli lipa.

Dla przykładu zamiast obecnych templetów, które z rozszerzenia nazwa_pilku.html.php raczej przerobię na nazwa_pliku.phtml mogę chcieć rozbudować projekt, o któregoś gotowca (twig templating component),
zastosować np. Slim\Views\Twig chyba można ? i już tutaj muszę mieć w kontrolerach wstrzykiwanie. Jednak należy mieć na względzie, że to tylko opcja (jeżeli zdecyduje się użyć Composera, domyślnie templates/ będą z rozszerzeniem .phtml).

P.S. Sorki, ale obecnie nie miałem kiedy do tego usiąść, może przy weekendzie coś wymyślę.
viking
Musisz się w końcu zdecydować. Robisz to żeby się coś nauczyć i ewentualnie szukać potem pracy jako programista czy robisz coś dla siebie i nie ma znaczenia jak, byle jaki kod który jakoś działa. Nie oszukujmy się że ktoś ten "framework" prywatnie wykorzysta więc raczej chodzi o naukę. A z takim podejściem sam sobie kłody pod nogi rzucasz.
Malinaa
Cytat(viking @ 3.02.2024, 15:34:29 ) *
Musisz się w końcu zdecydować.

Jestem zdecydowany i nie interesuje mnie byle jakość. Tylko nie za bardzo rozumiem czy myślisz, że naprowadzasz mnie na właściwą drogę kiedy piszę któryś raz, że chcę jak najbardziej czysty PHP i HTML w templates, bez gotowców,
a opcjonalnie mieć możliwość użycia Composera i gotowych rozwiązań. Podałeś wcześniej "rozwiązania", które chyba nie rozwiązały żadnego opisanego problemu
i przy pierwszej lepszej okazji wytykasz swoje mądrości pisząc jakby to była jedyna dobra droga, oszukując jednocześnie na temat byle jakości, kiedy chyba nawet sam "czujesz", że nie po to tu jestem.

Pewnie jak zwykle i tak się zrozumiemy umiarkowanie, ale chciałbym zrobić to wstrzykiwanie np. w kontrolerach bez konieczności użycia Composera. Co w tym złego?
Napisałem to samo już któryś raz, ma się rozumieć nie da się bez Composera (plus PSR) itd. zrobić bezbłędnie, więc po temacie.

Z punktu widzenia rzeczy, o których się fizjologom nie śniło, tylko blondynom - jak to jest w WordPress CMS - użytkownik pobiera aplikacje, instaluje i gotowe, nie ma konieczności, ale zapewne można używać Composera?
Może przypasowałby tu silnik frameworka, a funkcjonalność CMS -> "Framework CMS", czy można jedno z drugim pogodzić, pewnie tak, ale wyjdzie "rakieta".
viking
Wstrzykiwanie zależności a menedżer (albo service locator w zależności od tego co chcemy użyć) to dwie różne rzeczy. Do samego di nie potrzebujesz composer.
Widok można sobie wstawić dowolny, jeśli będzie jeden standard to kod powinien implentowac jeden wspólny interfejs i wymiana to przełączenie w konfiguracji. To czy twój szablon będzie miał rozszerzenie phtml czy zupa to najmniejszy problem.
Ciężko się z tobą rozmawia, bo nie tylko ja zwracam uwagę na pewne rzeczy, które następnie ignorujesz, bo masz swoją lepszą wizję. Tylko niestety jesteś na bardzo początkującym poziomie i widać to po tych pomysłach. Skup się na tym żeby pisać dobry kod a nie archaizmy typu brak composer. Tak się pisało 15 lat temu. Tak, możesz się teraz na mnie obrazić ale mało mnie to interesuje. Cześć.
Malinaa
Kilka konkretnych informacji się pojawiło. Dzięki.

Na tym można by poprzestać, ale jak zwykle musiałeś pojechać z poziomem... No, jesteś Najlepszy.

P.S. Oj, Królu Złoty sądzisz, że z Tobą się lekko rozmawia, nie obrażajmy się,
ewentualnie jeśli kogoś szukasz, wybacz proszę nie jestem ideałem.

Composer jest zajebisty, więc nie obracaj kota ogonem, nigdzie nie pisałem że chcę bez Composera.
Wyobraź sobie wymóg jest taki, że musi działać też bez niego.
nospor
skoro tak bardzo nie chcesz uzywac DI co ci zaproponowano, to :

- modele niech nie dziedziczac po DatabaseClass tylko niech przyjmuja w konstuktorze obiekt DatabaseClass i go uzywaja
- obiekt DatabaseClass tworzysz raz w index.php i potem przekazujesz w konstruktorach dalej.
- np do FrameworkClass, ktore potem w metodzie model() nie przekazuje obiekt DatabaseClass do konkretnych modeli.

I tyle, zmian malo a masz pelne DI.

ps: i miejze litosc wywal te "Class" z nazw klas w koncu. To mialo sens 20 lat temu gdy klasy dopiero wchodzily a nie teraz gdy wszystko jest klasa
Malinaa
Cytat(nospor @ 4.02.2024, 20:07:12 ) *
1. modele niech nie dziedziczac po DatabaseClass tylko niech przyjmuja w konstuktorze obiekt DatabaseClass i go uzywaja
2. obiekt DatabaseClass tworzysz raz w index.php i potem przekazujesz w konstruktorach dalej.
3. np do FrameworkClass, ktore potem w metodzie model() nie przekazuje obiekt DatabaseClass do konkretnych modeli.


Zacząłem od początku od pliku index.php tu nie spodobało mi się poprzednie:

### RENDER PAGE ###
use Dbm\Classes\RoutClass;
new RoutClass();

Sprawdziłem co tam kiedyś napisałem w wersji 1 i nie maiłem routes, tylko taką sprytna metodę.
Dopisuję routing, ale po drodze stwierdziłem, że całość jest do przerobienia: struktuira katalogów i po kolei, przy okazji zmieniłem te Class na bez Class, bo tak chciałeś (mi to nie przeszkadzało, wydawało się, że podobnie jak NameInterface tak też NameClass to nie problem, a chociaż od razu widać, że to np. nie AbstractClass, czy coś jeszcze innego wink.gif mniejsza o to teraz jest bez i jest OK).

Teraz zamiast powyższego w pliku index.php mam
### ROUTER ###
$routes = require(BASE_DIRECTORY . 'application' . DS . 'routes.php');
$routes();
Pytanie, czy tak jest dobrze?

1. modele niech nie dziedziczac po DatabaseClass tylko niech przyjmuja w konstuktorze obiekt DatabaseClass i go uzywaja
Wcześniej bez zmiany na $routes nie można było nic do konstruktora w modelach wstrzyknąć po dodaniu kodu __construct() wysypywało się.
2. jak z pliku index.php przekazać Database w konstruktorach?
3. zamiast FrameworkClass jest AbstractController, - zmieniłem tu stary pomysł na modele bez możliwości używania konstruktora - teraz można wstrzykiwać w modelach.

Mamy plik index.php (w katalogu public) w przeglądarce otwieram stronę główną,
obsługuje ją klasa IndexController (src/Controller/) tu nadal coś jest nie tak, nie mogę wstrzyknąć do konstruktora

Kod
/*
     * TODO! public function __construct(Database $database, Translation $translation) // TODO! Wstrzykiwanie do konstruktora!?
     */
    public function __construct()
    {
        $database = new Database;

        $model = new BlogModel($database);
        $this->model = $model;

        $translation = new Translation();
        $this->translation = $translation;
    }


w powyższym konstruktorze jest model, no udało się tu poukładać kod i wstrzykuje

Plik BlogModel (src/Model)

Kod
public function __construct(Database $database)
    {
        $this->database = $database;
    }


Czy tak jest ok, bo coś nie czuje jak to jest z tym połączeniem, aby mieć jedno?

Pozostał przykładowy IndexController wstrzykiwanie do konstruktora, a do metod, czy też?
No i dalej abstract klasy, interfejsy, fabryki, I tyle, więcej nie pamiętam.

Zaproponowane DI będę chciał się zająć, ale w pierwszej kolejności chciałbym dobrze poskładać całość bez Composera i gotowców.
nospor
Niby sluchasz co sie do ciebie mowi ale jednoczesnie nie sluchasz.

Mowie wyraznie: obiekt Database ma robic w index.php a nie w zadnym indexController....

Obiekt $database, ktory zrobisz w index.php masz potem przekazac do wszystkiego innego co go uzywa. A skoro z index.php przechodzisz do Route, to masz ten obiekt $database przekazac do Route a potem w route przekazujesz dalej czyli do kontrolerow itd itd. Schodzisz caly czas w dol, tu nie ma zadnej magii
Malinaa
Jeżeli słucham to jak mogę nie słuchać. Rozumiem, że nie ma w tym żadnej magii, ale nie potrafię zrobić tego przejścia dobrze, coś się wysypuje i w tym problem.
Piszemy o tym któryś raz i jak piszesz dla Ciebie to proste, a nie kumam, nie że nie słucham, a zawiesiłem się w tym miejscu (chyba potrzebny reset ;-)

Database mam zrobić w public/index.php, czyli jak rozumiem ma być tak:

// Routing and database connection
use Dbm\Classes\Database;

$database = new Database;

$routes = require(BASE_DIRECTORY . 'application' . DS . 'routes.php');
$routes($database); // -> dodane $database

dalej mam plik routes.php

return function (Database $database) { // -> dodane $database
$uri = $_SERVER['REQUEST_URI'];

$router = new Router();
...
}

następnie to nic mi z tego przekazywania nie wychodzi, więc jak dalej... ?
nospor
No masz dalej dodawac w dol te $database

$router = new Router($database);


Cytat
Jeżeli słucham to jak mogę nie słuchać.

Skoro mowie index.php a ty dodajesz w INdexController to jak ja mam to rozumiec skolei?
Malinaa
Dotąd już miałem
$router = new Router($database); i więcej..
ale idąc dalej i słuchając i tak musiałem dodać w IndexController bo się sypało,
w którymś miejscu dalej nie wychodzi
nospor
zajebisty opis problemu: bo sie sypalo.. Jak masz problem z kodem ktory robimy, to podajesz komunikat bledu a nie walisz tekstem "bo sie sypalo" i totalnie zmieniasz koncepcje. No tak do niczego nie dojdziemy

Przeciez w Router masz

$controller = new $controller();

no to jaki problem zrobic z tego
$controller = new $controller($database);

?
oczywiscie konstruktor kontrolera tez ma przyjmowac ten parametr.
Malinaa
Dobrze, że pokazałeś palcem, bo nie mogłem tego znaleźć,
sorki zamotałem się, a tak samo proste jak w index.php,
ale przy zaktualizowanym kodzie w index.php jednak nie dajemy, tylko w klasie Router ? :

$database = new Database;
$controllerInstance = new $controller($database);

po czym w AbstractController

public function __construct(Database $database)
{
$this->database = $database;
}

i teraz jest ok, bo działa w IndexController:

Kod
/*
     * TODO! public function __construct(Database $database, Translation $translation) // TODO! Wstrzykiwanie do konstruktora!?
     */
    public function __construct(Database $database)
    {
        $model = new BlogModel($database);
        $this->model = $model;

        $translation = new Translation();
        $this->translation = $translation;
    }

    /*
     * TODO! public function index(Translation $translation, etc...) // TODO! Wstrzykiwanie do metody!?
     *
     * @Route: "/"
     */
    public function index()
    {
    ...
    }


i modele wygląda że są już super - konstruktor śmiga i mamy jedno połączenie.

Pozostały jeszcze zapytania o IndexController
1. czy można / jak zrobić aby wstrzykiwać do woli co tylko potrzebne
public function __construct(Database $database, Translation $translation, FirstService, SecondService, Three, etc....)
2. oraz wstrzykiwanie do metody ? np.
public function index(Translation $translation, etc...)
nospor
Cytat
ale przy zaktualizowanym kodzie w index.php jednak nie dajemy, tylko w klasie Router ? :
No i widzisz aty dalej swoje. Ja ci mowie jedno, a ty i tak robisz po swojemy.
Wyrnaznie pisalem ze to ma byc w index.php.
Teraz $database stworzyles w Router, na dodatek warunkowo przed tworzeniem kontrollera. Ale przeciez $database moze byc wykorzystawane w innych miejscach a nie tylko w kontrolerze a ty to wlasnie ograniczyles do kontrolera.

Cytat
1. czy można / jak zrobić aby wstrzykiwać do woli co tylko potrzebne
public function __construct(Database $database, Translation $translation, FirstService, SecondService, Three, etc....)

Albo powtarzasz kroki z database, albo wkoncu sciagasz DI co ci proponowano.
Malinaa
No, aż mi głupio, ale jeszcze nie mogę uwierzyć, że aby było ok trzeba wykonać aż takie przejście z pliku do pliku i plik po pliku.

Jest tak w pliku index.php

// Routing and database connection
use Dbm\Classes\Database;
$database = new Database;
$routes = require(BASE_DIRECTORY . 'application' . DS . 'routes.php');
$routes($database);

routes.php

return function (Database $database) {
$uri = $_SERVER['REQUEST_URI'];
$router = new Router($database);
...
}

class Router

public function __construct(Database $database)
{
$this->database = $database;
}

if (class_exists($controller)) {
$controllerInstance = new $controller($database);
...
}

AbstractController - nie jest abstract, więc nazwa do zmiany

public function __construct(Database $database)
{
$this->database = $database;
}

IndexController

public function __construct(Database $database)
{
$model = new BlogModel($database);
$this->model = $model;

$translation = new Translation();
$this->translation = $translation;
}

aż dochodzę do modelu BlogModel

public function __construct(Database $database)
{
$this->database = $database;
}

Czy teraz jest Ok?
nospor
nie
aż dochodzę do modelu BlogModel

public function __construct(Database $database)
{
$this->database = $database;
}

a:

aż dochodzę do modelu BlogModel

public function __construct(Database $database)
{
parent::__construct($database);
// inne rzeczy w konstruktorze BlogModel
}



Moze to i glupio wyglada ale tak sie robi. W sensie nie robi sie tak jak ty to robisz, tylko sie uzywa automatow co juz ci proponowano. Ale tak wlasnie generalnie wyglada DI. Obiekt jest tworzony raz a potem przekazywany wszedzie tam gdzie potrzeba. Ulatwi to wiele spraw, chocby testowanie aplikacji
Malinaa
Po zmianie w __construct()

Message: Cannot use "parent" when current class scope has no parent
File: Model\BlogModel.php on line 21
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2024 Invision Power Services, Inc.