Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Prosty i ultra lekki PHP Framework
Forum PHP.pl > Inne > Oceny
eerie
Od 2015 r. uczę się programować obiektowo w PHP. Przez ten czas napisałem kilka własnych aplikacji. Ostatnią pod koniec 2024 r. Gdy ją skończyłem, doszedłem do wniosku, iż na jej podstawie mogę utworzyć własny PHP Framework. Stworzyłem go w dwa dni i jest bardzo prosto napisany. Tak prosto, że trochę wstydzę się go pokazywać do oceny. Nadaje się do tworzenia ultra lekkich stron i prostych Systemów Zarządzania Treścią. Wszystkie najważniejsze pliki znajdują się w "src/Core". Framework jest oparty na architekturze SOA (architektura zorientowana na usługi). Budowa systemu katalogów przypomina Symfony, na którym się wzorowałem. Bez problemu da się w nim instalować biblioteki przy użyciu Composer'a. Prosiłbym o ocenę... smile.gif
phpion
Ogólnie fajnie, że Ci się chciało tworzyć coś własnego. Do szerszego grona odbiorców raczej to nie trafi, no ale może się mylę. Tak z grubsza:
- klasa Cache nie uwzględnia terminu ważności cache, jak już zostanie utworzone to na wieki wieków amen,
- w klasie kontrolera przekierowania zaszyte na sztywno,
- klasa Data - wiesz, że str_replace przyjmuje jako argumenty również tablicę podmianek?
- Database - i tu ogromny minus - obsługuje połączenie tylko z 1 bazą danych i to tylko z MySQL za pośrednictwem mysqli, niestety to duże ograniczenie,
- Token - zupełnie niepotrzebnie uzależniasz działanie tej klasy od sesji,
- Validator - patrząc na metody to ma niewiele wspólnego z walidacją danych.
Ogólnie widać włożoną pracę i to można pochwalić, natomiast raczej sam będziesz to stosował we własnych projektach. Albo za jakiś czas stwierdzisz, że ktoś już coś podobnego stworzył smile.gif
eerie
Jak zauważyłeś, stworzyłem ten framework głównie dla siebie, aby łatwo tworzyć nowe projekty. Jednak pomyślałem, że może się komuś przydać. No i chciałem poznać zdanie fachowców na jego temat... W przyszłości będę go rozwijał. Dzięki za uwagi. wink.gif

Jakby ktoś chciał zobaczyć przykłady użycia, to może zajrzeć na repozytorium emailsender.eeq na GitHub. Można tam podejrzeć przykładowe użycie logowania i autoryzacji. Demo i dokumentacja są dostępne na stronie Email Sender. To prosty wysyłacz e-mail'i z newsletterem, który napisałem z pomocą forumowiczów ponad rok temu.
nospor
Cytat
Jak zauważyłeś, stworzyłem ten framework głównie dla siebie, aby łatwo tworzyć nowe projekty.
Tez tak kiedys myslalem, tez kiedys stworzylem swoj wlasny zajebisty i mega szybki framework. Napisalem na nim nawet pare projektow i bylem zajebiscie dumny.... Jakby mi teraz ktos kazal znowu zaczac w tym pisac to bym sie chyba zastrzelil. To byla tylko strata czasu. W to miejsc trzeba bylo sie uczyc znanych FWs.
Taki wlasny FW raz ze jest mega ubowi, dwa ze jak niedaj boze ktos bedzie chcial cos z toba robic to musi sie tego nauczyc, a dwa ze jak bedziesz chcial pojsc do pracy i pracowac z innymi devami to bedziesz sie musial uczyc tego co juz dawno znac powinienes.
Wiec jak juz bardzo chcesz cos takieg pisac, to tylko w ramach nauki/eksperymentow. Niestety zostajeszz w tyle uzywajac tego.

Co do kodu: to brawa ze jedziesz na najnowszym php (choc chyba nie do konca skoro nie korzystasz z "private readonly" w konstuktorze), kod jest w miare czytelny. W miare dobrze sie to czyta.

Zas co do krytyli (pomijajac to co juz napisano)

1) Takie cosiki
$array = $mainPageService->mainPageAction(....);
return $array;

Sie poprostu robi tak:
return $mainPageService->mainPageAction(....);
Dodatkowa zmienna jest tu zbedna

2) Moze przegapilem, ale nie widze by dla strony mozna bylo wybrac inny szablon niz tylko main. Nie mowie o srodku strony, tylko o calym szablonie na cala strone

3) Brakuje mi w konstruktorze kontrolera by dzieidziczyl po jakims abstrakcyjnym kontrolerze ktory by dodawal na dzien dobry stala funkcjonalnosc

4) Tworzenie w kazdej akcji kontrolera tego non stop
$html = new Html();
$csrfToken = new Token();
jest troche nieteges. Ciagla duplikacja tego samego kodu


6) Osobiscie strasznie nie lubie zbednych zagniezdzen np
public function prepareError(?array $array): string
{
$error = '';

if (is_array($array)) {
foreach ($array as $key => $value) {
$error .= htmlspecialchars($value) . '<br>';
}

$error .= "\n";
}

return $error;
}

powinno wygladac tak

public function prepareError(?array $array): string
{

if (!is_array($array)) {
return '';
}
$error = '';

foreach ($array as $key => $value) {
$error .= htmlspecialchars($value) . '<br>';
}

$error .= "\n";


return $error;
}

Dodatkowo wymuszasz tu jak ma wygladac struktura html bledu. A co jesli bym chcial miec UL LI zamiast BR ?
W przypadku braku bledu to powinno poza tym zwracac NULL a nie pusty text.
W innych miejscach dodajac error, laczysz je w string z nowa linia, potem robisz explode po nowej linii by zwrocic ARRAY... NIe lepiej od razu poprostu trzymac to w array? Taka robota do niczego , juz nie wspomne jak ktos bedzie chcial dodac wlasny error z nowa linia w srodku.

7) W Query nie bardzo kumam tej logiki
public function setParameter(string $search, $replace): self
{
if ($replace === false) {
$replace = '0';
}

jak replace false, to zmien na 0.

8)

public function dbFetchArray($result): ?array
{
return mysqli_fetch_assoc($result);
}

fetch_assoc moze zworic false, twoj kod tego nie uwzglednia i normalnie w swiecie sie wywali w takim przypadku

9) Brakuje interfejsow by ta funkcjonalnosc byla troche bardziej rozszerzalna a nie taka sztywna struktura

10 Brak testow


Wiecej juz mi sie nie chce patrzec wink.gif Generalnie jak mowilem, fajnie ze probujesz, ale to powinno byc tylko w ramach praktyki/testow. No chyba ze jestes juz super specem od Symfony czy czegos innego. Tylko jesli tak, to czemu nie uzywac tego (symfony)? Rownie szybko sie pisze - jak nie szybciej.
eerie
Symfony ma całą masę plików i bardzo długo się prekompiluje. Pomyślałem, że tworzę prostą stronkę i zrobię to po swojemu. Jak już skończyłem, doszedłem do wniosku, że bez wysiłku mogę sklecić z tego własny framework. Trwało to tylko dwa dni... smile.gif

PS W Symfony 7.0 stworzyłem wcześniej takie coś. To prosta stronka, którą napisałem, aby się lepiej nauczyć tego framework'a. Tylko trochę trudno znaleźć kogoś, kto to oceni i poradzi, co zmienić.
nospor
Cytat
i bardzo długo się prekompiluje.

Co masz na mysli? Tworzenie cache? Ale to tylko na dev i to nie zawsze. Na produkcji robi sie raz a potem smiga jak ta lala

Cytat
że bez wysiłku mogę sklecić z tego własny framework. Trwało to tylko dwa dni...

Ja to rozumiem, ze stworzenie tego dlugo ci nie zajelo. Ale teraz wszystkie projekty robisz na swoim FW, totalnie ignorujac Symfony czy ten inne jak Laravel, i zostajesz w tyle. Taka prawda. Mowie z wlasnego doswiadczenia. smile.gif

Cytat
Tylko trochę trudno znaleźć kogoś, kto to oceni i poradzi, co zmienić.

Bo banalna stronka napisana w symfony, to ciezko cos ocenic jak pisales wg sztuki. Jakies entity, repository - wszystko wg przykladow to nei ma co oceniac.
Na szybko widze ze masz swoj cache. Po co? Przeciez Symfony ma cache
Tomplus
W ogóle, dlaczego nie używasz composera?

DLa własnych małych projektów, jest to bardzo dobre narzędzie, bo można i własne projekty dodać to jego autoloadera i cudze, uzupełniając projekt o zewnętrzne zależności.
Nie trzeba tworzyć własnego autoloadera, bo tylko utrudnia rozwój aplikacji. Sam przez to przechodziłem.
eerie
Przysiadłem wczoraj, aby zacząć to poprawiać. I mam pierwszą wątpliwość:

Cytat(nospor @ 23.01.2025, 15:47:12 ) *
4) Tworzenie w kazdej akcji kontrolera tego non stop
$html = new Html();
$csrfToken = new Token();
jest troche nieteges. Ciagla duplikacja tego samego kodu


Rozwiązałem to przez stworzenie obiektów wszystkich klas pomocniczych Core'a w abstrakcyjnej klasie Controller. Wygląda to tak:

Kod
[...]

abstract class Controller
{
    protected Config $config;
    protected Cache $cache;
    protected Data $data;
    protected Key $key;
    protected Email $email;
    protected Html $html;
    protected Token $csrfToken;
    protected Database $database;
    protected Manager $manager;

    public function __construct()
    {
        $this->config = new Config();
        $this->cache = new Cache();
        $this->data = new Data();
        $this->key = new Key();
        $this->email = new Email();
        $this->html = new Html();
        $this->csrfToken = new Token();
    }

[...]


Może tak zostać? Nie będę musiał tworzyć obiektów dla wszystkich kontrolerów, które ten rozszerzają, po wielokroć. smile.gif

PS Na razie operuję jeszcze na PHP 8.0, ale to zmienię... wink.gif

2025.02.18: Chcę dopytać o kilka rzeczy...

Cytat(phpion)
- klasa Cache nie uwzględnia terminu ważności cache, jak już zostanie utworzone to na wieki wieków amen,


Może być w kontrolerze tak, jak podałem poniżej? Bądź lepiej dodać metodę sprawdzającą to do klasy Cache?

Kod
        if (
            !file_exists($cacheFile)
            || filemtime($cacheFile) <= time() - $cacheTime
        ) {
            [...]

            $this->cache->cachePage($cacheFile, $content);
        }


Cytat(phpion)
- klasa Data - wiesz, że str_replace przyjmuje jako argumenty również tablicę podmianek?


Mam z tym problem. Bo pewne wartości powinny być zmieniane w odpowiedniej kolejności. Jeśli zastosuję tablice w str_replace, to może np. podmienić mi & przed &amp;. Część jest zamieniana na '', a część na '-' i kolejność jest ważna, więc nie wiem... smile.gif

Cytat(phpion)
- Token - zupełnie niepotrzebnie uzależniasz działanie tej klasy od sesji,


Chyba źle nazwałem tę klasę... Bo to nie jest jakiś tam "token", lecz "csrf token" do sprawdzania, czy nie doszło do nieprawidłowości/nadużyć przy przesyłaniu formularza. Umieszcza token w sesji i przekazuje do formularza. Potem sprawdza, czy przesłany formularz ma właściwy token, który wcześniej zapisano w sesji. Mam nadzieję, że zostałem zrozumiany. Może tak być?

Cytat(phpion)
- Validator - patrząc na metody to ma niewiele wspólnego z walidacją danych.


Powróciłem do dawnej nazwy tej klasy, czyli jest to klasa "Error", która jest rozszerzana przez klasy CośTamValidator'ów. smile.gif

Bezpośredni link do repozytorium: https://github.com/EEQSOFT/framework.eeq

Cytat(nospor)
9) Brakuje interfejsow by ta funkcjonalnosc byla troche bardziej rozszerzalna a nie taka sztywna struktura


Mój problem jest taki, że za bardzo nie wiem, gdzie te interfejsy powinienem użyć. biggrin.gif


Cytat(nospor)
10 Brak testow


Testy to wymóg konieczny? Nie może być aplikacja bez testów? smile.gif
nospor
Cytat
Mój problem jest taki, że za bardzo nie wiem, gdzie te interfejsy powinienem użyć.

Chociazby dla klas Database czy Email, lub innych podobnych.

Cytat
Testy to wymóg konieczny? Nie może być aplikacja bez testów?

Wszystko moze byc, nawet postawic dom/budynek bez porzadnego nadzoru. Tylko potem placz i zgrzytanie zebow wink.gif

Tez kiedys podchodzilem do tematu: a po grzyba mi testy. Przeciez widze ze dziala. Na szczescie praca nad porzadnymi i rozbudowanymi projektami zweryfikowala moje podejscie do testow smile.gif
Piterr9
Cytat(eerie @ 18.02.2025, 18:28:00 ) *
Przysiadłem wczoraj, aby zacząć to poprawiać. I mam pierwszą wątpliwość:



Rozwiązałem to przez stworzenie obiektów wszystkich klas pomocniczych Core'a w abstrakcyjnej klasie Controller. Wygląda to tak:

Kod
[...]

abstract class Controller
{
    protected Config $config;
    protected Cache $cache;
    protected Data $data;
    protected Key $key;
    protected Email $email;
    protected Html $html;
    protected Token $csrfToken;
    protected Database $database;
    protected Manager $manager;

    public function __construct()
    {
        $this->config = new Config();
        $this->cache = new Cache();
        $this->data = new Data();
        $this->key = new Key();
        $this->email = new Email();
        $this->html = new Html();
        $this->csrfToken = new Token();
    }

[...]


Może tak zostać? Nie będę musiał tworzyć obiektów dla wszystkich kontrolerów, które ten rozszerzają, po wielokroć. smile.gif

PS Na razie operuję jeszcze na PHP 8.0, ale to zmienię... wink.gif

2025.02.18: Chcę dopytać o kilka rzeczy...



Może być w kontrolerze tak, jak podałem poniżej? Bądź lepiej dodać metodę sprawdzającą to do klasy Cache?

Kod
        if (
            !file_exists($cacheFile)
            || filemtime($cacheFile) <= time() - $cacheTime
        ) {
            [...]

            $this->cache->cachePage($cacheFile, $content);
        }




Mam z tym problem. Bo pewne wartości powinny być zmieniane w odpowiedniej kolejności. Jeśli zastosuję tablice w str_replace, to może np. podmienić mi & przed &amp;. Część jest zamieniana na '', a część na '-' i kolejność jest ważna, więc nie wiem... smile.gif



Chyba źle nazwałem tę klasę... Bo to nie jest jakiś tam "token", lecz "csrf token" do sprawdzania, czy nie doszło do nieprawidłowości/nadużyć przy przesyłaniu formularza. Umieszcza token w sesji i przekazuje do formularza. Potem sprawdza, czy przesłany formularz ma właściwy token, który wcześniej zapisano w sesji. Mam nadzieję, że zostałem zrozumiany. Może tak być?



Powróciłem do dawnej nazwy tej klasy, czyli jest to klasa "Error", która jest rozszerzana przez klasy CośTamValidator'ów. smile.gif

Bezpośredni link do repozytorium: https://github.com/EEQSOFT/framework.eeq



Mój problem jest taki, że za bardzo nie wiem, gdzie te interfejsy powinienem użyć. biggrin.gif




Testy to wymóg konieczny? Nie może być aplikacja bez testów? smile.gif

Może być, ale wtedy użytkownicy staną się testerami tylko że za darmo i bez gwarancji, że coś faktycznie naprawisz, zanim zaczną narzekać. Testy to jak sprawdzenie, czy spadochron się otworzy, zanim skoczysz niby można bez, ale ryzyko jest spore.
eerie
Cytat
Może być, ale wtedy użytkownicy staną się testerami tylko że za darmo i bez gwarancji, że coś faktycznie naprawisz, zanim zaczną narzekać. Testy to jak sprawdzenie, czy spadochron się otworzy, zanim skoczysz niby można bez, ale ryzyko jest spore.


Ja testuję moje aplikacje, ale robię to teraz ręcznie, bo nie są rozbudowane... Tu chodziło o np. testy jednostkowe (PHPUnit) w PHP. smile.gif

2025-02-24:

Cytat
- Database - i tu ogromny minus - obsługuje połączenie tylko z 1 bazą danych i to tylko z MySQL za pośrednictwem mysqli, niestety to duże ograniczenie,


Poprawiłem klasę Database, aby pozwalała na wiele połączeń:

Kod
    public function __construct(
        string $mysqlHost = null,
        int $mysqlPort = null,
        string $mysqlUser = null,
        string $mysqlPassword = null,
        string $mysqlDatabase = null,
        string $mysqlNames = null
    ) {
        $database = require(DATABASE_FILE);

        $this->mysqlHost = $mysqlHost questionmark.gif $database['db_host'];
        $this->mysqlPort = $mysqlPort questionmark.gif $database['db_port'];
        $this->mysqlUser = $mysqlUser questionmark.gif $database['db_user'];
        $this->mysqlPassword = $mysqlPassword questionmark.gif $database['db_password'];
        $this->mysqlLink = null;
        $this->mysqlDatabase = $mysqlDatabase questionmark.gif $database['db_database'];
        $this->mysqlNames = $mysqlNames questionmark.gif $database['db_names'];

        mysqli_report(MYSQLI_REPORT_OFF);
    }


Obsługuje się to np. tak:

Kod
$db = new Database([...]);
$rm = new Manager($db);

$db->dbConnect();

$or = $rm->getRepository(OptionRepository::class);

$optionData = $or->getOptionData();


Lub bezpośrednio w kontrolerze:

Kod
$rm = $this->getManager();
$ur = $rm->getRepository(UserRepository::class);

$userData = $ur->getUserData([...]);


Tylko w tej chwili Repository Manager pozwala na połączenie tylko z jedną bazą danych:

Kod
    public function setManager(): void
    {
        if (!isset($this->manager)) {
            $this->database = new Database();
            $this->manager = new Manager($this->database);

            $this->database->dbConnect();
        }
    }

    public function getManager(): Manager
    {
        $this->setManager();

        return $this->manager;
    }


Nie wiem, czy jest sens oraz jak rozwiązać połączenia z wieloma bazami danych z poziomu kontrolera...

Do tego obsługa innych baz danych niż MySQL wymagałaby chyba stworzenia oddzielnych klas dla każdej z nich? Na razie korzystam tylko z MySQL i nie widzę sensu, aby dodawać [dla samego siebie] obsługę innych baz danych niż MySQL. smile.gif

2025-02-25:

Cytat
Nie wiem, czy jest sens oraz jak rozwiązać połączenia z wieloma bazami danych z poziomu kontrolera...


Można byłoby to zrobić tak:

Kod
[...]

abstract class Controller
{
    protected array $database;
    protected array $manager;

    [...]

    public function setManager(int|string $name = 0): void
    {
        if (!isset($this->manager[$name])) {
            $this->database[$name] = new Database($name);
            $this->manager[$name] = new Manager($this->database[$name]);

            $this->database[$name]->dbConnect();
        }
    }

    public function getManager(int|string $name = 0): Manager
    {
        $this->setManager($name);

        return $this->manager[$name];
    }

[...]


I dla Database:

Kod
[...]

class Database
{
    [...]

    public function __construct(int|string $name = 0)
    {
        $database = require(DATABASE_FILE);

        $this->mysqlHost = $database[$name]['db_host'];
        $this->mysqlPort = $database[$name]['db_port'];
        $this->mysqlUser = $database[$name]['db_user'];
        $this->mysqlPassword = $database[$name]['db_password'];
        $this->mysqlLink = null;
        $this->mysqlDatabase = $database[$name]['db_database'];
        $this->mysqlNames = $database[$name]['db_names'];

        mysqli_report(MYSQLI_REPORT_OFF);
    }

[...]
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-2025 Invision Power Services, Inc.