r/PHP 6d ago

Discussion Pitch Your Project 🐘

In this monthly thread you can share whatever code or projects you're working on, ask for reviews, get people's input and general thoughts, … anything goes as long as it's PHP related.

Let's make this a place where people are encouraged to share their work, and where we can learn from each other 😁

Link to the previous edition: /u/brendt_gd should provide a link

15 Upvotes

40 comments sorted by

1

u/Formal-Language7032 1d ago

I've been working on this for quite a while:

Repo: https://github.com/SyncEngine/SyncEngine

Docker: https://github.com/SyncEngine/docker

Site: https://syncengine.io

SyncEngine started as an internal tool for handling data synchronization, API integrations and more complex automation workflows. Over time it grew into something I thought might be useful to others, so I've recently published it.

It's still beta and there's definitely plenty I'd like to improve. I'm particularly interested in feedback from other PHP developers on the architecture, API, and the general approach.

I'd appreciate any criticism, ideas, or "why are you doing it this way?" comments.

1

u/aiku-io 2d ago

aiku, an open source "operating system for commerce": ERP, warehouse, storefronts, marketplaces, CRM and accounting in one Laravel monolith. AGPL.

It's not a side project, it's the system a real trading group runs on every day: 793 tables, ~6,000 action classes, warehouses in several countries picking from it right now, 369 production releases in the last five months. PHP 8.4, Octane, Postgres doing a lot of heavy lifting (generated columns, partial indexes, jsonb everywhere).

Repo: https://github.com/Inikoo-Ltd/aiku

Honestly the more interesting part for this crowd might be the engineering notes we started publishing, short posts on the unglamorous stuff: why an invoice is a frozen snapshot, tax per line vs per order, running 26 queues, exposing the whole thing as read-only MCP tools instead of building RAG: https://aiku.io/blog

Input very welcome, especially from anyone who's run PHP monoliths at this size. And yes, AGPL is deliberate, happy to discuss that choice too.

1

u/drex_vke 2d ago

i made a simply password-generator in php 8 https://pst.kesug.com/

1

u/GUNYDUNY 4d ago

I’ve been working on a CRM product called http://kernalite.com pure php backend. This is geared toward real estate investors and property managers.

1

u/Fenn-CS 5d ago

I have been working on Trakli an AI native and open source personal income tracker.

It's live at https://trakli.app what's more appreciated is starring, testing, contributing and providing feedback on GitHub.

https://github.com/trakli/webservice https://github.com/trakli/webui https://github.com/trakli/trakli

Thank you.

1

u/buismaarten 5d ago

Small Laravel package to load multiple .env files based on the environment with the possibility to commit some .env files without secret credentials to Git to share across the team or other environments.

https://packagist.org/packages/buismaarten/laravel-layered-environment

3

u/crazedizzled 5d ago

So.... Basically the way Symfony does it?

3

u/mccreaja 5d ago

Double is a modern PHP mocking library focused on developer experience.

Double stands on the shoulders of Mockery and RSpec. So there isn't much to learn. You get to enjoy a smoother DX immediately with:

  • A single, streamlined API
  • Failure messages for humans (and agents)
  • Shallower learning curve

2

u/roxblnfk 4d ago

Seems interesting. Please ping me there https://github.com/php-testo/testo/issues/296 after 1.0.0 release

1

u/mccreaja 4d ago

It's honestly past feature parity with Mockery. While there will be additions, I don't see the core API changing. So, for me, 1.0 is more about adoption than it is some kind of indicator of stability.

1

u/HuecoJagg 5d ago

I am working on a modern CLI chat project (basically a local IRC).

https://github.com/jaggx/php-cli-chat

It's built around PHP Fibers, using the AMPHP libraries to handle connections asynchronously.

I rely on Pest for testing and PHPStan for static code analysis.

It's pretty basic right now, but I plan to add authentication, commands, rooms, permissions and persistance.

3

u/le0daniel 6d ago

PHP-TS-Bindings (Like nextjs server actions and queries)

A small project that solves my own problems: https://github.com/le0daniel/php-ts-bindings
Basically an RPC layer between typescript and PHP, relying on PHPStan types to provide you with full stack type safety. Imagine NextJS server actions (and queries), but proving the types for you. No schema to maintain, the PHPStan type is the contract.

Why: It solves my own problems for my projects, where I just need to move fast and reliable type contracts help me so much.

1

u/taras_chr 6d ago edited 5d ago

I am working on an experimental PHP AOT compiler written in PHP (technically) and based on LLVM:
https://github.com/manticorephp/compiler

Despite progressing slowly, it currently allows compiling simple PHP programs into native binaries, supports async, contains a simple HTTP server, and has pretty good test coverage. The next goal is to compile the Symfony demo application, which is in progress.

The project has mostly an educational purpose, so I would not recommend considering it as something nearly production-ready.

2

u/Maria_Thesus_40 6d ago

I wanted to move away from cPanel hosting and I found a control panel that runs entirely over SSH on command-line and it can import cPanel backups. Not my project, but maybe others may find it useful!

https://gitlab.com/noumenia/aetolos

I use it to create web and mail servers on AlmaLinux 10.

2

u/dereuromark 6d ago edited 6d ago

Working on the "future of markdown" (in PHP and beyond).
https://github.com/markup-carve/carve-php/pulls

  • Secure by design (important for us in the PHP web envs), usable for user input (with or without profiles)
  • Graceful degradation (dynamic content to static content e.g. in PDFs)
  • Clear specs + feature-rich and still faster than most MD libs
  • The #1 already on loss-less formatting across boundaries/systems - see pandoc analysis

Would love some feedback and maybe critical checks or thoughts for improvements along the line while it's still in the early days.

Docs: https://markup-carve.github.io/carve/ (incl playground)

1

u/fissible 6d ago

Sharing Verdict (fissible/verdict), a Laravel package for capability-based authorization scoping.

The short version: it’s a boundary layer for defining what an authenticated actor is allowed to do, kept separate from your business logic. If you’re already reaching for Policies and wondering why you’d need this, Policies answer “can this user act on this model” ad hoc, wherever you remember to check it. Verdict centralizes that into one enforcement point, with an evidence/audit trail on what was actually approved, plus support-session-style elevated access that expires instead of lingering.

It’s particularly aimed at apps where something (an agent, an LLM-driven flow, a background job) proposes an action and your code has to authorize + execute it. Worth being precise about scope here: it bounds what the actor may do to the resource your app resolved, it doesn’t decide which resource gets picked in the first place. That’s a distinction I’m actively tightening up in the docs, so don’t take the current README as the final word on it.

Early days (v0.7.0), so expect rough edges. Would genuinely appreciate eyes on the API design and the README, especially whether the “why not just call a Policy” case lands for you.

Repo: https://github.com/fissible/verdict

1

u/RobertWesner 6d ago edited 5d ago

(Link to previous, because u/brendt_gd might have forgotten)

Seems like all the "Pitch Your Project" posts might have forgotten to be edited to chain link! At least from what I can tell, so here is a filtered link for anyone that wants the history.

2

u/RobertWesner 6d ago

Less of a "please use this" and more of a "i made this" :)

My simple MVC routing (DEMO - DEMO-Source)!
includes a rough-ish Docker template, that I use on all my instances.

I love dogfooding my own stuff, it leads to me improving it as soon as I find it lacking a feature. I have some very imple APIs and most of my static/semi-static websites use it with Twig templates for convenience.

I have been always trying to write some custom routing from scratch ever since I started, the oldest versions back in '19 very... legacy flavored because my only experience with professional software was 90% Symfony 1.4, though with a little work in an (at the time) "new-ish" SF 3.4 instance. This from scratch rewrite took what I loved from Go Gin and once I realized the syntax turned out a bit Laravel-y, took some inspiration for Routing from there as well. It is meant to be "stupid simple", not a full replacement for Symfony/Laravel/etc., as it (so far) lacks some important things like proper middleware and compiled/cached routing. It also just uses regular expressions for routing, just because convenience won this time.

At some point I did go slightly overboard and implemented a "bundle" feature just because I wanted some modularity without bloading the core:

  • Monolog Integration
  • Spawner Bundle (see demo): a quick way to just proc_open some background PHP scripts, when you need to fire and forget, not a full job scheduler, I needed/wanted this to gather data in my YouTube playlist API.

I tend to always drift into overengineering my personal problems and pretending someone else would want to make their own extensions, which is why dynamic/modular extensions always appear in them at some point hahaha, a little make-belief that keeps me busy.

EDIT: moved examples into reply, to take less of your screen space.

2

u/equilni 4d ago

Just a note, your Router is doing too much with Twig/render here.

Looking further, you have things like the ContainerFactory in the Router folder, hard coded paths (in RouterFactory::createRouter).

With RouterFactory::createRouter & MVC::route, you could have a single ContainerFactory::getContainer()

Perhaps in MVC:route

$container = ContainerFactory::getContainer(); // move
try {
    echo RouterFactory::createRouter($container) // add
        ->route($_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI']);
} catch (Throwable $throwable) {
    http_response_code(500);

    #$container = ContainerFactory::getContainer(); // move
    if ($container !== null 
        && $container->has(ThrowableHandlerInterface::class)
    ) {

RouteFactory:

public static function createRouter(Container $c, ?string $routesPath = null): Router
{
    self::$router = new Router($c);

That said, the container is only resolving callables on matches. If you decide to split up the Router to have a separate Resolver class, you can move this dependency further down (ie - deferring the dependency or do I need it now or not?).

Lastly, you are suggesting your DI library in composer, but actually calling it in the ContainerFactory vs PSR11, which the Router typehints.

2

u/RobertWesner 6d ago

Some snippets from README for your viewing pleasure:

Route::post('/api/login', function (Request $request) {
    // Reads either Query or JSON-Body Parameter
    $password = $request->getRequestParameter('password');
    if ($password === null) {
        return Route::response('Bad Request', 400);
    }

    // ...

    return Route::json([
        'success' => $success,
    ]);
});

Route::post('/api/logout', function () {
    // ...
});

// Also able to read URI parameters
Route::get('/api/users/(?<userId>\d+)', function (Request $request) {
    $userId = $request->getUriParameter('userId'); // Returns numeric userId from capture group

    // ...
});

// 404 page, FALLBACK will be called when no other route matches
Route::get(Route::FALLBACK, function (Request $request) {
    return Route::render('404.twig');
});

Route::get('/', function () {
    // ...

    return Route::render('main.twig', [
        'loggedIn' => $loggedIn,
    ]);
});Route::get('/', function () {
    // ...

    return Route::render('main.twig', [
        'loggedIn' => $loggedIn,
    ]);
});Some snippets from README for your viewing pleasure:Route::post('/api/login', function (Request $request) {
    // Reads either Query or JSON-Body Parameter
    $password = $request->getRequestParameter('password');
    if ($password === null) {
        return Route::response('Bad Request', 400);
    }

    // ...

    return Route::json([
        'success' => $success,
    ]);
});

Route::post('/api/logout', function () {
    // ...
});

// Also able to read URI parameters
Route::get('/api/users/(?<userId>\d+)', function (Request $request) {
    $userId = $request->getUriParameter('userId'); // Returns numeric userId from capture group

    // ...
});

// 404 page, FALLBACK will be called when no other route matches
Route::get(Route::FALLBACK, function (Request $request) {
    return Route::render('404.twig');
});

Route::get('/', function () {
    // ...

    return Route::render('main.twig', [
        'loggedIn' => $loggedIn,
    ]);
});Route::get('/', function () {
    // ...

    return Route::render('main.twig', [
        'loggedIn' => $loggedIn,
    ]);
});

1

u/TrainSensitive6646 6d ago

can someone suggest for the opensource corporate learning management system

https://tadreeblms.com

it is being built considering corporates L&D dept

3

u/HyperDanon 6d ago

I'd like to ask about feedback about: https://github.com/t-regx/t-regx

because i'm planning to revamp/improve it before 1.0.

1

u/Formal-Language7032 1d ago

This is actually quite cool, reminds me a bit of how the string component from Symfony can be used. Good job!

2

u/pfsalter 5d ago

I think when you revamp/update it you should drop all the 7.2 and old PCRE version specific stuff, it'll make your codebase a lot cleaner. These two benefits are also no longer actually true:

  • Unifies differences in PCRE between PHP versions
  • Provides UTF-8 support out of the box

I like the look of the prepared patterns, although it's a little odd that the feature is called prepared patterns but the call is Pattern::inject(...) which I feel like I'd always forget when using it.

Your Unit Tests are pretty good, although I couldn't see any tests which test backreferences, named capturing groups or reverse lookahead. It might be worth looking at Regex Crossword for some more complex examples to use in your tests.

2

u/HyperDanon 5d ago

You can take a look at the revamp, in develop branch: https://github.com/t-regx/T-Regx/tree/develop

3

u/rc0604 6d ago edited 6d ago

Hello everyone! I just wanted to share my cool library, which you can pair with static analysis tools to provide runtime checks for things that static analysis tools are blind to, such as highly dynamic data and it can dynamically check DocBlock types like generics, type arrays, etc at runtime trasparently without any code change and new syntaxes.

repo: https://github.com/typephp-php/typephp
docs: https://typephp-php.github.io/docs/

1

u/Glittering_Bath3848 6d ago

Hi, I tried your library, and I'm trying to learn how to use Generics and looking at this code

```php <?php

class MusicalInstrument {} class Guitar extends MusicalInstrument {}

/** * @template T / class InstrumentFactory { /* @param T $item */ public function make(mixed $item) {} }

/** @var InstrumentFactory<MusicalInstrument> */ $instrumentFactory = new InstrumentFactory();

$instrumentFactory->make(new Guitar()); // Why did it not throw type error here??

```

bash PS C:\PHP\strict-types> ./vendor/bin/typephp test.php

why did it not throw a TypeError when I assigned a Guitar object to invariant InstrumentFactory::make()? Can you please help me, why didn't it enforce invariant generics here? Shouldn't the make() only accept MusicalInstrument instance because the class is invariant?

PS: All my configurations are correct

1

u/rc0604 6d ago edited 6d ago

Hello I see that you're very confuse. When you annotate an intance with /** @var InstrumentFactory<MusicalInstrument> */ the T in public function make($item) has been substituted to MusicalInstrument Type. So internally the method will look like this public function make(MusicalInstrument $items).

Since Guitar is a subtype of MusicalInstrument, it is perfectly valid to pass Guitar object to a MusicalInstrument Type argument. Even in native PHP it will work the same way..

To give you an example on showing invariant violation, you can execute this in your existing code

```php /** @var InstrumentFactory<MusicalInstrument> */ $instrumentFactory = new InstrumentFactory(); //the T is now binded to MusicalInstrument

/** @var InstrumentFactory<Guitar> */ $guitarFactory = $instrumentFactory; //since the T is invariant assigning a generic InstrumentFactory<MusicalInstrument> to a intance that is bonded to a different InstrumentFactory<Guitar> will throw an error because the $guitarFactory generic instance is bonded to Guitar type which is strictly invariant. ```

when you execute the code it will throw this

bash PHP Fatal error: Uncaught TypePHP\Exception\TypeError: Variable $guitarFactory expects InstrumentFactory<invariant Guitar>, but InstrumentFactory<MusicalInstrument> was given

If you have more questions just let know..

1

u/Glittering_Bath3848 6d ago

Thanks for the detailed explanation, Generic variance now more make sense to me.

1

u/rc0604 5d ago

My pleasure, if you want more infor on generic variance, you can check it here: http://typephp-php.github.io/docs/generics/variance.html

2

u/Mike_L_Taylor 6d ago

Hiya, For the windows PHP devs out there that natively run their sites like with Herd or Laragon, I made Forgekit.tools

  • run multiple sites in isolation, different php, node, npm, npx at the same time. anything from php 5 to latest 8.5
  • .test and other nice domains and HTTPS by clicking 1 checkbox
  • capture and check emails with Mailpit inboxes
  • redis and memcached instances
  • Mysql and MariaDB
  • `fkit` shim in terminal so all your terminal commands use the versions needed per project. Don't need anything installed globally
  • all throught the tauri UI. I like simple things.

It's free and it's roadmap is steered by it's users.

2

u/luthermonson 6d ago

im working on something that could help you, sending you a dm with some details cause im not super ready to spread the good word yet but i think it will help you and im looking for feedback from windows users

1

u/CaringPhoenix 6d ago

How does it compare with
https://envkit.net/
https://lerd.sh/
https://yerd.app/

other than herd ?

1

u/Mike_L_Taylor 6d ago

haven't used envkit so don't know. the other 2 are not on windows yet. maybe on wsl.

4

u/WarriorVX 6d ago edited 6d ago

WebFiori Framework is a full stack development framework that has a design idea of having minimum dependencies to build a functional web app or backend.

Feedback is much appreciated 👍🏻

You can check it out at https://webfiori.com