#php

1 messages Β· Page 3 of 1

obsidian forge
#

confused, how are they failing? do these not run in ci?

serene light
shy goblet
worthy ice
shy goblet
#

I already tried 3 time but yeah

#

I'll wait a bit before retrying, maybe the instance is broken

obsidian forge
#

hallo, started noticing a lot more php flakes recently πŸ€”

#

does anyone know why we do this array shifting? i'm a bit confused as to the logic here, specifically, shouldn't we avoid breaking out of the loop until we have sessionInformation?

serene light
# obsidian forge does anyone know why we do this array shifting? i'm a bit confused as to the log...

https://github.com/dagger/dagger/actions/runs/11478378808/job/31942452004?pr=8763
Are the flakes always specific to the Dagger\Tests\Integration\ClientTest?

It might be alright to do away with it, as I'm not sure what it really tests at this point.
It seems to test that it can make a file, directory and container, but here's the thing: We already make a Dev container with a source directory containing the sdk files just to run the tests. So by the time we're running those tests... what do they prove?

GitHub

An engine to run your pipelines in containers. Contribute to dagger/dagger development by creating an account on GitHub.

serene light
# obsidian forge it looks like somehow we're not getting any `sessionInformation`? this code look...

I'm not sure of what is in the sessionOutput. That code was mostly fleshed out before I got involved so I can't say for sure but here's what I can gather.

  1. It finds any valid lines of json.
                if (str_contains((string) $output, 'session_token')) {
                    // @TODO Rewrite when PHP 8.3 json_validate is available
                    $lines = explode("\n", (string) $output);
                    $validLines = array_filter($lines, function ($line) {
                        $this->logger->debug($line);
                        json_decode(trim($line));

                        return JSON_ERROR_NONE === json_last_error();
                    });

$validLines will only contain strings that we can use json_decode on. If there isn't any, then it will be an empty array.

  1. It takes the first element of the array, and decodes it.
                    $sessionInformation = json_decode(array_shift($validLines));

$sessionInformation will only be null if:

  • json_decode fails (impossible, because only valid json can make it into the $validlines array)
  • array_shift fails because $validLines is empty.

So $validLines must be coming back empty occasionally, what that means I don't know right now.

I know we want to remove that ProcessSession code eventually but its a bigger task than I have time for currently.

serene light
inner walrus
ocean creek
summer sequoia
#

we were struggling with tracing not working; I think we were going in completly the wrong direction with it though

green otter
#

Thanks @ocean creek πŸ’ͺ

hallow hinge
#

Hey

karmic tendon
#

hey !

#

Already starting to migrate our project to dagger based on your presentation @green otter . Thanks for these insights ! Eager to try more and reports any ideas I may have to see how I can help make this the default CI / CD for any PHP / symfony developper

green otter
#

welcome @karmic tendon

#

@karmic tendon I'm setting up a call with Grekas, and a few others next week, to begin the planning phase for this, and I can help with it .. so feel free to play around, but hold off on anything formal.

I'll ask Grekas to add you to the call

Is that cool ?

#

for this = for Symfony **

karmic tendon
#

Sure. Wasn't going on anything formal for a while about this. Not until I fully grasps what are the limits and work required on this kind of tool. So far I thought about having some modules around :

  • Pie / Pecl
  • Composer

A flex "hook" of some kind to allow when requiring phpstan for example taht it provides a way to connect to your main container.

So yeah. Glad to be here to help and to learn more on dagger !

green otter
#

@karmic tendon yes, I can guide your understanding of how it can all work together, that's why I will have some call(s) with Symfony/Sensio team to start advising how we can best to it.. as I've been sitting for 6+ months on DaggerPHP, and have my own ideas and conclusions on how it should/could be done πŸ™‚

#

@karmic tendon go to an existing project, and type dagger init --sdk=php .

#

it will become "Daggerized"

#

Then type dagger functions to see the 2x stub functions it added for you

#

Look at .dagger/src/SomeModule.php for the code

#

dagger call method-name on the CLI, to call it, and test it

#

Did you get this far, yet ?

karmic tendon
#

yup already migrated most of our Dockerfile (with some strange behaviours) to dagger functions already. Also multi stages.

green otter
#

multi stage πŸ’ͺ

#

Which project is it ? internal private project?

I'm keen to see a private gist.github.com copy (DM me?) of your file.

I can offer support on any of the strange stuff you're experiencing πŸ™‚e

LMK

#

@karmic tendon

karmic tendon
#

yup private one for a client. Will share you a private gist no worries. Some of the weirdeness I encountered :

  • no easy access to local filesystem files. ($phpConfigDirectory = dag()->currentModule()->source()->directory('/config/php'); but had to move the config folder to within .dagger seems relatable to docker context scope)
  • apt-get update gets weird fail errors which I can't figure out why at the moment
  • not confident what are the best practices for caching steps / apt-get list / etc etc
  • didn't find a way to save a container in local registry (build but not push)
  • didn't find a way to apply the "cache_form" equivalent
  • dagger call --help is quite slow (maybe because of dynamic modules loading ?)
#
  • also had some things like bash -c "$(curl -sL https://get-gnmic.openconfig.net)" which is not as trivial to migrate to dagger. Need to download the file as a temporary file, execute it, then remove the temp file
green otter
#

dagger call --help is quite slow (maybe because of dynamic modules loading ?) - yes I think it's looking up the internet for "stuff"

#

...

$phpConfigDirectory = dag()->currentModule()->source()->directory('/config/php')

I'm not sure you want to use currentModule()->source() any longer, i think it's the legacy way ..

I think there's a new better method ..

#

@sudden shuttle can you advise? or @obsidian forge if you're about.

karmic tendon
#

the only thing I found was to provide the source as an argument and auto resolve Directory class

green otter
#

@karmic tendon this is the ONLY way, the new way is to pass the source via argument

dagger call my-function --source=.

As per the grepDir sub example. Let me also link you to my "slides" from the SymfonyCon talk

karmic tendon
#

yes but I was hoping to not have to use a cli option for this. It won't change dynamically and will always be the same value for this project

green otter
#

@karmic tendon then you don't need to use CLI option for it - you can use static path .. that is why I pinged @sudden shuttle or @obsidian forge to advise.

karmic tendon
#

it contains php.ini configuration, entrypoint scripts. well basically anything we want to mount in the container

sudden shuttle
green otter
#

@karmic tendon to help Marco and such .. what are you curerntly trying to do with this /config/php/ directory object .. example? Can you show your code

Are you trying to "copy files" or something? what's your use case

green otter
sudden shuttle
karmic tendon
#

sure. BAsically I have a Dockerfile at the moment with

COPY "./bin/"            "/var/www/bin/"
COPY "./cachetool.yml"   "/etc/cachetool.yml"
COPY "./conf.d/"         "/var/www/conf.d/"
COPY "./php.conf/"       "${PHP_INI_DIR}/conf.d/"
COPY "./sudoer"          "/etc/sudoers.d/sudoer"
COPY "./php-fpm.d/"      "${FPM_CONFIG_DIR}/"

and moving this to dagger I need to copy those files from local filesystem over to the conatienr withotu having to pass a cli option for this

#

could be a simple file or a whole directory. Bonus point if it follows dockerignore

sudden shuttle
# karmic tendon sure. BAsically I have a Dockerfile at the moment with ``` COPY "./bin/" ...

cool, you're looking "context directories" which is resolved by using the defaultPath directive / annotation /pragma (https://docs.dagger.io/api/arguments/#directories-and-files)

Dagger Functions, just like regular functions, can accept arguments. In addition to basic types (string, boolean, integer, arrays...), Dagger also defines powerful core types which Dagger Functions can use for their arguments, such as Directory, Container, Service, Secret, and many more.

#

@green otter do you know if the PHP SDK already supports that?

karmic tendon
#

ok. So it is an option but with a default value then ?

green otter
karmic tendon
#

so it is nto mandatory to provide a custom value

sudden shuttle
karmic tendon
#

ok thanks will try then

sudden shuttle
#

πŸ‘ .Not sure how you define that in PHP πŸ˜›

green otter
#

python == php - will be the same

karmic tendon
#

function(Directory $default = ...) not sure either as it needs to be type hinted Directory so how can I provide a default string value ?

#

DefaultPath

#

found it

green otter
karmic tendon
#

sure will do some try later (have a meeting :/ )

green otter
#

@karmic tendon I will invite you to the meeting with Grekas, cool ?

karmic tendon
#

(if its on monday / tuesday french working hours : might not be available because I will be training people, but I don't think I am required so no worries if I can't make it)

karmic tendon
#

but it is working

#

thanks !

green otter
#

πŸ’ͺ

#

Show full function, please πŸ™‚ - make it pretty

karmic tendon
#
#[DaggerFunction]
    #[Doc('Build the base image for PHP')]
    public function buildPhpBase(
        #[DefaultPath('/.infrastructure/php')]
        Directory $phpConfigDirectory,

        string $phpVersion = self::DEFAULT_PHP_VERSION,
        string $icuVersion = self::DEFAULT_ICU_VERSION,
        string $timezone = self::DEFAULT_TIMEZONE,
    ): Container {
        return dag()
            ->container()
            ->from("php:{$phpVersion}-fpm")
            ->withEnvVariable('PHP_CPPFLAGS', '$PHP_CPPFLAGS -std=c++17', true)
            ->withEnvVariable('FPM_CONFIG_DIR', '/usr/local/etc/php-fpm.d')
            ->withEnvVariable('ICU_RELEASE', $icuVersion)
            ->withEnvVariable('CXXFLAGS', '--std=c++0x')
            ->withEnvVariable('TZ', $timezone)
            ->withEnvVariable('SYMFONY_ENABLED', 'false')
            ->withEnvVariable('PHP_ENV', 'dev')
            ->withEnvVariable('SCRIPTS_FOLDER', self::SCRIPTS_FOLDER)
            ->withEnvVariable('GPG_PASSPHRASE', '')
            ->withEnvVariable('ENTRYPOINT_DOCTRINE_MIGRATIONS_MIGRATE', 'false')
            ->withEnvVariable('ENABLE_CONSOLE_SERVER', 'false')
            ->withEnvVariable('CONSOLE_SERVER_PORT', '8000')

            ->withDirectory('/var/www/bin/', $phpConfigDirectory->directory('./bin/'))
            ->withDirectory('/var/www/conf.d/', $phpConfigDirectory->directory('./conf.d/'))
            ->withDirectory('${PHP_INI_DIR}/conf.d/', $phpConfigDirectory->directory('./php.conf/'), expand: true)
            ->withDirectory('${FPM_CONFIG_DIR}/', $phpConfigDirectory->directory('./php-fpm.d/'), expand: true)
            ->withFile('/etc/cachetool.yml', $phpConfigDirectory->file('./cachetool.yml'))
            ->withFile('/etc/sudoers.d/sudoer', $phpConfigDirectory->file('./sudoer'))

This is only the start of the function (too big)

green otter
#

@summer sequoia you about?

#

what do you think about [DefaultPath] annotation usage? πŸ™‚

#

@karmic tendon have you called that function without any --php-config-directory CLI args, to make sure it allows you to bypass it ? πŸ™‚ and use DefaultPath

karmic tendon
#

sorry yes. I used 0 arguments / options and it worked

summer sequoia
green otter
#

@summer sequoia look at the above code example, that's exactly what I'm asking/showing you

summer sequoia
#

soory, was reading back the whole convo and replying to parts as I went

#

that's my latest iteration of a dagger module for my codebase

#

up doesn't work properly yet though

serene light
#

Yeah the #[DefaultPath] attribute is the only way to set a path without specifying it.

green otter
#

@serene light that's good - it will do very nicely, for the PHP community adoption.

serene light
#

We don't support it being specified in any other format

green otter
serene light
#

You're correct, we plan to stick with only attributes.

#

That way we can keep any documentation brief, simple and have one defacto way to do it

#

If it's of any use we do also have an #[Ignore] Attribute for ignoring files from your directory @karmic tendon .

green otter
#

@karmic tendon this is good to emulate your .dockerignore file, conceptually similar. ☝️

karmic tendon
#

Good to know. altough I feel like tehre should be a bridge native to dagger about this. As it seems to have some kind of restricted context similar to docker build it should load dockerignore file by default.

#

regarding attributes I feel not so confident. It wasn't intuitive that to load a local filesystem I had to use it as an argument (mandatory one in regards of PHP) but make it optional by using an attribute. It feel counter intuitive IMO.

That being said I don't really see another way to do it. Except maybe Directory&string = 'default/path' But I suspect it won't be valid in regards of PHP

summer sequoia
#

yeah, the ideal would have been if we could have allowed setting a default path as a directory object in the function definition but you can't do that in PHP so it has to use an attribute

#

@karmic tendon take a look at my Sai module and see if you have any thoughts on how it works. Idea is to abstract knowledge about how various common tasks are performed in the underlying image: eg you request the xdebug extension; you shouldn't care if we install using pie or using the docker extension installer or some other method all you care about is having a PHP container with xdebug installed

#

It also encodes information about the container in labels to allow other modules to introspect that info: eg a future PHPUnit module could interogate the metadata to see if pcov, xdebug etc are installed so it can pick one to use to generate coverage for you

karmic tendon
karmic tendon
serene light
karmic tendon
#

I see. I'll try to think of something.

green otter
karmic tendon
#

Dagger.php

#

How does it work if you want to split accrosse several files ? I see in the sai modules that you have PHPComtainer & NginxContainer. What about if in my project I'd like also to have the PhpContainer class seperated from the app orchestration separated from the tests / qa analysis.

Is it as simple as new PHPContainer($container) ? or is it something "Generated" that adds ->withComposer to Container class automagically ?

summer sequoia
serene light
# karmic tendon How does it work if you want to split accrosse several files ? I see in the sai ...

Adding on from what @summer sequoia said: If you look at Sai.php

dagger call php would:

  1. Call the php function from the Sai.php
  2. Return a PHPContainer

Because the PHPContainer has the #[DaggerObject] attribute, you can chain another function on to it.

dagger call php with-composer would:

  1. Call the php function from the main entrypoint
  2. Call the withComposer method on the returned PHPContainer
  3. Return the PHPContainer with composer installed.

You can start chaining functions together like that

GitHub

Contribute to sai-php/sai development by creating an account on GitHub.

GitHub

Contribute to sai-php/sai development by creating an account on GitHub.

karmic tendon
#

ok thanks

karmic tendon
#

One thing I might add : debug is quite painful at the moment πŸ˜… . It says it failed but no way to actually linked to the action that really failed :/

summer sequoia
#

yeah; that's something we're finding as well

#

the traces might help if you set it up with dagger.cloud

green otter
#

@summer sequoia everything in Sai looks over engineered and non standard dagger practice. I don't like it, or that we are recommending people look at it for examples.

summer sequoia
green otter
summer sequoia
#

No?

#

It's a module which provides an abstraction layer for PHP and nginx containers; might separate it out a bit in the future but they currently live in the save module as there's some shared behavior around labeling

#

And you'd typically use them together

#

I'd be more inclined to separate them into their own modules if dagger had vendor namespaces though

green otter
#

Why do we need ->withLabel() ? - what value is it adding?

summer sequoia
#

The labeling annotates the state of the created container, allows the module to pick it back up later. Eg you could build a production container; then return to the module to install pcov for test coverage

#

Or something I'm planning later; once I get the hang of mounting files properly from the host; enable doing things like running composer require within the built container while in dev

green otter
#

ok

#

@summer sequoia can other SDK's have multiple modules in the .dagger/src/ directory?

Such as MyModule.php SomeOtherModule.php

summer sequoia
#

Yes, they are just additional dagger objects

#

It's how everything in dagger works, call container, you get a container object back which you can call functions on

green otter
#

@summer sequoia it's just lots of extra files, lots of complexity .. from a DX perspective there is "a lot to take in" .. and I'm asking myself how can we make this all very simple .. they shouldn't need to know about "labels" for starters.. that's an engine implementation detail

summer sequoia
#

for Sai, the labels are an implementation detail

#

now that, would be a bug

green otter
#

@summer sequoia

        $baseContainer = dag()
            ->container()
            ->from($containerInfo->getTag())
            ->withLabel(PHPContainerInfo::LABEL, (string) $containerInfo);

Why do I **need a label here? why can't I just do ->from() and crack on?

summer sequoia
#

labels are just used internally

#

sai is a module you use in your codebase

green otter
summer sequoia
#

you could use it that way, or you could do sai()->php('8.3', 'fpm')->withExtension('mysql')->withExtension('redis')->withComposer()->withSource($mySource)->container();

#

that's more expressive

#

abstracts the detail

#

why would you use symfony instead of raw PHP?

green otter
#

Okay, fine. If someone wants to make something for their own project.

the angle here is, people will want to make their own abstractions for their own projects and things (like nginx), and if we are giving them examples then it needs to be as simple as possible.

People will very quickly outgrow the standard SDK objects API

summer sequoia
#

yes; I'm moving towards creating a simple enough toolset that someone could just grab off the shelf and get 90% of the way to a deployable project

#

but also, get out of the way and let people do their own thing if they wish

#

you can still grab the raw container and do whatever you need with it

green otter
#

this is more like it .. I'm not feeling these "Label objects" .. they contain meta data about the docker image to use .. and people are like "wtf is a label and why does it contain my image name/tag" ... do you get me ?

summer sequoia
#

(one of my next projects is to read from the composer.json to do the withExtension stuff automatically for you)

#

it's an internal implementation detail though; as an end user you don't need to worry about them

green otter
#

actually, they need to worry about it if they're going to be making their own versions of that abstraction .. they'll be copying it .. you're already showing newcomers it, as a reference,

summer sequoia
#

I don't think it's a bad idea to label your containers with metadata about their built contents

#

it is used internally for some checks eg with withExtension won't install the same extension twice

#

i'll probably use the source dir label to make sure you're in the right workdir for doing stuff with composer

#

pretty sure chainguard is doing that to aid with their security stuff for example

green otter
#
        $containerInfo = new NginxContainerInfo(
            $version,
            $os,
            $variant
        );

        return new NginxContainer(dag()->container(), $containerInfo);

What about this, instead? Why do I (need) to be specifying the ->from() at consumer level?, and why do I need to be specifying ->label() at this level?

summer sequoia
#

If you don't add the label to the container you lose the meta data once you hand the container to the user. Makes it harder to pick up again

green otter
#

I'm saying to keep label() but not let the consumer be responsible for that .. surely we can do it inside of NginxContainer()

summer sequoia
#

It does it inside the sai module

green otter
#

okay. I know it does, but I'm wondering why it needs to .. it's exposing complexity that I thought could be encapsulated inside NginxContainer() .. like in the __construct()

#
        $containerInfo = new NginxContainerInfo(
            $version,
            $os,
            $variant
        );

        return new NginxContainer($containerInfo);

This is simple, and clean .. can't we have NginxContainer->__construct() take care of the dag()->container() ?

That would solve this

summer sequoia
#

That would prevent creating an nginx container from an existing container though, see adopt PHP container function

green otter
#

Do you have sample code (scenario) for adoptPHPContainer() ? trying to see it

summer sequoia
#

Something like: sai()-php()-withExtension('mysql')-cintainer()-someCustomStuff(); sai()-adopt()-withComposer()-etc

green otter
#

Let's talk over the weekend about it, when you're at your computer πŸ™‚

summer sequoia
#

Oh, I just remembered the biggest issue it was solving: you can't depend on objects from another module in your module.

#

So a PHP unit module couldn't depend on a PHP container object from Sai

#

It would need to depend on a dagger container

green otter
#

What if you passed the container in, though? between the modules

summer sequoia
#

Then call adopt to get the sai container

green otter
#

what about this?

$container = dag()->container()->from('php:8.2')
    ->withDirectory($stuff ....)->withExec(['apk add', 'some package']);

phpunit()->fromContainer($container)->runTests();

phpunit being a separate module

summer sequoia
#

I need to open source a few more bits I think to demonstrate this better

#

I'll see if I've time on Sunday

green otter
#

The PHP community can't rely on sai(), there needs to be "a clean simple way" so they can adopt that technique for their own modules, and their own things .. for their own private company projects

Agreed?

summer sequoia
#

It's a good example right now, but I'd not push it as the one true way.

#

I do plan for it to be a standard ish toolkit but it's got a way to go yet

green otter
#

Ok.. see DM .. night πŸ™‚

karmic tendon
#

I find having everything for my project in one file (build base, build local, build prod, build assets, build nginx, run phpunit, run phpstan, etc etc etc etc) not very "friendly" in DX PoV. Do you have any recommandation on how to split concerns properly ? I like some examples you shared @green otter for your talk about having ->withBaseEnvVars, ->withComposer() or stuff like this. But whenever I want to put it in another class it feels weirder... Will try to provide code to better demonstrate what I mean

green otter
#

Hey, I make a separate trait .. and bring it into the main class context. That way it's the same class but separate code πŸ™‚

How about this?

#

@karmic tendon

#

Trait for Building stuff

Trait for Testing stuff.

Each function in a Trait, can either do dag()->container()

Or it can just receive argument Container object and return Container once it is finished

#

WDYT?

karmic tendon
#

yup good idea. I think trait is the better of both worlds. Altough we might have to try it on very bog project where dagger would become central to everything to see if it does bring any cognition load to have all the "Functions" in one place only.

karmic tendon
#

I use those constants as default cli options for a dagger Function

green otter
#

@karmic tendon hold on. Let's ask @summer sequoia I might know why but Chris will know better.

It could be a PHP version issue, or it could be our introspection code..

Let's see what he says

green otter
#

@karmic tendon I couldn't reach Chris yet, but will eventually

#

@karmic tendon I think this is a PHP issue now Dagger. So the runtime where all your code runs inside of, is a PHP 8.2 container...

karmic tendon
#

no worries. I'll be full until end of next week

green otter
#

@karmic tendon show your code that's throwing the error. So we can see and maybe chris can replicate it.. if anyone will know it will be him

summer sequoia
#

As for code organisation. There are two ways you could do it.

The first, is what I posted with the gist up above; whereby your module entrypoint contains the only public API for your module and you then separate using non-dagger classes or functions. There's nothing to stop you creating a Unit tests class, an integrations tests class and a static analysis class which takes a container as a constructor arg and has functions you can call to do your build steps. Youd' then have a single "runTests" function in your module entrypoint which does some setup and then defers to calling each of the subclasses. If any of these sub class components are reusable across your projects, you could turn them into modules in their own right.

The second is similar but instead of using the entrypoint to rollup lots of calls into a single function; you use it to provide access to the separate components of your module; so you might have a function tests() which returns a Tests object which in turn contains functions which return A Unit tests, integration tests and static analysis objects which you can then call the functions to perform your build. This allows more granularity in the function calls and will play nicer if you want to integrate with tools which visualise or do further processing on results (eg showing code coverage against your code in the PR)

#

Personally I'd tend to lean towards the second option as the longer term aim, but the first is a good starting point to move pipelines into dagger to start with and if you organise it well, it'll naturally convert to the second option further down the line.

green otter
#

@hallow hinge ask here your Qs πŸ™‚

hallow hinge
#

I’m crafting a PoC for Symfony-cli as dagger module. It could be a base module for : console (importmap, doctrine, cache, linters, tailwind, etc). All those things are commonly used in CI pipelines of Symfony apps

#

Besides, it could be awesome to have modules for quality tools! Here a non exhaustive list:

  • Phpstan in pure php(it exists coded in Go)
  • Php-cs-fixer in pure php (it exists coded in Go)
  • ECS
  • Rector
  • TwigStan
  • PHPUnit
  • Pest
  • Psalm
  • Behat
  • Deptrac
  • PHPat

Feel free to complete this list, and share if you want to craft some. Maybe we could share base module ship standardized and solid modules 🦾

green otter
#

@hallow hinge I already have the code for the above things, already created .. If you have a Module question then we can ask .. otherwise let's set up a call (and a repo?) for me to start putting in the code for all the above stuff .. as mentioend I've already built most of it

hallow hinge
#

I guess you can publish them under your name, and we (php devs) will use/contribute then πŸ˜‰

green otter
#

@hallow hinge I will publish my code onto a Dagger Module (the daggerverse) so you can immediately start using them in whatever context you wish (symfony-cli?) and you can contribute to any of these modules for missing fields/functions/flags πŸ˜„

So then they will be ready for "the PHP community at large" πŸ™‚

I didn't make one for Pest or TwigStan or Rector πŸ™‚

So maybe once you see my modules for the others you can have a try at making the TwigStan one and Rector πŸ™‚

#

I'll go and charge my laptop and grab all the code now..

I'm wondering if we want 1 repository for all the "dagger-php-tools" or we have 1 repo per module

#

Let me make 1 repo per tool, actually, as I see "issues" πŸ˜…

green otter
#

I'm running static analysis on the Symfony project, using my new phpstan module 😎

#

ALL ZE CORES πŸš€

green otter
#

@hallow hinge I have finished the phpstan module 😎

#

Wanna see?

hallow hinge
#

Yeah! I will check it properly tomorrow morning, but yes, shoot the link here!

(I was wondering about a GitHub organization dedicated to dagger php modules, WDYT?)

green otter
#

@hallow hinge yessir, been thinking about it for a few months now .. I'm thinking of php-dagger or dagger-php org ??
WDYT?

hallow hinge
#

I have the exact same question in mind πŸ˜…

green otter
#

So I built the official phpstan module 😎

#

I went to the symfony/symfony git repo, and now I'm calling it from inside the Symfony repo's dagger module

#

@hallow hinge all of this works πŸ˜›

hallow hinge
#

Let’s roll a dice? Odd for dagger-php, even for php-dagger? Do you have a dice?

green otter
#
dagger call static-component --source=. --Translation
dagger call static-component --source=. --Asset

πŸ˜›

#

ok, I'm now changing it to run so that it's not confusing with x2 phpstan()

#

Do you liiiiiiike? @hallow hinge

hallow hinge
#

Run? Or analyze, to reflect the real command?

hallow hinge
green otter
#

analyze++

#

I'll go make an official psalm module now .. and then I'll add psalm as well as phpstan, to align with official Symfony stuff

#

Final phpstan copy πŸš€

green otter
#

official psalm() module now exists - and here is the symfony project using it πŸ™‚

green otter
green otter
karmic tendon
#

Woow. Moving so fast ! Congrats on this workload ! Can't catch up yet sorry (end of year is kind of a marathon on my side). Eager to check those out !

low bolt
#

If I may share a few thoughts: I think it's generally a good practice to set versions in module constructors. In the end, the module just invokes a container which could be anything and in some cases, the container itself may need to be custom as well.

That's why I generally allow setting versions and a container (taking precedence over version) in a module constructor.

That's how I built my phpstan module (and most of my modules): https://daggerverse.dev/mod/github.com/sagikazarmark/daggerverse/phpstan@84e479601ced57c999880867f0beb56e2afd683d

A couple other thoughts:

  • If there is a module constructor, you can build most of the container upfront which simplifies the actual function that you invoke (mostly useful when there are multiple functions. For phpstan, I also have a generate baseline function)
  • sometimes it's a good idea to pin tool versions to avoid breaking due to accidental upgrades
  • nit: phpstan accepts multiple paths AFAIK.
  • it's generally a good idea to disable any interactive mode or progress reporting as they don't display nicely in some consoles/logs (phpstan has --no-progress AFAIK)

Instead of

            ->withMountedDirectory('/tmp/app', $source)
            ->withWorkDir('/tmp/app')

you can write

            ->withWorkDir('/tmp/app')
            ->withMountedDirectory('', $source)
#

Well, that became a bit longer than I expected πŸ˜„

#

Anyway, kudos on bringing Dagger to the PHP world!

#

One last note regarding your symfony PR: if those functions are always supposed to be called with --source=. why not set a default path?

Or better yet: why not just pass the source in the module constructor (with a default path)?

serene light
#

^ Which, if you decide to do, could look like this:

#[DaggerFunction]
public function __construct(
    #[DefaultPath('./my/default/path')]
    private Directory $source,
) {
}
#

The difference then being that your calls would change:
From dagger call psalm --source=.
To dagger call --source=. psalm

summer sequoia
#

fun bug. Turns out if you mount a composer.lock file in place of a composer.json file; composer will happily run and do... nothing.

serene light
#

Bug when mounting composer lock without composer.json

hallow hinge
#

Teaser 🀫

karmic tendon
hallow hinge
#

IDK, for now it's static. I've mapped all those commands manually. For most of them, there is no specific flags, for others, I've mapped the flags too (i.e --no-interaction for doctrine:migrations:migrate).

I've took 15 min to craft this, I'll take a look deeper to find out if we can dynamically map the commands from symfony, console and composer, even if we don't need all of them. Only the ones useful in CI are important for now (who runs make:auth in CI? πŸ˜„ )

karmic tendon
#

true but how do you make sure which ones are important ? They can all be. Not our decision to make IMO. For doctrine migration there is also the --allow-no-migrations or something

hallow hinge
#

Sure, we can ship a set of ultra popular commands and let users add some more in the future, based on their need. BTW, I also expose console, symfony and composer commands to let users run any available command. Ex: dagger call console --cmd="make:controller FooController --no-template". Kinda ugly but given the nature of Dagger, almost no one will write this manually everyday, but one time in a CI file.

summer sequoia
#

A better approach might be to write something which automatically generates a dagger module based on the CLI interface; should probably take a container as a constructor parameter to run the commands in but then there will still be a bit of complexity as to figuring out how exactly to run the command within a custom container you don't know anything about.

#

eg if the symfony binary wasnt in the place you expected it to be; or the workdir wasn't set as the directory containing the code (or maybe it is, but due to project layout, the php code is in a sub dir); or perhaps it's using an older version of a tool that you don't pass the correct args to...

#

lot of complexity to manage.

hallow hinge
#

Yes, it sounds great but incredibly complicated regarding the goal to reach. Let’s provide useful commands in CI context and users contribute complementary commands later. WDYT?

summer sequoia
#

I think we'll need to iterate over how this is done quite a bit really; until we get people using it, we won't know all the issues we need to solve

cunning pine
#

Don’t remember if you can change the output of the Symfony CLI, if you could output that as json I wonder if that could help with auto discovering commands in the module?

hallow hinge
karmic tendon
#

But for composer it is a bit more difficult I think... Composer allows through plugin to register new functions. So Yeah maybe something basic at first for common use case and create something more powerful later on.

summer sequoia
#
  • instantiate the cli application
  • call all() to get registered commands,
  • call getDefinition (or getNativeDefinition?) on each to get name & args
  • create PHP code to turn that into a dagger function.
  • create a boilerplate dagger object which takes care of
    -- taking a container to run stuff in as a constructor arg
    -- mounting your local src directory into said container
    -- returning an object which contains the string output of the command and the modified directory from the container
  • each function can then rely on the boilerplate for running the command; code is generated to handle passing in args

extra credit: use namespacing information to separate commands into multiple dagger objects

#

that will get you the basics sorted for any symfony cli based application

#

you can then modify the code as needed to handle special cases

karmic tendon
#

Is there a way to "publish" an image in the local registry ? (do not push)

inner walrus
karmic tendon
#

Yup

inner walrus
#
$ dagger shell -c 'container | from alpine | with-directory /dagger $(git https://github.com/dagger/dagger | head | tree) | export ./my.tar'

$ docker tag $(docker load -i my.tar | cut -d: -f3) my-image

$ docker run -it my-image ls /dagger
summer sequoia
#

The other way is to run a local docker registry and publish to that; you can then pull from it.

hallow hinge
# summer sequoia - instantiate the cli application - call all() to get registered commands, - ca...

Generating dagger functions based on json could work for the Symfony console, but not for the CLI tool (as it does not provide any other format than text for output).
That said, the most important commands live in the Symfony console, not in CLI (actually, the only important command from CLI is security:check I guess, others are related to Platform.sh (and could be a separated module), or to instantiate a new symfony app, or managing the dev server)

green otter
#

Hey @hallow hinge we're both awake hacking on Symfony/Dagger 😎

I'm focusing on the integration tests stuff .. grinding through that right now ..

summer sequoia
green otter
#

@hallow hinge update - all the services are now binding on my IntegrationTests work

Still got lots more work to do .. but the base services are running now πŸ™‚

summer sequoia
hallow hinge
summer sequoia
#

does that work?

#

I know at one point we were having issues in getting changes made in dagger functions to go back to the host.

hallow hinge
# summer sequoia does that work?

AFAIK, yes. I’ve tested it on a Symfony app locally, it worked.
Now, I’m wondering about using Dagger to build the CI of the module itself πŸ˜…πŸ”

green otter
#

@hallow hinge I'll check your cli module PR soon. Still crazy busy with first of the year rush.

hallow hinge
#

@green otter same here, no free time to work on it. Don’t hesitate to ping me if needed

obsidian forge
#

hm something weird seems to be going on with the php traces - it seems like we lose all spans from a php dependency module, which means there's no info on what's going wrong when we get a failure

#

for example, if i run dagger call -E sdk php lint in the dagger repo, i don't seem to be able to find a span in the TUI or the cloud that corresponds to the withExec for phpcs

#

this is a bit of a pain, because it seems like phpcs is a bit flaky
but i can't ever seem to catch a failure of it

serene light
obsidian forge
#

aha

#

i found the issue πŸ˜›

#

the dev module was using a very old version of the php sdk

#

which didn't have this support

serene light
#

Ah... good to know. @obsidian forge While you're here, are there any updates on using the names of enums?

obsidian forge
#

uh no updates, it's not really been on my radar recently

#

the issue is still the plan

#

we just haven't really had the time to properly do it

serene light
#

That's completely fine, thanks for the update πŸ‘

Just wanted to double check if I should be brushing the dust off my enum PR

serene light
#

@ocean creek you wizard, just admiring your work on the traces for PHP. πŸŽ†

ocean creek
#

Thanks πŸ˜ƒ

obsidian forge
# serene light I'm not sure of what is in the sessionOutput. That code was mostly fleshed out b...

okay, i wrote this up into an issue since it's still happening - and submitted a potential fix in https://github.com/dagger/dagger/pull/9348

GitHub

This is an attempt to fix the PHP flake from #9346.
What appears to be happening is that despite confirming that the output we read has session_token in it, we're somehow decoding a JSON ob...

#

my best theory atm is that using setPty is doing weird things - somehow, i'm seeing progress output come through the callback? which shouldn't be happening, it should only be appearing in stderr.

serene light
obsidian forge
#

yeah, no real clue what's going on - we'll see if it keeps happening with that change πŸ˜›

#

it occurs with some amount of consistency πŸ˜›

summer sequoia
#

I'd really like to get rid of the cli client downloader thing. I really feel that it shouldn't be required if everyone is using the PHP SDK to build dagger modules (Rather than just making dagger calls) as we know the details for connecting to the dagger graphql API will be present in the container spun up by the SDK

#

the client download is only a fallback if there are no creds defined in the environment

#

//cc @green otter what do you think?

serene light
# summer sequoia I'd really like to get rid of the cli client downloader thing. I really feel tha...

I think at this point; if someone wants to continue using dagger the old way, they can always use an old version.
If it was not causing any harm, I might feel differently. As it stands, continuing to support the old way seems to be cause consistent CI flakes which wastes further development time.
Arguably, we could simply remove any tests related to it, but at that point, we're just holding on to an outdated and untested piece of kit.

While we're talking about removing things:
It would be nice to get rid of the committed generated/ directory.
That whole weird chicken and egg situation of needing a Client to generate a Client.

summer sequoia
#

yeah, again with the generated stuff; that's only needed if it's being run stand alone; as a module the SDK should inject the graph ql spec file already

obsidian forge
#

imo, i think removing the provisioning stuff is a decision to be made across several sdks? obviously kind of up to y'all, support can just be dropped, but i think there's a conversation to be had about whether we just entirely remove it

#

you can still use the standalone sdk without automatic provisioning using dagger run

#

cc @cobalt pelican since we've had this conversation a few times before

cobalt pelican
#

Yeah. Using dagger run has a better experience (e.g., TUI), but some old timers still like the automatic provisioning stuff still so they don't have to fetch the dagger CLI first. However, for new/experimental SDKs, I suggest to keep it off. Standardize around dagger run for non-modules. Keep the maintenance burden lower by not worrying about automatic provisioning support.

radiant flume
#

If we remove auto-provisioning, the SDK will still be capable of executing dagger session on its own, it just will require dagger already being installed, correct? So even dagger run won't be mandatory, just installing the dagger CLI yourself as a runtime dependency of your dagger-powered tool.

I'm perfectly OK with that πŸ‘† and I believe we agreed to do this in the past @obsidian forge @cobalt pelican ? Perhaps we neglected to make it an issue, I can't find it in the record

cobalt pelican
# radiant flume If we remove auto-provisioning, the SDK will still be capable of executing `dagg...

We usually refer to automatic provisioning as both the download and running dagger session. We haven't discussed splitting those afaik. But notice that I'm only arguing for ditching automatic provisioning for experimental SDKs, which don't have the same baggage as the 3 stable ones. The SDK docs mention since the start that this is an optional feature. That was written before modules, at a time where we wanted to shift focus to the dagger CLI (dagger run and the TUI were new) . I think for Go, Python, and TypeScript, it requires it's own discussion because there's different things to consider.

radiant flume
#

I think we should discuss the download & running separately. Ditching the download makes sense. Ditching the running IMO doesn't, the loss of feature isn't worth the saved work IMO (download is more work than run)

summer sequoia
#

There are a couple of separate things here; the first is that using calls out to the dagger cli to talk to the engine was a bit flakey. Using the graphql client is preferred; however that needs the session data set as env vars to work

radiant flume
summer sequoia
radiant flume
#

Ah, sorry I'm not familiar with the specifics of this sdk. But generally executing dagger session is the recommended way to open a session, it's not recommended to do it with a native http client, because the logic and use of env variables and config files will evolve over time and it's not realistic for all SDKs to implement it all correctly and thoroughly as it changes

summer sequoia
#

hmm, well for dagger modules, I thought we could always rely on having the session env vars set. I was also under the impression that dagger modules were the way to go, going forward; so since the PHP SDK is new and/or shiney we can encourage users to only go down that path; meaning the other options are far less important

kind linden
#

Hi, i've been following dagger for a couple weeks now. Interesting tool. We are using php/symfony at our company. Is the php sdk ready for a poc or is it too early? Is there an overview somewhere of outstanding/known issues? On what topics is help needed?

I want to start with the dagger quickstart and something like running phpstan or php cs fixer with the php sdk. Is that doable right now?

serene light
#

PHP SDK Quickstart

green otter
#

Hey @kind linden welcome here! Did you attend my Dagger PHP talk at SymfonyCon Vienna (December 2024) ?

You can indeed use the phpsdk, it is indeed ready for you to start using.

Don't worry about the "Experimental" keyword, that's because it's not being updated by dagger core team on every release, for any new shiny stuff.

We (the php community) are updating the PHPSDK as new features come online.

95% of all the features you want to use for your pipelines, are 100% functional and working for many months now πŸ™‚

green otter
#

If anyone here joined from SymfonyCon or SymfonyOnline, just wave here πŸ‘‹

haughty smelt
#

πŸ‘‹πŸΌ

kind linden
#

I saw the announcement of your talk and am very interested but have not seen it as i didnt join the conf.

green otter
#

welcome @haughty smelt

#

welcome @lapis drum

green otter
#

Hey @cunning pine so if you're thinking about building a Dagger module for PHP community - ping me (and others here) first, as we have loads created that are just pending publishing, and you may be building stuff that already exists .. and thus instead you can focus on things that don't exist πŸ™‚ just let us know what's on your mind

cunning pine
green otter
#

ok

green otter
#

"I have a few modules that are PHP adjacent," - feel free to share with me stuff you're upto πŸ™‚ curious and enthusiastic

ocean creek
#

@green otter @serene light @summer sequoia @shy goblet πŸ‘‹ I open a PR to add float type support here https://github.com/dagger/dagger/pull/9411.

The most commits in this PR come from https://github.com/dagger/dagger/pull/9396 which is based PR so you can focus on https://github.com/dagger/dagger/pull/9411/commits/458361717dd2cbf00f8833e26b0cd8da447001b3 afterwards.

My PHP knowledge is very very limit so please tell me if I'm missing something. πŸ™‡β€β™‚οΈ

GitHub

GitHub is where people build software. More than 100 million people use GitHub to discover, fork, and contribute to over 420 million projects.

GitHub

Summary
Add float support and fixes #9280.
Doc page available on #9408
Examples
Go
package main

import "context"

type Test struct{}

func (m *Test) Test(n float64) float64 {
re...

GitHub

This PR follow up #9396.
How to test this feature
I create a module named potato and put the following code to src/Potato.php:
<?php

declare(strict_types=1);

namespace DaggerModule;

use D...

green otter
#

hello again @ocean creek - hope you had a good christmas holiday period πŸ™‚

#

@ocean creek I checked your PR - I believe it's all that's necessary. Only thing I can think of is that we could have a unit/functional test in the test suite, to make sure the correct GraphQL is generated, for float .. or that we're correctly parsing the GraphQL and ensuring things basically work end to end.

I'm not 100% remembering how we do our testing, so I'll defer to @summer sequoia and @serene light on any other comments or on their thoughts on how we can make the testing more robust.

ocean creek
#

@green otter πŸ‘‹ Hi, hope you had a good christmas holiday period as well.

This is the first time for me to use PHP type system, I'm unsure if it has any other types than float.

lapis drum
green otter
green otter
lapis drum
#

Ah okay, thanks πŸ™‚

#

Hmm so I'm first trying to run PHPUnit in a PHP 8.4 container (because, why not? :p)
Any idea how I could mount automatically the app directory into the container?

green otter
#

Yep

#

Stand by

lapis drum
#

Stills requires me to pass the directory :/

! required flag(s) "dir" not set

green otter
lapis drum
#

I mean, in your example here, you still have to pass the --dir option; I'd like to avoid that πŸ˜…

green otter
#

Mount the entire cwd

#

I'm at the bar. I can't show you that. Just do this to learn πŸ™‚ fix later

#

type "dagger functions" to see the function list

#

It's like symfony console basically

lapis drum
#

Ah found it, #[DefaultPath('.')]

green otter
summer sequoia
#

yeah, because Directories are objects, you can't give them a default in your code; the attribute exists so that you can give a default as a string and have it converted into a real directory

#

That attribute also pairs with #[Ignore] so you can avoid adding things to dagger you don't need (and might mess with it's cache)

zealous venture
lapis drum
#

Thanks for the information πŸ™‚

serene light
# ocean creek <@466733415539015681> <@1229425915675807797> <@459650547872563201> <@28187448065...

Thank you for the PR I requested a few changes that are necessary for it to pass CI.

I also gave an example of a couple tests that could be added, but I'm fairly certain it will already handle floats.

GitHub

This PR follow up #9396.
How to test this feature
I create a module named potato and put the following code to src/Potato.php:
<?php

declare(strict_types=1);

namespace DaggerModule;

use D...

ocean creek
serene light
#

chore(sdk/php): use DefaultPath to SDK s...

restive umbra
#

Hey all πŸ‘‹ Laravel dev here, looking to start looking into using Dagger for our testing and asset build pipelines as they are phenominally painful to get running on github actions, and slow to run locally with act. Any tips or trick, or starting points specifically for Laravel that anyone knows about would be amazing.

serene light
#

That would get you a basic module, those would be the first steps regardless of framework

restive umbra
#

Done, although, i started with Typescript just because the docs for the PHP SDK didn't seem to exist currently

#

I know it's WIP

serene light
#

Ah fair enough, if you prefer you can always work in Typescript

#

But if you prefer to use PHP it should be more than capable

restive umbra
#

Thanks, i'll take a look! I'm on the lookout for example dagger modules anyone might have for Laravel projects, but i know that's a stretch at the moment, if anyone spots one let me know!

serene light
#

I guess it depends what you're trying to set up exactly, is this CI stuff like phpunit, pest, phpcs, php-cs-fixer etc.

restive umbra
#

Yeah, so running our tests with phpunit/pest, and then we also have an asset pipeline where we (currently) build our front-end assets locally, but we'd like to move that to CI so it can happen on push etc.

serene light
restive umbra
#

Thanks!

serene light
#

No problem, also in terms of docs for PHP SDK, if you generate a PHP module, it comes with a README that has some rough guides on each feature

restive umbra
#

Ah beautiful, thank you again.

obsidian forge
#

I've been enabling graphql validations, and just caught this here πŸ€”

#

does it make sense to remove the first couple lines there?

serene light
# obsidian forge does it make sense to remove the first couple lines there?

It's been a while since I went that deep on the GQL part of it but this is the function that it boils down to

    public static function formatValueForRHS(
        null|bool|float|int|string|BackedEnum|Stringable $value
    ): string {
        if (is_null($value)) {
            return 'null';
        }

        if (is_bool($value)) {
            return $value ? 'true' : 'false';
        }

        if (
            is_float($value)
            || is_int($value)
            || $value instanceof Stringable
        ) {
            return (string) $value;
        }

        if ($value instanceof BackedEnum) {
            return (string) $value->value;
        }

        if (self::isVariable($value)) {
            return $value;
        }

        if (str_contains($value, "\n")) {
            return sprintf('"""%s"""', $value);
        }

        $value = preg_replace_callback(
            '/[\x00-\x1f\x22\x5c\x7f-\x9f]/u',
            function (array $matches) {
                $str = $matches[0];
                return self::ESCAPE_SEQUENCES[ord($str[0])];
            },
            $value
        );

        return sprintf('"%s"', $value);
    }
#

So yeah, it gets in here... looks at it, if it's a string it's going aaaaaaall the way to the bottom and surrounding it in double quotes.

#

So yes

#

For a backed enum we actually want to just pass it in

obsidian forge
#

awesome okay

serene light
#

Obviously, give it a whirl and see if it explodes 🀞

obsidian forge
#

definitely πŸ˜„ thanks for the help, i'm really really not familiar with php, so the assistance is always appreciated πŸ™‚

serene light
#

Thank you for the spot, honestly I'm admittedly not familiar with the setup before I started working on it. I want to look into it and start understanding the guts of it more.

#

But working out where to start is hard.

obsidian forge
#

oh also i had a thought 🀦
dagger.json for the php dev module can just be:

{
  "name": "php-sdk-dev",
  "engineVersion": "v0.15.2",
  "sdk": "../",
  "source": "."
}
#

that way it always uses the same version as in-tree

#

i wonder if there's a downside to that

#

otherwise i'm gonna have to work out how to stagger this change somehow

serene light
#

Oh that's interesting, I didn't know it could reference another dagger.json like that!

#

I think that would be a decent change. As testing in development is literally what the dev module is for

obsidian forge
serene light
#

πŸ€” I believe we did that to normalize objects and arrays for GQL.

So PHP has:

  • lists [1, 2, 3]
  • arrays [a => 1, b => 2, c => 3]
  • objects which if they're serializable, then they can end up looking like ``[a => 1, b => 2, c => 3]`
#

There's going to a neater way to do it, but it worked, so for now it stayed.

#

But clearly something is going awry there

obsidian forge
#

even something like echo "{container}" | dagger query produces an invalid result

#

(it should error out, but isn't for some reason)

#

since inputArgs is actually an object type

#

since it's a list, we should just be able to iterate over it and fill a map like we do in the go example?

serene light
#

Sorry, my memory of why it's done that way is a bit hazy, so whether I'm forgetting the reason or not... 🀷

I think in part, it was done this way due to limited knowledge of what inputArgs could be.
So this decode, encode bit...

        $args = $this->formatArguments(
            $parentName,
            $functionName,
            json_decode(json_encode($functionCall->inputArgs()), true)
        );

... forced the data into a format that was a bit friendlier for me to inspect.
I was able to see that it was simply an array with a Name and Value, ready for formatting.

    /**
     * @param array<array{Name:string,Value:string}> $arguments
     *
     * @return array<string,mixed>
     */
    private function formatArguments(

So, this, may be tech debt to be honest.

I think the changes required are quite small. I should be able to sort them fairly quickly when I find the time, but I would like to know if there is an exact format I should expect each argument to be in?

GitHub

An engine to run your pipelines in containers. Contribute to dagger/dagger development by creating an account on GitHub.

#

Is inputArgs always a list of objects, each with the properties: Name and Value ?

serene light
#

But that is only occuring on the phpsdkdev test function.

#

It builds all of the container before that stage

#

and i can run dagger/sdk/php dagger call -m dev format and it works

#

I also keep running into a lot of [ERROR] Undefined constant Dagger\TypeDefKind::FLOAT_KIND When trying to test a WIP branch as the SDK version.

#

I assume that might be an issue until 0.15.3 is tagged?

ocean creek
serene light
ocean creek
serene light
inner walrus
serene light
#

Should I make an issue for it?

inner walrus
serene light
#

Done.

Feel free to edit it or add anything if I missed the point πŸ™‚

GitHub

An engine to run your pipelines in containers. Contribute to dagger/dagger development by creating an account on GitHub.

inner walrus
#

The other thing would be to understand what IDE integration setup folks would need to do for code-completion, etc similar to:
https://docs.dagger.io/api/ide-integration/

Dagger uses GraphQL as its low-level language-agnostic API query language, and each Dagger SDK generates native code-bindings for all dependencies from this API. This gives you all the benefits of type-checking, code completion and other IDE features for your favorite language when developing Dagger Functions.

serene light
cunning pine
serene light
serene light
#

Any objections are welcome but from what I've seen: pretty much every editor like Zed, Emacs, Vim, Neovim, VSCode, etc. uses LSP

This means php language detection for pretty much every editor is based on phpactor or intelephense My experience with phpactor has been that it detects all of the dagger classes and methods out of the box.

So my expectation is any editor using LSP is just going to work OOB.

GitHub

Mainly a PHP Language Server with more features than you can shake a stick at - phpactor/phpactor

GitHub

PHP intellisense for Visual Studio Code. Contribute to bmewburn/vscode-intelephense development by creating an account on GitHub.

#

The exception being PHPStorm which, ignoring how it works (I don't know), also just works OOB.

green otter
#

@hallow hinge can you link me to your symfony-cli work? I wanna see what docker images you're using (base docker image) πŸ™‚ and thus what PHP extensions you're using

hallow hinge
#

Feel free to commit on this branch if needed

obsidian forge
#

the BackedEnum support only appears in the newest version

summer sequoia
#

Quick Q to anyone building with the PHP SDK: has anyone added a dependency to their composer.json other than the auto generated/added dependencies put there by codegen?

radiant flume
#

Hi PHP wizards... @summer sequoia @green otter @hallow hinge @serene light I asked the same question to the Java folks. I am very curious to see what would happen if you built a toy AI agent module with the SDK PHP, similar to my demo here: https://x.com/solomonstre/status/1891205257516003344

That demo is based on a branch of the engine (to add the navive LLM type and magic tool-calling capabilities). It should all work with any SDK.

I think the PHP community might be very excited at the idea of not only writing world-class CI pipelines in PHP, but also leapfrogging the AI engineering community, and perhaps writing world-class AI agents in PHP as well πŸ™‚

If you're interested in trying, we're hacking on this in #agents

inner walrus
#

The PHP SDK has liftoff!!
#announcements message
Huge thanks to the community leaders that made this SDK happen@summer sequoia @serene light @green otter congrats! πŸŽ‰

Great to see the collab with the PHP pros on the Dagger staff as well @zealous venture @cunning pine πŸ™

kind linden
#

Congrats all! This will help a lot to get newbies like me on board πŸ™‚

grim stump
#

Its so awesome to see this all come together and launch. I am inspired by all the work that went into it from this group, amazing!

amaze

radiant flume
green otter
#

Docs docs docs

#

When they land they must see

hallow hinge
#

Hi PHP wizards... @Carnage @

serene light
#

Hey @obsidian forge we just want to quickly test the fix @summer sequoia discussed during. I ran dagger develop with this schema

{
  "name": "update-minimal-dagger",
  "engineVersion": "v0.15.4",
  "sdk": {
    "source": "github.com/carnage/dagger/sdk/php@fix-composer-lock"
  }
}

We get this error

! failed to get sdk required paths: failed to call sdk module requiredPaths: select: Select: PhpSdk has no such field: "requiredPaths"
obsidian forge
#

aha

#

okay, so requiredPaths has now been removed

#

what engine version are you using?

serene light
#

currently 0.15.4 I believe

obsidian forge
#

i expect what's happening is that fix-compose-lock is based off of v0.16.0 (so has no requiredPaths), but the engine is v0.15.4 (and so needs it)

serene light
#

Oh, I see...

obsidian forge
#

if you upgrade the engine, it should fix it

serene light
#

It is, yes.

#

Thank you, brilliant. I'll let you know how it goes and we should be able to merge that fix soon πŸ™

obsidian forge
#

no worries πŸ˜„ anytime! πŸ’œ

serene light
#

Alright, merged the branch. That should remove some a few hiccups. Thank you @summer sequoia @obsidian forge

#

As a side topic I've been wondering about: How do the other SDKs test actual integration with dagger?

#

Like, creating some test modules and calling them from dagger?

#

Because right now the PHP SDK has unit tests for code that can be tested independently, but integration or feature tests are basically non-existent

obsidian forge
#

yeah πŸ€”

#

then you can create modules using --sdk=./path/to/imported/sdk/source

#

and write tests similarly to how we do for all of our other tests

serene light
obsidian forge
#

i'm just very lazy actually, and don't like having to manually check things work

ocean creek
#

I can help looking into this if you like. I have planned to add it to Elixir as well to discover what I missed in the SDK.

serene light
ocean creek
#

Nice. Will looking into this weekend, hopefully that PR will be open around Tue-Wed.

ocean creek
obsidian forge
#

yup πŸ™‚ although if you do that, that version will stop working on the new versions of the engine (though i think that's absolutely fine)

serene light
obsidian forge
#

hmmm

#

i feel like this might have started breaking stuff on main after it was merged

#

since there's a php test that does init with sdk php@main

#

Cannot update only a partial set of packages without a lock file present. Run composer update to generate a lock file.
^ this feels a bit suspicious

summer sequoia
#

why didn't it break on the PR?

#

might have to wrap that update with a if file exists (composer.lock)

#

revert for now and we can fix it asap

covert bolt
#

Hi everyone! Is this the correct channel regarding daggerizing a PHP (Symfony) project?

covert bolt
obsidian forge
# summer sequoia why didn't it break on the PR?

These only started failing on main because these tests fetch the version of the PHP SDK from main. While these checks are somewhat important, we should probably have a test for the commit - similar to how it's done for TestJava.
(quoting myself from the pr)

cunning pine
#

Also, is there a way to set a default directory with the PHP SDK. Maybe I missed it in the docs? Trying to do something like this (using a default directory in the constructor):

serene light
#

#[DefaultPath] on the Directory parameter

#

You also have #[Ignore('this.txt', 'that.json', 'dont-forget-this.yaml')]

cunning pine
# serene light #[DefaultPath] on the Directory parameter

Totally forgot attributes can be used in functions! facepalm

Also, I feel like we need to add those as examples to this page (specifically for default paths and docs) https://docs.dagger.io/api/arguments/

Dagger Functions, just like regular functions, can accept arguments. In addition to basic types (string, boolean, integer, arrays...), Dagger also defines powerful core types which Dagger Functions can use for their arguments, such as Directory, Container, Service, Secret, and many more.

serene light
#

We have the default path one there: https://docs.dagger.io/api/default-paths

It is possible to assign a default path for a Directory or File argument in a Dagger Function. Dagger will automatically use this default path when no value is specified for the argument. The Directory or File loaded in this manner is not merely a string, but the actual filesystem state of the directory or file.

cunning pine
#

we meaning all languages, not just php

serene light
#

I'm not sure where Ignore is but I think we got it as well?

#

Yeah, that might be useful on the same page actually

cunning pine
#

yeah, I think the arguments page should also highlight some best practices - like documenting the args. Thoughts?

serene light
#

I think that would be a good move, or at least make a note of it within the page and point to the relevant info

#

Because, case and point; you went looking for how to put a default on a Directory argument and did not find it where you expected

#

I definitely think we should mention it, or point to it here: https://docs.dagger.io/api/arguments#default-values

Dagger Functions, just like regular functions, can accept arguments. In addition to basic types (string, boolean, integer, arrays...), Dagger also defines powerful core types which Dagger Functions can use for their arguments, such as Directory, Container, Service, Secret, and many more.

#

I think because there's quite a lot of info to digest on default paths and inline docs, it's probably best to point to it (rather than try to wedge it all in). But a brief mention would help anyone who follows the same path through the docs that you experienced just now

obsidian forge
#

mm, agreed, that is weird.

#

imo, arguments + default paths + directory filters are all very related?

#

makes sense to have them on different pages i guess, but they either need better linking, or should maybe appear one after each other?

cunning pine
#

yeah I'm always jumping between those pages

obsidian forge
#

maybe @zealous venture might have some context for why it's currently like this?

zealous venture
#

It looks like this change didn't help much, so I'll open a PR to add prominent cross-links between those pages and we can see if that helps.

#

Open to other ideas as well ofc!

serene light
zealous venture
#

Thanks for the feedback!

zealous venture
#

when you have a few minutes, please check out Jason's awesome Laravel agent written with Dagger: #agents message

serene light
#

PHP SDK Integration tests

cunning pine
serene light
#

But yes, that switch statement is clearly never going to work for darwin.

#

Having a quick look at it, I think there's a better solution here by relying on PHP_OS_FAMILY instead.

it has a smaller subset of predefined values and we can match against them exactly rather than str_contains

PHP is a popular general-purpose scripting language that powers everything from your blog to the most popular websites in the world.

#

One of 'Windows', 'BSD', 'Darwin', 'Solaris', 'Linux' or 'Unknown'. Available as of PHP 7.2.0.

cunning pine
#

Maybe we should discuss the composer require? I think embedding dagger clients in other programs is a little bit of a super power (we document how to in the other SDKs). From personal experience, that is how I deployed it with Craft Cloud (embedded dagger client in a Go application).

serene light
#

I might be mistaken, I just looked more closely at the docs you linked

cunning pine
cunning pine
serene light
#

I don't think we are against requiring dagger in projects, I'm just not particularly accustomed with how it works and if it does

#

That part of the functionality was developed before I got involved, I haven't touched it too much because I didn't want to break it. πŸ˜“

I'm currently working on the integration tests. Once we've got a more thorough suite, it should be a bit less daunting to work on it.

summer sequoia
summer sequoia
ocean creek
#

@serene light Here is the integration tests we discussed last week https://github.com/dagger/dagger/pull/9712. It has only 1 feature, 2 tests at the moment but I think we can add more to this PR. πŸ˜„

NOTE: This needs to be merge after https://github.com/dagger/dagger/pull/9710 in order to make CI happy.

GitHub

GitHub is where people build software. More than 150 million people use GitHub to discover, fork, and contribute to over 420 million projects.

GitHub

Adds a test which takes the local ./sdk/php to test if the current changes work.
This is to help avoid issues like this.

serene light
green otter
ocean creek
slim thistle
#

hi, I think there is an issue while creating a module πŸ€”
EDIT: it seems that I did not have network in docker ... my bad

ocean creek
#

is this working?

$ dagger init --sdk=github.com/dagger/dagger/sdk/php foo 
serene light
serene light
cunning pine
serene light
#

@shy goblet If you have a moment, could you please have a look at this?

I noticed you've mentioned [this is a known flake](#1334452944740814931 message)

It's the same output we're getting here

I'd have assumed flake already, but since the PR changes the core/integration/module_php_test.go It's somewhat related to the jobs that are failing.

GitHub

An engine to run your pipelines in containers. Contribute to dagger/dagger development by creating an account on GitHub.

shy goblet
serene light
#

It seems to get this error:

Run #!/bin/bash --noprofile --norc -e -o pipefail
Error: Process completed with exit code 1.
#

I'm not finding any useful information in the error to work out what went wrong

cunning pine
shy goblet
green otter
#

@serene light what's our most basic php example we can give someone.

  1. Install composer
  2. Php ext install <--- which extensions do we choose?
  3. composer install
  4. run phpunit
shy goblet
#

Elixir tests are failing, same on my PR

#

And there are also some flakes with private module using SSH

serene light
#

I seem to be able to access it, but only via your link. I don't know how to get there normally

shy goblet
#

dagger.cloud -> dagger organisation

#

@zealous star Are the dagger repo traces publicly accessible?

zealous star
#

they are, but only with a direct link, yea - you can't view the trace listing atm

serene light
#

Ah okay, yeah I was looking and could not find a link to the organisation page

#

I only have my local traces set up

#

@charjr what's our most basic php

ocean creek
ocean creek
serene light
#

@ocean creek That's fine πŸ™‚ Also thank you for finding the link! I tried clicking it but I don't seem to be able to access it like that.

green otter
#

@summer sequoia @serene light about to help me before my community call?

β”‚ β”‚ β”‚ β”‚ β”‚ ! process "/src/dagger/entrypoint.php" did not complete successfully: exit code: 1
Error: failed to serve module: input: moduleSource.asModule failed to load dependencies as modules: failed to load module dependencies: select: failed to call module "php" to get functions: process "/src/dagger/entrypoint.php" did not complete successfully: exit code: 1
#

Existing codebase, I upgraded dagger to the latest

summer sequoia
#

there seems to be some over zelous caching of module dependencies going on hit us earlier

green otter
#

Nope.

#

Trying

#
✘ ModuleSource.generatedContextDirectory: Directory! 1.5s
! failed to load dependencies as modules: failed to load module dependencies: select: failed to call module "php" to get functions: process "/src/dagger/entrypoint.php" did not complete successfully: exit code: 1
Error: failed to generate code: input: moduleSource.withEngineVersion.generatedContextDirectory failed to load dependencies as modules: failed to load module dependencies: select: failed to call module "php" to get functions: process "/src/dagger/entrypoint.php" did not complete successfully: exit code: 1
summer sequoia
#

does the dependant module work independently?

#

if so; might need to a) update the engine version in the dagger.json of the module; b) update any dependencies it uses; c) remove composer.lock from the dependency repository (temp until the fix for this goes in)

green otter
#

I might just remove the external module

#

and re-add it

#

later on ..

summer sequoia
#

you may have the same issue tbh#

#

if the module was created on an older version of the engine; good chance you hit the composer.lock issue with it

serene light
#

Your best bet if possible is as chris said, remove the composer.lock from the module

green otter
#

Please send me URLs to more examples

#

so I need our custom PHP module @summer sequoia @serene light

#

for extensions

#

and such

cunning pine
green otter
#

we already have one for a few months now, and it's written in PHP

#

thanks for replying tho

#

@cunning pine feel free to add examples on your readme

#

on how to use it, from PHP

summer sequoia
#

I had an example PHP module, but I've been focusing on Sai recently as a more general purpose toolkit

serene light
#

I don't have any example modules unfortunately

green otter
#

It's fine, I used my phpstan() daggerverse module, for the community call demo

#
return dag()->phpstan()->analyze('8.4', $this->source, './app');

#

PS: don't format your OS the day before you're due to do demos πŸ˜›

#

@summer sequoia can you link me to some examples of using our PHP module, for extension installations?

summer sequoia
green otter
#

Found some old usage of it, onan older version of the SDK

$container = $this->client->php()->cli('8.2');
$container = $this->client->php()->withExtension($container, 'pdo_mysql');
$container = $this->client->php()->withExtension($container, 'intl');
$container = $this->client->php()->withExtension($container, 'gmp');
$container = $this->client->php()->withExtension($container, 'gd');

New version should probably be something like

dag()->php()->cli('8.2')->withExtensions(['intl', 'gmp', 'gd'])
#

Hey Team! Here is the new "base snippet" for the PHP community - I've given it to @inner walrus to review and update our Blog Post Announcement .. and we can use this for "intro to dagger PHP" too.

https://gist.github.com/dragoonis/5e10df970f062324afbd8f549b960298

This is what we can use to teach people.

Lesson #1 of our tutorials. People can add this to ANY php project (mostly) and have it execute tests

Gist

GitHub Gist: instantly share code, notes, and snippets.

#

@summer sequoia I need the URL to our PHP system builder package we worked on .. can you link me to it please? I want to review it and also bring it up to date with latest PHP SDK and test it out .. then it's ready for documentation stuff.

green otter
#

aye

summer sequoia
#

Usage is how you described the update you wanted

green otter
#

@inner walrus @cunning pine @summer sequoia @serene light

Here is the "Dagger PHP" github organisation I was talking about. I will get you guys added to it. It will be where we host our "official community dagger modules" for popular things.

Like SymfonyCli, phpstan, psalm, drupal, magento, laravel .. and so on I already have the modules on my personal github, but it shouldn't live there it should be part of the community

I have 2-3 laravel project build stuff already made, I'll publish it soon too

Symfony is in progress

QA tools are complete, need moving over to the organisation

https://github.com/dagger-php

For our modules we will have to

  1. Write good docs
  2. Tag releases so they're pinned against specific dagger engine versions. As dagger engine team try to innovate and change/break stuff, we need to allow them to do so, so we can separate by "tag"
GitHub

Collection of Dagger modules dedicated to PHP toolchain - DaggerPHP

#

phpstan module - discussion

fast vine
#

Hi, how do you solve the issue with Dagger performance due to missing cache in CI? I mean, every time Dagger builds its cache in CI, so simple call takes up to 5 minutes in GitLab. I saw Depot, but it's paid (I'm doing open-source mostly, so that's not an option). Do you solve it somehow, or just doesn't care about it? Thanks in advance! If you have any examples I'd be great to see them πŸ˜….

inner walrus
green otter
#

Thread

inner walrus
#

Hey PHP Daggernauts!

If you're looking for a way to get involved, we have a number of docs issues open that we'd all be glad to review and merge PRs on.
https://github.com/dagger/dagger/issues/9790 (parent issue)

Overall the PHP docs are really solid, but this set will make it stellar. Could be a great first issue for someone. 🀩

If you'd like to claim one, I'd suggest leaving a comment on the issue to say you're working on it and get a draft PR up as soon as you can with your first commit in it. Make sure to put something like fixes #9779 in the PR description so the issue and PR will be linked up. link

Then when you've got all of your commits in, you can make it ready for review and drop it in here. πŸ™‹

Thanks in advance! We're close to having full docs coverage for PHP. πŸš€

GitHub

What is the issue? Add missing documentation for the PHP SDK. Individual page requirements are described in linked sub-issues.

slim thistle
serene light
slim thistle
# serene light You should be able to use daggerverse and install modules without issue. πŸ™‚ [T...

when I try, I got an error:

$ dagger init --sdk=php .
# ok
$ dagger install github.com/sagikazarmark/daggerverse/gh@v0.11.0

Warning: Undefined array key "description" in /sdk/vendor/webonyx/graphql-php/src/Utils/BuildClientSchema.php on line 363
Warning: Undefined array key "description" in /sdk/vendor/webonyx/graphql-php/src/Utils/BuildClientSchema.php on line 363
Warning: Undefined array key "description" in /sdk/vendor/webonyx/graphql-php/src/Utils/BuildClientSchema.php on line 428
Warning: Undefined array key "description" in /sdk/vendor/webonyx/graphql-php/src/Utils/BuildClientSchema.php on line 363
Warning: Undefined array key "description" in /sdk/vendor/webonyx/graphql-php/src/Utils/BuildClientSchema.php on line 363
Warning: Undefined array key "description" in /sdk/vendor/webonyx/graphql-php/src/Utils/BuildClientSchema.php on line 363

 [INFO] Generating scalar 'CacheVolumeID' 
 ...

Fatal error: Uncaught TypeError: Nette\PhpGenerator\ClassLike::addComment(): Argument #1 ($val) must be of type string, null given, called in /sdk/src/Codegen/Introspection/EnumVisitor.php on line 20 and defined in /sdk/vendor/nette/php-generator/src/PhpGenerator/Traits/CommentAware.php:37
Stack trace:
#0 /sdk/src/Codegen/Introspection/EnumVisitor.php(20): Nette\PhpGenerator\ClassLike->addComment(NULL)
#1 /sdk/src/Codegen/Introspection/AbstractVisitor.php(20): Dagger\Codegen\Introspection\EnumVisitor->generateType(Object(GraphQL\Type\Definition\EnumType))
#2 /sdk/src/Codegen/Introspection/CodegenVisitor.php(45): Dagger\Codegen\Introspection\AbstractVisitor->visit(Object(GraphQL\Type\Definition\EnumType))
#3 /sdk/src/Codegen/Codegen.php(61): Dagger\Codegen\Introspection\CodegenVisitor->visitEnum(Object(GraphQL\Type\Definition\EnumType))
#4 /sdk/src/Command/CodegenCommand.php(61): Dagger\Codegen\Codegen->generate()
serene light
slim thistle
serene light
#

Also thank you for the replicable stack trace πŸ™‚

radiant flume
#

Found some duplicate code between .dagger/sdk_php.go and sdk/php/dev/src/PhpSdkDev.php.

Going to try and transfer some of that code from the Go to PHP side

#

PHP SDK devs: just checking that you actively use the module github.com/dagger/dagger/sdk/php/dev, and it accurately represents an up-to-date toolchain? In particular that container build. Can I rely on it over the one built in sdk_php.go?

#

They look very very similar

serene light
# radiant flume Found some duplicate code between `.dagger/sdk_php.go` and `sdk/php/dev/src/PhpS...

You're welcome to give it a go, it's referenced in issue #8125. It's been on the backburner, I never quite got round to solving it.

sdk/php/dev is the developer module used for running unit tests and linting on the sdk itself. It hasn't been updated in a while but it is an actively used as part of development.

GitHub

An open-source runtime for composable workflows. Great for AI agents and CI/CD. - Issues Β· dagger/dagger

serene light
#

^ Also, if it isn't the up-to-date toolchain, it will be.

I want to make extensive use of that module for testing the SDK. πŸ”

serene light
#

@obsidian forge Do you have any idea how to do this bit in PHP?

dirOpts := dagger.ContainerWithDirectoryOpts{
  Exclude: "*.md*",
}
#

I'm trying to write the filters bits of the docs. I've never used this method before.

#
const dirOpts = { exclude: ["*.md*"] }

Typescript just seems to be an anonymous object?

#

I'm assuming in PHP it's just

$dirOpts = ['exclude' => ['*.md*']];

But I'll be honest, I'm not really sure what purpose these snippets serve: https://docs.dagger.io/api/filters#post-call-filtering

When you pass a directory to a Dagger Function as argument, Dagger uploads everything in that directory tree to the Dagger Engine. For large monorepos or directories containing large-sized files, this can significantly slow down your Dagger Function while filesystem contents are transferred. To mitigate this problem, Dagger lets you apply filter...

obsidian forge
#

it's just an optional arg

#

the reason it's the struct in go is because go doesn't haven't optional args

#

it's like that in ts, because that's a pretty common pattern

#

you just need to pass exclude, and override the option

serene light
#

Ah thank you, in that case, I think showing it as a PHP array is probably the right call.

#

Because you can throw that into a call like this: directory('/src', $source, ...$dirOpts)

#

And it would be treated as identical to directory('src/', $source, exclude: ['*.md*'])

obsidian forge
#

yup, exactly

#

it's much neater in a language that has features (i guess the closest parallel here for you is actually python)

#

since it has the *args and **kwargs spread operators

iron sandal
#

Does anyone have a working php example template for container or helm chart builds?

lusty grove
#

How does one work with state / getters with the php sdk? I can add the snippet here if someone points me in the right direction πŸ™‚ https://docs.dagger.io/api/state?sdk=java

Object state can be exposed as a Dagger Function, without having to create a getter function explicitly. Depending on the language used, this state is exposed using struct fields (Go), object attributes (Python) or object properties (TypeScript).

inner walrus
# lusty grove How does one work with state / getters with the php sdk? I can add the snippet h...
<?php

declare(strict_types=1);

namespace DaggerModule;

use Dagger\Attribute\DaggerFunction;
use Dagger\Attribute\DaggerObject;
use Dagger\Attribute\Doc;

#[DaggerObject]
#[Doc('A module that provides greeting functionality')]
class MyModule
{
    /**
     * @var string
     */
    #[DaggerFunction]
    #[Doc('The greeting to use')]
    private string $greeting;

    /**
     * @var string
     */
    #[Doc('Who to greet')]
    private string $name;

    /**
     * Constructor for MyModule
     *
     * @param string $greeting The greeting to use
     * @param string $name Who to greet
     */
    public function __construct(string $greeting = 'Hello', string $name = 'World')
    {
        $this->greeting = $greeting;
        $this->name = $name;
    }

    #[DaggerFunction]
    #[Doc('Return the greeting message')]
    public function message(): string
    {
        return "{$this->greeting}, {$this->name}!";
    }
}

I see what you mean. I couldn't get a getter by decorating with

    #[DaggerFunction]
    #[Doc('The greeting to use')]
    private string $greeting;

nor did public work vs private.

lusty grove
#

Yeah I tried a bunch of different things and dug around in the sdk code and I think it's not supported. I left the getter getSource in the php snippet in my PR to account for that

#

It seemed like we need a Dagger\Attribute\DaggerField to be consistent with the other SDKs. I can open an issue. If I'm missing some current way to do this I'll close it πŸ™‚

serene light
#

@lusty grove @inner walrus Apologies, they have not been implemented yet.
cc @summer sequoia @green otter

It seemed like we need a Dagger\Attribute\DaggerField to be consistent with the other SDKs. I can open an issue.

For the PHP SDK, functions are only exposed if they are annotated with Dagger\Attribute\DaggerFunction and they have public visibility.
My inclination is to do the same for public properties.

My reasoning can be explained with this class:

class MyModule
{
    #[DaggerField]
    public string $greeting;

    #[DaggerFunction]
    public function greeting(): string
    {
        return "{$this->greeting}, Dagger!";
    }
}

This is allowed in PHP, but to Dagger... we would expose two identically named functions. Best case scenario: it prints a meaningful error.
I suspect this will confuse users as they would seem like separate things.

My hope is, by reusing DaggerFunction , like typescript does the overlap will be clearer.

class MyModule
{
    #[DaggerFunction]
    public string $greeting;

    #[DaggerFunction]
    public function greeting(): string
    {
        return "{$this->greeting}, Dagger!";
    }
}

Obviously; open to discussion by anyone

Object state can be exposed as a Dagger Function, without having to create a getter function explicitly. Depending on the language used, this state is exposed using struct fields (Go), object attributes (Python) or object properties (TypeScript).

summer sequoia
#

you might be able to expose one of the fancy getter/setter functions that have been added to PHP recently; but the SDK doesn't currently support exposing fields directly

serene light
#

That would be a meaningful reason for us to upgrade to PHP 8.4

summer sequoia
#

mmm, couldn't remember if they were in 8.3 or 8.4

serene light
#

I forgot too, just checked. It's 8.4

PHP is a popular general-purpose scripting language that powers everything from your blog to the most popular websites in the world.

#

That said, I don't think PHP is treating those getters and setters as functions is it?
Are they not just hooks on accessing/setting the property?

#

i.e. This is still allowed

class MyModule
{
    public string $greeting {
        #[DaggerFunction]
        get {
            return $this->greeting;
        }
    }

    #[DaggerFunction]
    public function greeting(): string
    {
        return "{$this->greeting}, Dagger!";
    }
}

If this is allowed by PHP, then it would cause the same issue: Two identically named functions being exposed to Dagger

cobalt pelican
#

Yeah, I'd just return an error if there's a conflict.

serene light
#

In that case, keeping it simple I propose :

  • Stick with 8.2 (until a meaningful reason to upgrade presents itself)
  • Reuse DaggerFunction (to hint the overlap to users)
  • Only expose public properties (consistent with exposing functions)
  • Ensure a useful error is returned for naming conflicts.
cobalt pelican
#

Another issue with the getter is that the API won't call the PHP getter if there's additional logic there. It will return the value it has for the field directly.

#

Under the hood the engine creates a getter function for the field, without arguments, but it's executed inside the engine, not relayed to the SDK.

serene light
#

Ah, in other words the 8.4 property hooks would not work?

    public string $greeting {
        #[DaggerFunction]
        get {
            return $this->greeting . ", World!";
        }
    }

i.e. In the above case, if $greeting === "Hello" then Dagger will return "Hello"

cobalt pelican
#

The SDK can still support getter functions, but it's best to report them as a normal function, not as a field.

#

Fields are faster though, because they don't take the round trip to the SDK, so need to keep that in mind.

serene light
#

That's definitely food for thought.

For now, we don't support property hooks, so the simple approach above should suffice.

I won't be implementing it today, so there's still time to mull it over.

#

While you're around, @cobalt pelican

Is there a change log that would help SDK maintainers keep up to date with what features/changes should be implemented?

Currently, I only tend to find out when an issue arises or I happen to read part of the docs and go "Huh, I haven't added that to PHP yet"

cobalt pelican
serene light
cobalt pelican
#

Yeah, or just an #sdk-dev channel next to #engine-dev for things that touch all SDKs. We can mention for announcements. \cc @tropic whale

karmic tendon
#

Hey ! Long time since I played with dagger. I am trying to get back on it for a simple usecase. But I ran into a question. If you look here https://hub.docker.com/r/composer/composer you'll see that it would be best to add volumes for composer home / cache dir and so on. But locally these are defined through env variable. Is there any way to have something like #[DefaultPath('${COMPOSER_HOME:-$HOME/.config/composer}')] ? Maybe this is global to dagger and not PHP specifically ?

serene light
# karmic tendon Hey ! Long time since I played with dagger. I am trying to get back on it for a ...

Using environment variables in default paths would be global dagger functionality rather than PHP specifically.

I'm not sure it's possible, and I don't believe it will be. For security reasons: You can't provide paths outside of your dagger module

It is possible to assign a default path for a Directory or File argument in a Dagger Function. Dagger will automatically use this default path when no value is specified for the argument. The Directory or File loaded in this manner is not merely a string, but the actual filesystem state of the directory or file.

#

So I would presume that getting access to environment variables could be a security issue as well.

serene light
# karmic tendon Hey ! Long time since I played with dagger. I am trying to get back on it for a ...

That said, if caching is your concern; Dagger will cache calls with identical arguments, so if you separate your composer step enough, it will be cached.

For instance:

    private function getVendor(
        File $composerJson,
        File $composerLock
    ): Directory {
        return dag()
            ->container()
            ->from('composer/composer')
            ->withFile('/app/composer.json', $composerJson)
            ->withFile('/app/composer.lock', $composerLock)
            ->withWorkdir('/app')
            ->withExec(['composer', 'install'])
            ->directory('/app/vendor');
    }

Now you have a call to get your vendor/ directory which will be cached until you make any changes to your composer.json or composer.lock
You'll have to manually insert it into your app but the time saved on dagger calls is well worth it.

karmic tendon
#

ok thanks. will check it out. but regarding caching (just tried on github action) and I thought the "load module" part would get cached or something. It takes 17s on my local machine and I think about the same time on github actions...

serene light
#

Ah, hmm... I'm not sure about that initial step. I expect someone from the core Dagger team would be better suited to answer that question.

#

cc @obsidian forge @cobalt pelican Do you have any insight on Adrien's problem? πŸ™

regarding caching (just tried on github action) and I thought the "load module" part would get cached or something. It takes 17s on my local machine and I think about the same time on github actions...

cobalt pelican
# serene light cc <@488718750690967563> <@768585883120173076> Do you have any insight on Adrien...

You guys need to benchmark loading a simple PHP module (without a git repo). The SDK module can perhaps be better optimized. We have a workflow that runs periodically for the 3 official SDKS: https://github.com/dagger/dagger/blob/e79b3347c89d614f9eb6677d29aa0b3cffbbc955/.github/workflows/benchmark.yml#L20-L56

If it's looking good on that end it could be that @karmic tendon is uploading more context than intended (think docker build context). Similarly to #1379046207527325746 message, try running this (assuming running from the directory where your module is):

dagger -M -c '.core | module-source . | context-directory | glob "**"'

If you see the vendor directory this could be slowing you down but I'd expect a second dagger functions would be much faster (i.e., cached). This is something the PHP SDK maintainers can try as well, and add anything that shouldn't be there in dagger.json exclude.

GitHub

An open-source runtime for composable workflows. Great for AI agents and CI/CD. - dagger/dagger

cobalt pelican
karmic tendon
#

the command shows .dagger/vendor directory

#

and .dagger/sdk

cobalt pelican
#

Don't include .dagger, assuming you have "source": ".dagger" in your dagger.json. Paths are relative to your source directory.

karmic tendon
serene light
#

As Helder said, there are probably some optimizations that we could make in the PHP SDK so it is probably slower than the official SDKs

karmic tendon
#

πŸ‘ I understand. regarding defaults. I understand defaults. Just not how to get env variables. I know that it is something that can be any input and the user provide it as an option but I wanted to make it default to not have to provide the values each time. Also I wonder how cache is handled in github action. because one of the promise of dagger was layer caching at every step but if github actions don't persist said cache then I don't see the point... And it just takes longer to run things (by far)

cobalt pelican
#

Github actions caching

karmic tendon
#

modified and ran dagger develop before the dagger call. It still takes around the same time

cobalt pelican
karmic tendon
#

same thing as before :/

cobalt pelican
#

So vendor and sdk weren't excluded?

karmic tendon
#

wait... when I update to exclude and run dagger develop it seems to rollback the changes

cobalt pelican
#

That's strange. Would need to know more, but please make sure. dagger develop shouldn't remove your manually added "exclude" field. Have you fully saved your changes before running that command?

karmic tendon
#
{
  "name": "GotenbergBundle",
  "engineVersion": "v0.18.9",
  "sdk": {
    "source": "php"
  },
  "exclude": [
    ".venv",
    "sdk"
  ],
  "source": ".dagger"
}
#

yes I have this and it is saved

#

when I run dagger develop. after ~15s it rollbacks my changes back to the include

#
{
  "name": "GotenbergBundle",
  "engineVersion": "v0.18.9",
  "sdk": {
    "source": "php"
  },
  "include": [
    "!.venv",
    "!sdk"
  ],
  "source": ".dagger"
}
cobalt pelican
#

What's your dagger version?

karmic tendon
#
$ dagger version
dagger v0.18.9 (docker-image://registry.dagger.io/engine:v0.18.9) darwin/arm64
cobalt pelican
#

Hang on

#

Oh, wow, I can reproduce it. That shouldn't happen! Do you mind creating a bug report in GitHub?

karmic tendon
#

sure. where ?

#

?

cobalt pelican
obsidian forge
#

that's good yup πŸ™‚

cobalt pelican
#

Same happens in Go. I wonder if it's because of some latest changes for client generation.

karmic tendon
cobalt pelican
#

Oh wait, I sort of remember @worthy ice wanting to no longer do two include + exclude. Maybe it should always be include from now on and the engine is normalizing.

karmic tendon
#

even though it doesn't explain why sdk and vendor are in the context

serene light
#

Modules can be configured by editing their dagger.json file. The configuration in there contains all module metadata - from the name of the module and the SDK it uses, to the dependencies it requires. An initial configuration is automatically generated when using dagger init or dagger develop for the first time, and is kept up-to-date with dagge...

#

If the "context" is in the middle of your calls

cobalt pelican
karmic tendon
#

if so that would be weird since all of this is freshly auto generated with dagger init

cobalt pelican
#

The "include" isn't auto generated on init. Didn't you add it manually?

karmic tendon
#

nope it was automatic

cobalt pelican
#

If you do dagger init --sdk=php new-module are you saying there's an include in dagger.json?

karmic tendon
#

I just ran dagger init --sdk=php but yes

cobalt pelican
#

Did you run that on an empty dir?

karmic tendon
#

nope. I ran it at root of my library

#

ok modifying the include with .dagger/ and adding .dagger/vendor did improve things a bit. We are now at 8s instead of 17

cobalt pelican
#

I don't think that's doing what you think. Didn't it add a .dagger to the root of your library? Just add a new directory as in:

dagger init --sdk=php new-module
karmic tendon
#

yes it added a .dagger with everything I need in it

#

new-module was not needed

cobalt pelican
#

The new-module was to ensure it created the new module in a new empty dir. If you run dagger init on a dir with existing files it's doing something slightly different.

#

It doesn't add include on dagger init:

❯ cd $(mktemp -d)
❯ dagger init --sdk=php my-module
❯ cat my-module/dagger.json
{
  "name": "my-module",
  "engineVersion": "v0.18.9",
  "sdk": {
    "source": "php"
  }
}
karmic tendon
#

tried it with plop and indeed the dagger.json is lighter

#

but then the dagger.json is not at the root

#

so any dagger call something must be done withing the plop` folder

cobalt pelican
karmic tendon
#

AND you still have the vendor and sdk issue

#

yeah I understand. it does if you do not execute this on an empty dir

cobalt pelican
karmic tendon
#

weird it didn't to me either this time... But I'm sure I didn't touched this file... so which command add includes like this ?

cobalt pelican
karmic tendon
#

I just ran dagger develop and dagger call commands

#

maybe... sorry I can't remember

#

either way thanks to your help we reduced a bit the "load" time.

cobalt pelican
serene light
cobalt pelican
summer sequoia
karmic tendon
#

thank. will have a close look πŸ™‚

karmic tendon
#

I think I spotted an issue with ReturnsAsList attribute and wanted to contribute. But the install with docker compose up -d fails with "./hack/dev": stat ./hack/dev: no such file or directory: unknown does that ring a bell ?

serene light
#

I think you just use dagger to build dagger

obsidian forge
#

mmm yeah the docker-compose file might need to be removed actually

#

i had no idea it existed, that's definitely not the intended way to get a dev setup

#

to build the engine, you want to just run ./hack/dev

karmic tendon
#

ok so I have to fork dagger/dagger instead of dagger-php-sdk ?

obsidian forge
#

oh yeah!

#

see the description on the repo

karmic tendon
#

OH missed it on the About section. usually it is in readme or maybe UI changed in github. didn't noticed. thanks.

#

so I forked and ran the hack/dev now if I make changes to the PHP sdk. waht is the procedure ?

  • in dagger.json/source I must point toward myforked-dagger/sdk/php

but do I need to run hack/dev at every change ?

#

I am trying

  "sdk": {
    "source": "../dagger/sdk/php"
  },

and running dagger develop but it doesn't work

#

I didn't find any documentation on how to set everything up locally for contribution

#

The "../dagger/sdk/php" SDK does not exist.

serene light
#

There is probably a more streamlined way, but when I want to test it with a module I push it to git and label the source as my branch

#

So it ends up being "source": "github.com/<my-username>/dagger/sdk/php@<my-branch>"

#

Or something like that. cc @obsidian forge any better methods?

obsidian forge
#

you can set source to a local path

obsidian forge
#

the path is relative to your dagger.json for the module

karmic tendon
#

dagger.json is at the root of my project. the project and the fork are siblings. I use "source": "../dagger/sdk/php" so it should be good ?

#

but it does'nt :/

serene light
#

Hold on.

#

It might need to be ../dagger/sdk/php/runtime

#

mm.. maybe? It's been a while.

karmic tendon
#

nope :/

serene light
#

Yeah ignore me. I'm looking at it now. the dagger.json file is in sdk/php

#

and that points to runtime, so it should be fine.

#

Are you seeing this error?

Error: failed to get local context directory path: input: moduleSource failed to load sdk for local module source: local module dep source path "../dagger/sdk/php" escapes context
#

This is what I get if I try what you're doing

#

It seems to me, that a local path in a different directory is not allowed for security purposes

karmic tendon
#

failed to load sdk for local module source: local module dep source path "../dagger/sdk/php/runtime" escapes context "/xxx/xxxx/xxxx/GotenbergBundle": unknown builtin sdk

serene light
#

Yeah so, it is telling you it escapes context. Which, for security, dagger can only accept paths that are at the same level or lower in the file system.

#

So if dagger.json is not right next to the directory you're accessing, it can't access it.

#

Going up a directory is not allowed in this instance

#

This works:

{
    "name": "scratch",
    "engineVersion": "v0.18.9",
    "sdk": {
        "source": "dagger/sdk/php"
    },
    "source": "scratch"
}
#

Where my file structure looks like this:

  drwxrwxr-x 37 4.0K May 28 15:50 dagger/
  -rw-r--r--  1  124 Jun 12 14:38 dagger.json
  drwxr-xr-x  5 4.0K Jun 12 14:38 scratch/
karmic tendon
#

ok

#

so symlink might do the trick

serene light
#

You can give it a go, I've not tried that but it might work

karmic tendon
#

yup it seems to be working (no errors for the moment)

#

still : If I change something on the SDK shoud I run dagger develop each time ?

serene light
#

I think so, yes for changes to the SDK you will need to.

karmic tendon
#

ok thank you

serene light
#

No problem, thank you for wanting to contribute πŸ˜ƒ

karmic tendon
serene light
#

I may be mistaken, or outdated knowledge. But I believe the real issue is that dagger has no defined way to display nested arrays in stdout

#

@obsidian forge Does this sound correct?

karmic tendon
#

I understand. but then why ReturnsListOfTypes accept a ListOfType ?

serene light
#

Hold on, I'll have a look at it and refresh myself

karmic tendon
#

no worries. I'm done for the day πŸ˜‰ Let me know if I need to change something I'll be happy to help

obsidian forge
#

you're right though, it didn't used to

serene light
serene light
#

no worries. I'm done for the day πŸ˜‰ Let

serene light
#

i.e. [Int]: --my-array=1,2,3 [[Int]]: ???

obsidian forge
#

I don't think it's supported on the cli, you're right

#

cc @cobalt pelican

#

but it's still possible to do so from other code or using a raw graphql query

#

so the sdks should ideally still support it

serene light
#

Yeah. I think it may be supported already. I was just curious what shiny new toys we had 🀩

karmic tendon
#

why not multiple --arg ? like --keyword=plop --keyword=plip ?

serene light
karmic tendon
#

--keyword-level0-level1=value ?

serene light
#

It could work, but it's a bit messy and probably a lot more work than it's worth.

We can still pass nested arrays between functions, just not over CLI.

cobalt pelican
#

That could be supported but in shell, probably never in dagger call.

green otter
#

Hello everyone

karmic tendon
#

Hi everyone.

I am pleased to say I submitted a talk to SymfonyCon about dagger (PHP SDK).
Based on @green otter 's last year at Vienna, mine will be focused on a real-world use case using https://github.com/sensiolabs/GotenbergBundle/pull/168 .
I don't know yet if I'll be selected but I'd like for people in this channel to review the PR if possible and point out best practices regarding dagger. For things like performances / caches and DX.

Thank you in advance ! πŸ™‚

GitHub

Q
A

Gotenberg API version ?
8.x

Bug fix ?
no

New feature ?
yes

BC break ?
yes
…

serene light
karmic tendon
serene light
pulsar nest
#

Hi all ! I'm curious what you guys are using dagger for with PHP, I saw some cool examples in the introduction for the community SDK, but wondering if there's been any cool/unique/helpful ways to use it πŸ™‚

#

and on the off chance someone is using phalcon...

karmic tendon
# serene light I put in a few suggestions in a review πŸ™‚

did the changes. Still bothered by the $result = [] which I find is not very friendly DX wise and waits for everything to finish (the whole matrix) before rendering anything.

Wouldn't there be a way to :

  1. do the foreach loop in parallell
  2. output as it goes ?
karmic tendon
serene light
#

Running a CI Matrix in parallel

serene light
obsidian forge
#

yes!

#

ahaha sorry i so forgot to tell you about this

#

so. we shipped it, and also finally seem to have ironed out all the bugs that we shipped alongside it πŸ˜„

serene light
#

Nice! πŸ˜„
I'll have to look at what I'd done before, but i'm looking forward to adding that in πŸ™‚

obsidian forge
#

lemme know if you hit anything - also happy to jump on a quick call or something if you want to chat through what would need doing

serene light
#

Brilliant will do πŸ™

obsidian forge
serene light
obsidian forge
#

wooo πŸŽ‰ thanks ❀️

#

just merged the fix πŸ˜„

serene light
#

Thank you πŸ™‚ πŸŽ‰

#

@obsidian forge Are there common conventions for errors btw?

serene light
karmic tendon
#

hi all. FYI thanks to @serene light review we finally merged and migrated officially to dagger on our Symfony Bundle : https://github.com/sensiolabs/GotenbergBundle/pull/168 . Now trying to add pie to the native dagger sdk php image so we can easily add new extensions without being too much restricted. Also I wondered... because sdk are simple strings ATM. like php. Wouldn't it make sens to have something like php:8.3 with php being equivalent to php:latest for example ? WDYT ? Should I open an issue on dagger itself to talk about this ?

GitHub

Q
A

Gotenberg API version ?
8.x

Bug fix ?
no

New feature ?
yes

BC break ?
yes
…

serene light
# karmic tendon hi all. FYI thanks to <@1229425915675807797> review we finally merged and migrat...

The "php" string is actually just an alias for the github url that points to the the dagger php sdk. So I think changing that string isn't much of an option.

If we supported multiple versions I think it would have to be done with a new keyword. I believe Typescript did something similar to pick which package manager you wanted to use.

That's a big if though, because I suspect it would be a large task and a heavy maintenance burden as I don't believe any other SDK allows different language versions, not even the SDKs maintained by the core team.

cc @obsidian forge am I right about this?

karmic tendon
#

But I think it would make totally sense. Because ATM dagger is relatively new so it is ok. But whenever a change like the PHP runtime version is done, there is a big risk that CIs will break. Thus not complying with the promise by design. WDYT ?

serene light
#

For the end-user, if they get CI working using Dagger version 0.18.4, which uses PHP 8.2. They can stay on version 0.18.4 forever if they want and it will not break, it will use PHP8.2 forever.

If we then upgrade the SDK to PHP 8.4, it would only affect new versions of Dagger.

#

So I don't think it breaks any promises in that regard.

It works similarly to other tools like PHPUnit or PHPStan, where later versions sometimes require later versions of PHP.

If we were to upgrade PHP to a version that introduced BC breaks, I would recommend we try and time the change with the next minor version (since there is no major version yet, this would be acceptable use of sem ver)

#

I'm not against the idea. I think if we could, it would be very cool to support multiple PHP versions. I'm just saying it's probably quite a big task

obsidian forge
#

you can add php@dagger-tag in dagger.json to select a specific version of the dagger sdk

#

for supporting multiple versions of php, that would be neat? both typescript and python support this

#

they read from the package.json or pyproject.toml

serene light
#

Oh they do? Interesting, does it add much maintenance?

obsidian forge
#

we don't bother for go, since go's backwards compatbility essentially guarantees to never break anything (and this mostly holds)

obsidian forge
karmic tendon
obsidian forge
#

yeah, each module would need to specify the version it wants

#

overriding globally is a big no

serene light
#

Wouldn't each module just be going through dagger anyway? And just use the appropriate version of the engine? (not rhetorical, genuinely curious)

obsidian forge
#

so the way that ts/python work is that they read the module's package.json or whatever. then the sdk uses that python:version image to actually execute the runtime

#

everything still goes through the engine

#

but overriding globally (except for updating the default), is kinda tricky because a module might require a specific version for some reason

serene light
#

But what I mean is, if you have some old module using a php:8.2 image, then in the distant future use a module with a php:9.0 image... that should still work shouldn't it?

#

Even using both modules in tandem

obsidian forge
#

yeah, they would both have separate Runtimes (as defined in the SDK)

serene light
#

I thought as much, since I can use a Go module inside a PHP module, it seemed natural that I could use an old PHP module inside a new PHP module

serene light
#

On an absolutely, completely superficial and utterly pointless, yet entirely desired, note... any chance PHP can get it's own arbitrarily coloured circle to the left of our names like other languages? πŸ˜› (perhaps a nice blue? https://www.elephpant.com/)

shy goblet
serene light
shy goblet
#

I think @pine bridge did it already for java

serene light
#

Ah, that would probably be much simpler, thank you!

#

Especially since the image is currently decided by the underlying Go module

shy goblet
#

Check the java SDK, I think there's an extra config somewhere

pine bridge
karmic tendon
#

thanks I'll take a look. So it would be a per module configuration ? If a module B is required by project A then to each their own images right ?

serene light
#

Yeah, each module would specify their image separately via their dagger.json

#

@pine bridge Does the Java SDK get affected by picking a different image?

To be clear, my concern is this:
Lets say you use new features of the Java language, then someone uses an old image, would this break the SDK?

#

Basically, are you limited to versions that don't break compatibility with the SDK's code?

#

I'm just trying to wrap my head around it

pine bridge
# serene light <@809456513298464798> Does the Java SDK get affected by picking a different imag...

The Java SDK is providing some configuration in the dagger.json but not the java image used.
If I had to, that's where I would put it.
But yes, once you do that, you start to deal with compatibility issues.
Maybe it could be possible to check some of the components? For instance to quickly instanciate a container from the image and check things like php version (or any other component) and if that doesn't match requirements fail with an error message?
That way you can allow users to pick the image they want but guarantee it works.
(I haven't followed the whole discussion so maybe that doesn't match your needs, just thinking out loud)

karmic tendon
#

Lots of things to think about ... To sum up :

  • I am trying to add PHP/pie to the container so it installs PHP extensions on the fly.
  • How do we ensure forward compatibility with newer modules / PHP versions

The global answer is that we could provide some configuration through the dagger.json for both some extensions / images and ensure everything is coherent with checking the composer.json file.

serene light
# karmic tendon Lots of things to think about ... To sum up : * I am trying to add PHP/pie to th...

How do we ensure forward compatibility with newer modules / PHP versions

I think this point is already covered by Dagger's language agnostic feature, we can already use completely different languages from other modules, so using a slightly older/newer PHP is a non-issue.
The only time forward compatibility breaks is if a new version of Dagger introduced BC breaks. Which would happen no matter what the PHP SDK does.

serene light
serene light
# karmic tendon Lots of things to think about ... To sum up : * I am trying to add PHP/pie to th...

I am trying to add PHP/pie to the container so it installs PHP extensions on the fly.

I think if php/pie were introduced it would be best to just stick to composer.json since that's the advantage of it.

If we were writing it in the dagger.json we might as well use PECL, which is more mature.

PIE has not officially replaced PECL (yet) and looking at the supported libraries: PIE's <70 extensions vs. PECL's 436 I would be hesitant to introduce PIE as a core part of the SDK.

#

As an "opt-in" feature, it would be cool and future-proof us for when PIE does take over

#

But I don't think it would make sense as the default; end-users shouldn't need to know why some of their extensions installed and the rest didn't.

#

So a "withPie": true should have to be explicitly set by the user in their dagger.json, where the default is false.

That way, only users who know exactly what they're signing up for would use it.

Then, when PIE does fully replace PECL, we could set the default to true

karmic tendon
#

Yes. What I had in mind. Trying to push pie forward but cannot solely rely on it at the moment

serene light
#

I agree, having it all in composer.json would really neaten things up.
And end-users getting all their extensions in for free ☺️ now that would be some nice UX

summer sequoia
#

I'm not really sure on what the value is of being able to install extensions or specify a PHP version for dagger modules? You are mostly writing code to orchestrate containers; if you need a specific version you can just build a container with that version, the extensions you need and run your build step inside that container.

karmic tendon
#

For example I tried to install pcntl to use the forking process trick to try parallel building. Not available. Seems overkill to do dagger in dagger

summer sequoia
#

I do think that we need to handle parallelism better; perhaps the base image could include the pcntl extension, but if we were to do that I'd want to have some examples of how to make it work properly in the docs, cause I'm sure there will be good ways and bad ways to do it

summer sequoia
serene light
#

I assume we'd have to dig into the client code a bit more for that one?

zealous venture
#

In the other sdks, Container.sync() returns a Container. In the PHP SDK, it returns a ContainerId.
Can you help me correct the function below? It fails because of this type mismatch

#[DaggerObject]
class MyModule
{
    #[DaggerFunction]
    public function copyDirectoryWithExclusions(
        // source directory
        #[Ignore('*', '!**/*.md')]
        Directory $source,
    ): Container {
        return dag()
            ->container()
            ->from('alpine:latest')
            ->withDirectory('/src', $source)
            ->sync();
    }
}
#

guessing the solution is to not call sync() but checking

zealous venture
#

is it mandatory for dagger functions in php to have a return type? if so, what should it be for this function?

    #[DaggerFunction]
    public function copyFile(
        // source file
        File $source
    ) {
        $source->export('foo.txt');
        // your custom logic here
        // for example, read and print the file in the Dagger Engine container
        echo file_get_contents('foo.txt');
    }

[ERROR] DaggerFunction "copyFile" cannot be supported without a return type  
serene light
serene light
zealous venture
#

I noted that when you run the Go function, for example, although it doesn't have a return type specified, it works and returns Void. That's different from PHP, where the function doesn't run unless the return type is explicitly specified

#

Go function run:


$ dagger call copy-file --source=./go.sum
β–Ά connect 0.5s
β–Ά load module: . 7.8s
● parsing command line arguments 0.1s

● myModule: MyModule! 0.0s
β–Ά .copyFile(
  ┆ source: Host.file(path: "/home/admin/sandbox/go/go.sum"): File!
  ): Void 0.7s
serene light
serene light
# cobalt pelican Yeah, that's worth doing.

I will look into it. It SHOULD be fairly simple, but I'd have to be certain it prints out an incredibly clear error for users that try to return something without a return type

cobalt pelican
serene light
#

Yes of course, I believe it already does so. I just need to check that the same logic applies if Void

karmic tendon
#

Hello everyone. So... I am trying to implement what we talked about , Add a "config" key to allow :

  • changing php version
  • adding pecl modules
  • and (maybe) start with pie as well...

To do so, I checked how it was impleemnted in Java and saw that I needed to add a WithConfig method and stuff like this. But now that I want to test it. dagger develop doesn't seem to be enough. So I am trying the ./hack/dev but it fails horribly with the following message

β–Ό .loadToDocker(
β”‚ ┆ docker: Host.unixSocket(path: "/Users/neirda/.docker/run/docker.sock"): Socket!
β”‚ ┆ name: "localhost/dagger-engine.dev"
β”‚ ): DaggerEngineLoadedEngine! 9.7s ERROR
╰─▼ Container.withExec(args: ["/bin/busybox", "--install", "-s"]): Container! 0.3s ERROR
  ┃ /bin/busybox: /usr/lib/libc.so.6: version `GLIBC_2.42' not found (required by /bin/busybox)
  ! process "/bin/busybox --install -s" did not complete successfully: exit code: 1

which prevents me from going further. I am new to go so I don't know if it is related to go or something else (my local machine maybe) any ideas ?

To give a bit more input : my project has a symlink to the fork of dagger and updated the dagger.json like so :

  "sdk": {
    "source": "dagger/sdk/php",
    "config": {
      "phpVersion": "8.3"
    }
  },
#

ok nevermind... the hack dev is still failing but I need to run armagedon on my docker containers for it to work it seems πŸ™‚

radiant flume
#

@karmic tendon personally, when I want to test a dev version of the engine, I use this (using a regular stable install of dagger):

  • dagger -c 'dev | terminal' : build a complete engine + CLI, then open a terminal in the resulting environment. If I need to mount extra files or set env variables in the container, I can do that as well: dev | with-directory . ./my-test-files | with-env-variable OP_SERVICE_ACCOUNT foobar | terminal

  • To run all linters: dagger -c lint

  • To run the full test suite (which is huge..) dagger -c test | all

TLDR I personally don't use ./hack/dev but I am not a full-blown core engine developer, I contribute various PRs here and there. I know the core devs have a tighter dev loop and rely on ./hack more.

Anyway just my 2c!

karmic tendon
#

Hi @radiant flume . Thank you for your input. At the moment my symlink is very easy to work with but I was a bit confused with how things works so now it should be good. Although using goland from jetbrains I didn't get breakpoints which would be very useful but didn't took the time yet to understand how to set it up properly.

serene light
#

There's several bits:

  • The composer image and the PHP image being updated could be one PR and go in as soon as it's ready.

  • The bug fix is brilliant, thank you for spotting it. That can go in immediately as a separate PR.

  • I think installing extensions is trickier, and forgive me if I've forgotten but what user-facing problem are we trying to solve?

    • It would install extensions into the SDK image itself, not into the containers you create with it.
#

This might confuse users a lot, if we tell them they can install extensions automatically. They install pdo_sql, then they call dag()->container() and that container does not have pdo_sql

shy goblet
#

Hey guys, I'm working on a PR (https://github.com/dagger/dagger/pull/11052) to bump the engine dependency and one of the blocker is gqlgen, they changed the way we disable some validation rules that seems required to make the PHP SDK working well.

The latest gqlgen package automatically enables either ValuesOfCorrectTypeRule or ValuesOfCorrectTypeRuleWithoutSuggestions even if we disable them on our side (see https://github.com/99designs/gqlgen/blob/522517d5cd2356fae51f9945124d2a08eb2d795e/graphql/executor/executor.go#L246-L254)

I see that our CI is green so no tests fails after the changes but I'm wondering if maybe something not tested may broke, is there any tests that we could add to prevent a surprise if we merge it?

serene light
#

Magical world of enums: 🧡

faint current
#

hello php community, any reason to not allow/use php 8.4 on pipeline execution?

Container.withExec(args: ["composer", "update", "--with-all-dependencies", "--minimal-changes", "dagger/dagger"]): Container! 1.6s ERROR
Loading composer repositories with package information                                                                                                                                                                               
Updating dependencies                                                                                                                                                                                                                
Your requirements could not be resolved to an installable set of packages.                                                                                                                                                           
                                                                                                                                                                                                                                     
  Problem 1                                                                                                                                                                                                                          
    - Root composer.json requires php ^8.4 but your php version (8.3.9) does not satisfy that requirement.                                                                                                                           
! process "composer update --with-all-dependencies --minimal-changes dagger/dagger" did not complete successfully: exit code: 2

any way i can hook into it or do i need to wait for a release that allow is?

serene light
#

hello php community, any reason to not

karmic tendon
#

@serene light . Hi. Just woke up to this : https://github.com/Neirda24/GotenbergBundle/actions/runs/17992975791/job/51186788443 no worries it is nothing critical on my side... but I was wondering, are sha supposed to expire / get overwritten ? If so it makes (at least) the PHP runtime flaky at best don't you think ? Should we target a more specific version to avoid this ? Or set up a mirror somewhere ?

GitHub

Contribute to Neirda24/GotenbergBundle development by creating an account on GitHub.

karmic tendon
#

I am trying to regenerate the generated directory for PHP sdk. But I am having a hard time understanding how things work... there are two commands : dagger:codegen and ``dagger:schema codegenrequires theschemafirst. Butschemarequires two env variablesDAGGER_SESSION_PORT&DAGGER_SESSION_TOKENwhich should be set by dagger itself I guess... But then I am looking at where is thedagger:schemaexecuted ? Nowhere to be found in teh dagger repository. Neither in github workflows or in dagger itself... Am I missing something ? So I tried to add a newSchemagengo function asCodegen exists to try to output a file (schema.json) but it is still doesn;t work because there is a CliDownloader` in the PHP sdk which is deprecated that is trying to download the dagger cli... all of this is very confusing. Any guidance would be greatly appreciated ! I see several stuff I'd like to contribute / co-contribute :

  • Fix generated classes (order or arguments required / optionals)
  • Use / rework Dagger attributes to ease things a bit
  • See if I can optimize other part of the code
  • Fix a bad detection of windows / darwin (looking for string win first creates a mismatch darwin for windows)
serene light
#

Contributing

karmic tendon
#

someone already tried to use dagger with cypress (cypress GUI I mean) ?

serene light
karmic tendon
serene light
karmic tendon
#

thanks but this seems to be running headless without gui access :/

serene light
#

Ah, sorry, I'm unfamiliar with Cypress

karmic tendon
#

no worries

serene light
#

Someone may have tried it, when you say X11 are we talking about the windowing system?

karmic tendon
#

yup

serene light
#

I'm not sure if anyone has to be honest, I could be wrong. I typically only hover in the PHP channel

#

cc @obsidian forge

in general are there known example of how to forward X11 or similar using dagger ?

serene light
#

holy heck

#

that was instant

obsidian forge
#

it's likely going to look similar to how you do it in docker

#

so starting a x11 session, and grabbing the x11 socket

karmic tendon
#

but there is an siolation layer added with dagger right ?

#

won't that be an issue you think ?

obsidian forge
#

it would be similar to what happens when you run them in docker

#

i think x11 maybe needs --privileged? we have a flag to AsService that does the same thing

#

essentially, what you'll want to do is pass the x11 unix socket as an input to a dagger function, then you can attach it using WithUnixSocket, and run operations against it using WithExec or AsService

karmic tendon
#

is

    #[DaggerFunction]
    public function cypress(
        #[DefaultPath('.')]
        Directory $source,
        #[DefaultPath('/tmp/.X11-unix')]
        File $x11Socket,
        string $display = ':0'
    ): Cypress {
``` the right approach ? Becaus ethe socket is just a file right ? Or should I use the Socket object from dagger ? never tried it before
obsidian forge
#

you need a dagger.Socket type

#

not a File

karmic tendon
#

ok. Trying it...

#

cannot set default path for Socket trying something else

serene light
#

I assume that was the DefaultPath attribute, which only works for File and Directory

karmic tendon
#

yes

serene light
#

I think you'll have to pass the socket in manually

karmic tendon
#

Yes. Might be worth to allow that Attribute on Socket as well to ease DX

#

Or create a DefaultSocket because it can be somethign else than a file I guess

#
 [ERROR] failed to evaluate container: InvalidArgument: InvalidArgument: rpc      error: code = InvalidArgument desc = not a socket: /tmp/.X11-unix

so not it apparently (macos)

#

trying with /X0

#

seems good so far. Having errors later down but not related to x11 at the moment...

serene light
#

Default paths on Sockets

karmic tendon
#

so I managwed to make it work but clearly it is not stable and require too much work before calling dagger for it to be DX-friendly... :/ too bad

radiant flume
#

Hello PHP SDK devs πŸ‘‹ I'm refactoring codegen in our CI, and wondering if Generate() in .dagger/sdk_php.go is expected to include sdk/php/vendor, or if it's safe to exclude that?

#

We have a fancy new UI for code generation workflows - if your function returns the new Changeset type, the CLI will interactively show you the diff and prompt you to apply it. Sadly, with an included php/vendor directory that experience instantly becomes horrendous

#

cc <@&946480760016207902> πŸ‘†

sudden shuttle
radiant flume
#

Because that should be unrelated to modules

sudden shuttle
#

so it seems to me it's safe not to export that folder from the Generate function

serene light
#

@radiant flume Marcos beat me to it but yes, that is most likely a bug and should be removed. Thank you for catching it πŸ™‚

karmic tendon
#

not sure if I'm relevant. but the export of the vendor directory seems to be to improve DX so we don't have to. otherwise it would require to run both dagger develop & compsoer install to make it work. But to run compsoer install we need the export of the generated parts and to generate those parts we need the composer install. am I right ?

karmic tendon
#

BTW I'm happy to share that I will be speaking about dagger and PHP at symfonycon this year ! following @green otter last year at vienna

#

I will work on my conference and then that would be great if some of you could help me review it to make sure I'm not saying anything completely wrong πŸ™‚

serene light
green otter
#

@karmic tendon post on #general to announce. Also twitter and LI. Same post. Tag Dagger and me and stuff

serene light
radiant flume
#

The change I'm making affects the generation of the php client library in the core repo. Whenever the engine API schema changes, this has to be done for all SDKs, and the output checked into git.

I am changing the generate function so that it only returns the generated client library (and php reference docs), and not the vendor directory

serene light
radiant flume
#

No

#

Well except that the PHP runtime imports the Go client

#

So if your dev version of the PHP runtime requires a new feature in the dev version of the engine, you'll need to dagger call sdk go generate (or just dagger call generate) so that the PHP runtime builds

#

but that's unrelated to sdk/php/vendor

serene light
#

If that's correct, then it should be fine to ignore vendor, especially in diffs

radiant flume
#

Yes that particular generate function is purely for sdk & engine maintainers, to re-generate official client libraries for the different SDKs. Never called by the end user

serene light
#

Sounds fine then, worst case scenario it affects maintainers on dev and we revert it

karmic tendon
#

hey everyone. How can I access the host container image using the PHP SDK ? because dag()-> doesn't have host anymore and the auto resolution of typing Container but passing a local image doesn't work (trying to pull from docker.io)

serene light
#

It seems like the host() function should still be there. Did it disappear on the latest tagged release?

(I can confirm it is missing for me as well, using a v0.19.6 module)

pine bridge
serene light
pine bridge
serene light
#

Right, okay so it's accessible through custom applications, interesting. Thank you. I think that resolves my confusion. Thank you @pine bridge

pine bridge
# serene light Right, okay so it's accessible through custom applications, interesting. Thank y...

no problem, it's not always obvious πŸ™‚ This is a point not always easy, how to allow easy interactions with the host and at the same time security.
One thing for instance on this area as we don't have access to the host, is the ChangeSet object. At any level we can create one, but it will only be the top level (the CLI roughly) that will apply it on the host. So dependencies can expose their need to create files for instance, but the modules themselves will not have access to the host to do it, only the client will do.

karmic tendon
#

Okay but then I think there are a couple of things that dagger could benefit from. Because I am tryiong to migrate to dagger after I've been playing with it for quite soem time now. But :

  • This is a project with multiple tests types (phpunit, cypress, phpstan, etc etc)
  • a Big Dockerfile for php : the "base" image + extra stage for debug / local or for CI, or for production and also a stage for building assets.
  • locally and on CI we have a traefik to replicate the same environement as production with host going through traefik, cuystom certificates for CI
  • 1 compose for local, 1 compose for building, 1 compose for cypress tests

all in all it is quite heavy to migrate. So I'd like to migrate step by step and starting with the biggest pain point : cypress tests. So I am trying to migrate only the cypress compsoe file. But to do so :

  • I need the docker socket for traefik (No worries I managed but I think a DefaultSocket would be a nice addition for DX)
  • I need built images from the build compose file ==> This is an issue because There is no easy way to do this at the moment. I am exploring the idea of create a new contaienr based on docker:cli with the socket mounted, docker save to a tarball and then trying to import from dag()->container()->import()
  • Even migrating the build to dagger is not easy because Yes it provides a Directory::dockerBuild method but this does not comply with all docker features : extra context for example

That's about it at the moment πŸ˜…

serene light
#

@karmic tendon I forwarded your message to #daggernauts. Not that it can't be discussed here, the feedback is absolutely welcome. 😸

But I suspect the Dagger team's expertise might be able to alleviate some of your problems and if not, it's the right channel to discuss proposals which could alleviate your problems in the future.

pine bridge
karmic tendon
#

thank you both. And I'm happy to try to contribute more to dagger. (I'm giving a talk next week at SymfonyCon about it and my slides are still nto ready 😬

karmic tendon
#

hey all. Is there a way yet to configure function caching with php sdk ? Thanks / because of this. Directories as input are considered part of the cache key. Is there a way to automatically filter something like this

        #[DefaultPath('.')]
        Directory $source,

to ignore things based on the .gitignore / .dockerignore / something else ? For example we could use dagger to generate files that are ignored (code coverage) by git without having side effect on the cache key.

#

the next step could be to create a phpunit object that exposes several functions such as getCoverage, displayResult etc etc and cache won't be impacted so everything should run very fast without having to redo everything ?

#

because AFAIK there isn't a way yet to both output somehting to user and export a directory / changeset. Am I right ?

serene light
# karmic tendon hey all. Is there a way yet to configure function caching with php sdk ? Thanks ...

You can manually ignore things like so:

#[DefaultPath('.')]
#[Ignore(
    '.phpunit.cache',
    'vendor/',
)]
Directory $source,

You can also manually ignore things from the module itself, using dagger.json.

I do recall automatic ignores based on .gitignore being a frequently sought after feature. Here's the first example I found searching for it:
https://github.com/dagger/dagger/issues/11317

GitHub

Dagger can natively load .gitignore and apply its rules to filter host directories pre-upload. This feature is disabled by default, and can be enabled as an argument to Host.directory(). But, it ca...

serene light
# karmic tendon the next step could be to create a phpunit object that exposes several functions...

This can be done to take advantage of the cache, as long as the cache continues to exist between calls. i.e. Your mileage may vary between CI pipelines.

You can do something like this:

    #[DaggerFunction, Doc('Generate PHPUnit report')]
    public function test(): TestReport
    {
        return new TestReport($this->container->withExec(
            args: ['vendor/bin/phpunit', '--log-junit=cov.xml'],
            expect: ReturnType::ANY,
        ));
    }

And now you have a TestReport object which has a container with everything you need:

  • $this->container->stdout(),
  • $this->container->stderr(),
  • $this->container->exitCode(),
  • $this->container->file('cov.xml')

And every step to create the TestReport will be cached.

#

The most awkward part, I will admit is getting the exit code and stdout/stderr at the same time nicely printed.

This is a bit hacky, as I'm abusing internal SDK knowledge for this one:

    #[DaggerFunction('Return test report')]
    public function report(): string
    {
        $exitCode = $this->container->exitCode();
        $stdout = $this->container->stdout();
        $stderr = $this->container->stderr();

        if ($exitCode !== 0) {
            throw new QueryError(['errors' => [[
                'message' => '',
                'extensions' => [
                    'exitCode' => $exitCode,
                    'stdout' => $stdout,
                    'stderr' => $stderr,
                ]]]]);
        }

        return $stdout;
    }

You can throw any exception you want and your CI will fail, but that QueryError is the exception thrown by the GraphQL library we depend on. So if it fails, it will fail just like it would if you had only just called phpunit and received a non-zero exit code.

#

You might also just be able to do something clever with a withExec call and echo the stdout then exit 1 but I haven't tried that.

karmic tendon
#

hey. thanks. exactly my point. it is a bit hacky and DX not very great. It is very common in jobs (in pipelines) to have both outputs (plural) and a single exit code and some artifacts (plural).

serene light
#

I want to add some custom exceptions similar to the Python SDK. It has some base exceptions so you know it came from that library

#

I understand your point, it would be very convenient to get all of it in one call.

My knowledge may be outdated, but I believe that is a current limitation. You can still make several dagger calls within the same step on CI and then fetch everything from it. But as you say, it's a bit awkward.

PS: To be clear, this is a current limitation of Dagger in general, not specifically the PHP SDK.

karmic tendon
#

indeed πŸ‘

serene light
#

Checking the Github issues I've found this one by Dagger's core maintainers: https://github.com/dagger/dagger/issues/8421

It's a known limitation and there is work going towards it, but it seems to be a huge feat.

I can understand of course, because that would involve us having to return some form of data object, since PHP does not support multiple return types and neither do most of the supported languages.

GitHub

What are you trying to do? Problem Dagger functions can currently return an error OR any other value but they can't do both at the same time. This makes it impossible to implement pipelines ste...

karmic tendon
#

php does support multiple return types

#

but the underlying engine does not allow it (dagger)

#

we could have Directory|Container

serene light
#

Sorry, I meant multiple return values like how Go can return a value and an error, as two separate values.

#

Either way, I want the feature too ☺️

karmic tendon
#

hmm I see. What about using yield instead then ?

#

It would allow us to return multiple values as well

#

or a Custom object dedicated for this.

#

either way regarding the ignore it is nice I'll probably do it like this But I think supporting external files would be useful so you don't have to repeat yourself multiple times in your dagger source files

serene light
#

@karmic tendon

hmm I see. What about using yield instead then ?

It's possible, but it entirely depends on how it's implemented in Dagger first.

or a Custom object dedicated for this.

That is one of the suggestions (number 3 specifically) and seems to be the preferred option currently.
I personally prefer this option as well.

GitHub

What are you trying to do? Problem Dagger functions can currently return an error OR any other value but they can't do both at the same time. This makes it impossible to implement pipelines ste...

karmic tendon
#

I think it should also allow for example for a ChangeSet to be considered an error if not empty. Would this DaggerError allow for custom object or just raw strings ?