[multiple-field_type]: ->attach($id) not working/saving
Created 5 years ago by finnito

Hey all,

I have a model ($community) which has a multiple-field_type called administrators. This field is related to the UsersModel so that multiple users can be assigned as moderators to the community.

When creating a new community from the frontend (not the backend) I have a command that makes the user who submitted the form, the single administrator, because I don't think that it would make sense to display the administrators field input on the frontend.

Now, I've read the docs and read some Laravel doc stuff which suggests using ->attach($id) for adding a new entry to the relationship, or ->sync([$id1, $id2]) which truncates the relationship and then adds the new ones. I opted for attach().

My command that adds the initial administrator to the community looks like this:

<?php namespace Finnito\NzenModule\Community\Command;

use Finnito\NzenModule\Community\Event\CommunityWasCreated;
use Finnito\NzenModule\Community\Contract\CommunityRepositoryInterface;
use Anomaly\UsersModule\User\Contract\UserRepositoryInterface;

class AddInitialAdmin
{
    protected $communities;
    protected $users;

    public function __construct(
        CommunityRepositoryInterface $communities,
        UserRepositoryInterface $users
    ) {
        $this->communities = $communities;
        $this->users = $users;
    }

    public function handle(CommunityWasCreated $event)
    {
        $community = $event->getCommunity();
        $community->administrators->attach($community->created_by_id);
        $this->communities->save($community);
    }
}

Now, when I view the table of communities in the backend, there is no administrators set for the newly created community. I'm honestly not sure what is causing this to not work as I have look around a LOT. Any pointers would be much appreciated!

P.S. If it's of any use, my multiple-field_type handler looks like this:

<?php namespace Finnito\NzenModule\Agent\Support;

use Anomaly\UsersModule\User\Contract\UserRepositoryInterface;
use Anomaly\MultipleFieldType\MultipleFieldType;

class AgentHandler
{
    public function active(
        MultipleFieldType $fieldType,
        UserRepositoryInterface $entries
    ) {
        $fieldType->setOptions(
            $entries
            ->newQuery()
            ->where("verified", "=", "1")
            ->pluck('agent_name', 'id')
            ->all()
        );
    }
}
finnito  —  5 years ago Best Answer

Daaaang! So, I get this if I use ->reload()

Call to undefined method Illuminate\Database\Query\Builder::reload()

But upon doing some more Googling, I found that there is ->load() which is very similar to with, which makes me think that the relationship is not being loaded, so perhaps I need to eager load the relationships in the model!

I've added this to my CommunityModel:

protected $with = [
        'administrators',
        "regions",
    ];

And then my command can look nice and simple like this!

<?php namespace Finnito\NzenModule\Community\Command;

use Finnito\NzenModule\Community\Event\CommunityWasCreated;

class AddInitialAdmin
{

    public function __construct()
    {
    }

    public function handle(CommunityWasCreated $event)
    {
        $community = $event->getCommunity();
        $community->administrators()->attach($community->created_by_id);   
    }
}

That was a huge amount of mucking around and going back and forth, so thank you very much Ryan! I appreciate it hugely!

ryanthompson  —  5 years ago

Trying to look through some of this I think you're missing a critical behavior of the multiple and other relation providing field types. Basically all those FTs (file, files, related, multiple, polymorphic.. anything providing a relation) provide relations as the camel case of their field's slug. I.e. multiple roles field makes a relation like roles() and maybe a files FT called gallery_images makes a relation called galleryImages().

So following suit you can use those methods POST save of your initial entry to manipulate stuff manually.

Pop open your compiled models and find the relation methods (bottom of the model) for your fields - and you'll see it returns getRelation from those fields. Which you can then see the type if you want (or dd($entry->roles()); for example).

Hope this makes sense!

ryanthompson  —  5 years ago

I know you come from the v2.2 CodeIgniter Pyro and I just wanna say - it's been SO cool to watch you progress in your work 😄 I know you went through a difficult learning curve as many others did (as did I even) coming from CI. Very cool 😄

finnito  —  5 years ago

Hey!

Thanks for the kind words, I appreciate it! I feel like I've learned a huge amount and I've still got a way to go.

I definitely have noticed through your source code the use of the camelCase method to access a relationship field. I didn't think that it might be in the compiled model though, so that was cool to see.

I have been doing some debugging and I am seeing the weirdest things going on @ryanthompson. Let me describe it and then post an image of the results.

Entry 1: I created a community and selected some geographical regions (another multiple field type). Result: Geographical regions added but user not added to the administrators multiple field type.

Entry 2: I created a community and did not select any geographical regions. Result: No geographical regions added and user not added to the administrators multiple field type.

Entry 3: I created a community, selected some geographical regions and did dd($community->administrators()->get());. Result: No geographical regions added but user added to the administrators multiple field type

Entry 4: I created a community and did not select any geographical regions but did dd($community->administrators()->get());. Result: No geographical regions added but user added to the administrators multiple field type

Conclusion: There appears to be some conflict, somehow, between the two multiple field types on the model, and I'm not sure how that might occur at all.

DIm5qDC.png

AddInitialAdmin.php

<?php namespace Finnito\NzenModule\Community\Command;

use Finnito\NzenModule\Community\Event\CommunityWasCreated;

class AddInitialAdmin
{

    public function __construct()
    {
    }

    public function handle(CommunityWasCreated $event)
    {
        $community = $event->getCommunity();
        $community->administrators()->attach($community->created_by_id);
        dd($community->administrators()->get());
    }
}

FrontEndCommunityFormBuilder.php which has been bound in the Addon Service Provider

<?php namespace Finnito\NzenModule\Community\Form;

use Anomaly\Streams\Platform\Ui\Form\FormBuilder;
use Finnito\NzenModule\Community\CommunityModel;

class FrontendCommunityFormBuilder extends FormBuilder
{

    protected $model = CommunityModel::class;

    /**
     * Fields to skip.
     *
     * @var array|string
     */
    protected $skips = [
        "enabled",
    ];

    /**
     * The form actions.
     *
     * @var array|string
     */
    protected $actions = [
        "create",
    ];

}

FinnitoModuleNzenCreateNzenFields Migration

protected $fields = [
// Other fields omitted
    "administrators" => [
        "type" => "anomaly.field_type.multiple",
        "config" => [
            "related" => UserModel::class,
            "mode" => "tags",
            "handler" => "\Finnito\NzenModule\Agent\Support\AgentHandler@active",
        ],
    ],
    "regions" => [
        "type" => "anomaly.field_type.multiple",
        "config" => [
            "related" => RegionModel::class,
            "mode" => "tags",
        ],
    ],
];

create-a-community.twig frontend view

{% set form = form("communityForm").redirect("/create-a-community").get() %}
{{ form.open()|raw }}
{{ form.fields.name.setPlaceholder("Community Name")|raw }}
{{ form.fields.slug|raw }}
{{ form.fields.description|raw }}
{{ form.fields.regions|raw }}
{{ form.actions|raw }}
{{ form.close|raw }}
ryanthompson  —  5 years ago

Before you work with the relational information - try $entry->reload('theRelation'); I wonder if it's not picking up recent data. I have to do this depending on the nature of how/when I am using what relations in correlation with when the parent is being created.

finnito  —  5 years ago Best Answer

Daaaang! So, I get this if I use ->reload()

Call to undefined method Illuminate\Database\Query\Builder::reload()

But upon doing some more Googling, I found that there is ->load() which is very similar to with, which makes me think that the relationship is not being loaded, so perhaps I need to eager load the relationships in the model!

I've added this to my CommunityModel:

protected $with = [
        'administrators',
        "regions",
    ];

And then my command can look nice and simple like this!

<?php namespace Finnito\NzenModule\Community\Command;

use Finnito\NzenModule\Community\Event\CommunityWasCreated;

class AddInitialAdmin
{

    public function __construct()
    {
    }

    public function handle(CommunityWasCreated $event)
    {
        $community = $event->getCommunity();
        $community->administrators()->attach($community->created_by_id);   
    }
}

That was a huge amount of mucking around and going back and forth, so thank you very much Ryan! I appreciate it hugely!