Your current command is almost there, instead off using xargs with grep, lets:
- Move the grepto an-exec
- Use xargsto pass the result todirnameto show only the parent folder
find ./ -maxdepth 2 -type f -exec grep -l "foo-bundle" {} /dev/null \; | xargs dirname
If you only want to search for composer.json files, we can include the -iname option like so:
find ./ -maxdepth 2 -type f -iname '*composer.json' -exec grep -l "foo-bundle" {} /dev/null \; | xargs dirname
If the | xargs dirname doesn't give enough data, we can extend it so we can loop over the results of find using a while read like so:
find ./ -maxdepth 2 -type f -iname '*composer.json' -exec grep -l "foo-bundle" {} /dev/null \; | while read -r line ; do
    parent="$(dirname ${line%%:*})"
    echo "$parent"
done
We can use grep to search for all files containing a specific text.
After looping over each line, we can
- Remove behind the :to get the filepath
- Use dirnameto get the parent folder path
Consider this file setup, were /test/b/composer.json contains foo-bundle
➜  /tmp tree
.
├── test
│   ├── a
│   │   └── composer.json
│   └── b
│       └── composer.json
└── test.sh
When running the following test.sh:
#!/bin/bash
grep -rw '/tmp/test' --include '*composer.json' -e 'foo-bundle' | while read -r line ; do
    parent="$(dirname ${line%:*})"
    echo "$parent"
done
The result is as expected, the path to folder b:
/tmp/test/b