Tenanted files, testing batch jobs, and enhanced enumerations
Hey. I am Michael Dyrynda.
Jake:And I'm Jake Bennett. Oh, yeah.
Michael:And this is episode 162 of the North Meet South web podcast.
Jake:How many times do I have to do this before I learn my lesson? Every time I open a can like that, I get it all over my keyboard and it's just a mess. So what in the world? This is swoon peach tea. I actually messaged Aaron, and said he should he should try this.
Jake:He should,
Michael:I think I think the way that it works is that you have to send him a case of it.
Jake:You have
Michael:to ship
Jake:it to his house. Right now?
Michael:Yeah.
Jake:Is that what he said? Like so in order for him to drink a soda on his oh, Siri is. Siri is talking to me. So so he he wants me to send him a case? It's no.
Jake:I don't think it's it's
Michael:He doesn't want you to. That's what happened after he after he put the first episode out, and he put, you know, his his office address into the Internet. People started sending him cases of various, sparkling waters. So Aaron, if you're listening to this
Jake:If it was only that easy, he doesn't listen to the show. Let's be real.
Michael:He's a man of the people.
Jake:Dude, dude barely has enough time to record all the podcasts that he's on, much less listen to podcasts. Pretty sure the dude doesn't listen to us.
Michael:I feel like he records a lot of podcasts, because I just saw, like, he posted a link to the one that he did with Glauber from, Terso back in June, and it's the first I'm seeing anything of it. So
Jake:yeah. I know. He's everywhere. The dude is everywhere.
Michael:I mean, when it when it is your full time job to create content, I suppose it makes it a bit easier when your entire 9 to 5 is content creation than for, like, you and I who are doing this in our lunch breaks and after the kids are in bed and things like that.
Jake:No. For sure. I think that's definitely true. I mean, let's be real. I I'm stoked for him.
Jake:I mean, he's done the thing is, like, it's not like he's a slime bag, and he's just, like, getting on the shows. I mean, the people reason people have him on the show is because he's a genuinely really nice guy, a really good, a really good, guest because he's great at talking and he's interesting and he's funny. Mhmm. And the quality of the content that he puts out is next level. Like, so if you saw the new the Postgres, trailer thing, Mastering postgres, I mean, it looks like a trailer for, like, a album or something.
Jake:It's Yeah. Incredible. Like, the amount of effort and work that he puts into this. And then his friend Steve as well. Right?
Jake:TriHard Studios, both of them together. It's just incredible stuff, and so, you know, good on him. I'm glad it's going well for him. You'd hate to see somebody put in all that effort and then fail. Yeah.
Jake:I'm really glad that people are recognizing it for for what it is and, you know, rewarding him, I guess, quote, unquote. And I mean, maybe not, like, monetarily, but, like, rewarding him with, like, you know, distribution, essentially. Getting him on the show Oh, yeah. Getting him in front of other people, you know.
Michael:Well, I messaged him this morning, because I woke up my entire Twitter timeline. It was just, like, his face over and over again. Everyone just, like, sharing, retweeting, quote tweeting, him reposting, like, everyone saying, you know, how how good this this video looks. I think I watched it about 4 or 5 times.
Jake:I I watched it once, and then I messaged him. I was like, dude, I think it was fire. It was awesome. So good. So
Michael:I said, is there any concern? Is there any concern over using Frank Sinatra? Like, what's what's the worst here? And I think we both decided that the worst would be that they get, like, a cease and desist, and they would just have to tear the video down. But at that point, the market
Jake:change the music. Everyone knows exactly. They've gotten the exposure for it. Yeah. Yep.
Jake:Yep. Really good. I mean, the video call I mean, like, the I I wonder who I shot it on. I mean, he had to set all those shots up by himself. It's not like he has an assistant more running around in his office.
Michael:They, you know, someone Honestly they did. Someone someone that did he did have someone come out. I think he tweeted about it last week.
Jake:So Okay.
Michael:And, like, we're just we're just feeding that machine right now. We're just talking about his content creation business, and Yeah. You should all check out, what is it, mastering postgres.com or something like that. So
Jake:Who knows? I don't have any idea. Yeah.
Michael:I've never used Postgres before, but I think I think between between this course and Laravel Cloud having serverless Postgres by default although, I think Tyler did say in his q and a that that they plan to have MySQL available on launch. But I think between those two things, there is a good chance that there is gonna be a lot lot more Laravel developers in particular looking at Postgres in the coming months.
Jake:Yeah. Sure. Why not? I mean, only thing is I don't know anything about it. That's the only limiting factor for me.
Jake:But, I mean, if you're using all the take care
Michael:of that.
Jake:I was gonna say if you're using the grammar without, like, eloquent, it doesn't really matter. I mean, it's just, you know, it's just another driver, so who cares? But, anyway, yes. No. It's, I'm glad for him.
Jake:I'm glad for him. It's it's good stuff. There was something else I was gonna talk about regarding that, but don't remember what it was. So no worries. K.
Jake:Couple things I would love to talk to you about today. Yeah. Number 1, I would love to talk to you about, tenancy in Narwhal and talk about storing files per tenant in a segmented location. Let's talk about that. I think that's interesting, and I think it's something it's a challenge we're trying to solve right now.
Jake:I also wanna talk about an I'm policy that uses the username of an I'm user to segment the permissions, which I really, really like and I can share into Gistelog. It's something that we've used recently, and I sort of just stumbled across. I was like, I really like that pattern, so I'm gonna do that. So we should talk about that. And then you had something recently that you were messing with, in you talked about this in cash money.
Jake:Cash money, cash oh, you know what else I wanna talk about is, testing batches.
Michael:Thatches. Yeah. That looks that looks gnarly. What you
Jake:It is a bit it is a bit gnarly. Yeah. Yeah. But, no. I think I think we should talk about that a little bit.
Jake:And then what did you have? You had something the other day you were talking about, and I was like, oh, this makes good sense.
Michael:Talking about enums. Is that is that is that it?
Jake:Ah, that's it. Enums. Yes. Enums. Exactly that.
Jake:Yep. Yep. Yep. Yep. Yep.
Jake:Yep. I wanna write these down because otherwise, I'm going to forget them.
Michael:You will forget it. That is what always happens.
Jake:Yep. So I said first, I said we should talk about tenant, storage. Mhmm. Talk to you later about my policy, segmenting by username of I'm user, and then you were talking about enums. And what else was there?
Jake:Did I say something else or no?
Michael:Batch testing.
Jake:That's it. Batch testing. Thank you. Batch testing. We'll see if we get through all that.
Jake:If we don't, that's okay. We could talk about it some other time. We're on episode 160, so I'm gonna write that down here too. And this is why Caleb just talks about stuff as soon as it comes to his brain in notes on work, which I gotta say also, if you have not listened to that, you definitely should because it's really awesome.
Michael:Sorry. Tell me about tenanted storage.
Jake:Tenanted storage. Okay. So here's the challenge. Right? I and maybe it's unnecessary, but my fear is that if I'm using something like Spasie Media Library, and I have models that are scoped to a tenant.
Jake:It feels weird to me to just use the media library to just add on a media item to that tenant, and then it just stores it in this s 3 media location. That's it. You have the media disc, and everything's just chucked into the root directory. And I guess I just feel like I want a little bit more separation between the files than that, than a record in the database. Like, I want to protect myself somehow from my own stupidity, and you know what I mean?
Jake:Accidentally giving someone else access to something that doesn't belong to them or them being able to be nefarious and get to a URL that they should not be able to get to or to generate a a, you know, temporary link to a file that they should otherwise not have access to. Yeah. And that's so that's that's my fear, and maybe that's unfounded, but I don't think it is. I think it's actually probably a good idea to protect myself from those sorts of things where, like, I might accidentally forget or have something like that. So it's just this layered approach, this idea of layered sort of, you know, things that prevent me from having unauthorized access to these different file locations.
Michael:Yeah.
Jake:So what are your thoughts on that first before I dig into it? Like, yay, nay. Do you think that seems like a reasonable fear? Is that what do you think?
Michael:I think I I think the main thing there would be, like, collisions and file names between tenants. But if you're just using Laravel's default stuff where it where it generates a file name from a hash or, you know, random string or whatever it is that it does, then I think that's not a concern. I think the default is to, like, store those things as private files. So you can't like, you can't get a directory listing on s 3, and you can't just access these things without a signed URL. So I think That's true.
Michael:I think the opportunity to accidentally stumble upon a file is taken care of at this, you know, at this high level by S3. I think if you are accidentally leaking media records between tenants, The problem is in, like, application application logic land where you are leak like, if you are leaking media models between tenants, you are probably potentially leaking other information between tenants. And that's something that you need to to look at. That said, segmenting Which
Jake:I agree. I that and that's what I'm saying is, like, I I am confident that we will get it right most of the time, but I'm afraid that there will be times or there will be something where I will you know, somebody if it's even if it's not me, somebody on my team will accidentally write something or we want to realize that it is leaking something.
Michael:Mhmm.
Jake:And in the case that it does, I want to have another mechanism that will protect me from giving that person access.
Michael:Mhmm. Yeah. So, I mean, if you if you link the model to to the wrong user in the wrong tenant, you're going to link access to that file anyway. Because I assume, given that you are using signed URLs to access those files, if you happen to return that model, you are returning a authorized link to that file anyway, irrespective of where it's stored.
Jake:And this is the backstop. Right? So the backstop is if I'm storing them so let me just tell you sort of this leads into my second part here, which is, this idea of a policy in AWS that allows me to control access to particular folders. I guess you could call it clip particular directories inside of a bucket based on the user that is currently authenticating to that bucket. Okay?
Jake:So the way that I have this, this policy set up is it says allow listing of buckets for we'll just let's just call it Jake's media bucket. K? So you can list buckets for for Jake's media bucket because you have to have that permission for some reason in order to be able to do anything in there. You have to have the ability to list buckets. Great.
Jake:Yep. But the ability to get, put, or delete is restricted to a path that is scoped to the username of the I'm user that is currently having this policy applied to them. So if I have a user, an I'm user called, let's just use Wilbur. Like, Wilbur is the name of my employer. That's the tenant is Wilbur.
Jake:Then what happens is Wilbur has access to Jake's media bucket slash Wilbur slash star. Anything within that directory works. It it'll just work. I I can get I can get put and delete in there, which is great. So if there's another one, what's the name of your employer?
Michael:LMG.
Jake:LMG. So if we also have jakesmudiebucket/lmg, even in the case that I accidentally get access to a record that belongs to LMG, If I try and go get something that lives in the LMG bucket, because I'm authenticated as the Wilbur tenant, as far as the credentials to AWS are concerned, I will not be able to get assigned URL to LMG.
Michael:Okay.
Jake:So that is the backstop. It's like, yes, I may have a me. I may have access to the model somehow, but the signed URL, when I go to get that will be covered up, will be protected by the fact that I have different AWS credentials based on the tenant. Now that that brings in other challenges. Right?
Jake:There are other challenges, like, now where do you store those AWS credentials and those sorts of things. But in theory, without thinking about those other things, that is my question. It's like, is that a good idea? Does that sound reasonable? And I think it does, but I'd I'd like to hear what your thoughts are.
Michael:Yeah. So we we're at the moment are using the tenancy for Laravel package that kind of handles the stuff on the fly. So based on whatever your tenant is, it will swap out the storage at as it's part of the application boot process. So it goes and scaffolds it and sets a prefix to, like, whatever the tenant ID is. So everything's in one bucket, and then it's slash tenant whatever the UID is or whatever the ID
Jake:is. Okay. Yeah. Sure.
Michael:So all of that stuff is segmented, and we use, domain based tenancy. So, you know, it would be wilber.whateverlmg.whatever. And so it would then switch to that tenant. You would authenticate to that tenant. And then but but it's still all using the same set of credentials to access each of those tenants.
Michael:So even though the flowers themselves are segmented, you still have so I think you with your IAM policy, you have an additional layer on top, so long as you're also swip switching the credentials as part of
Jake:that Yeah.
Michael:Boot process there, which I think Yeah. I think that adds a little bit of extra protection. I think the the way that the the tenancy for Laravel package does it, it's just swapping the bucket. And that and that, I think, is more around a portability perspective, where if you wanted to pick up a tenant and shove them onto their own EC2, for example, onto their own node, you can do that and just pick up that whole thing and bring all their storage and then put it somewhere else as opposed to, like, isolating between the buckets. So I think you've got the extra layer at the moment where, you know, you are you're accounting for the possibility of inadvertently leaking the models.
Michael:But because you are also switching the credentials used to access those files, Even if you did get a URL, it would still deny your access anyway because it'd be generating Correct. A link to a file that like, with with a different sign in key. So
Jake:That's right. Yeah. That's that's the idea.
Michael:Yeah. I think I think that's probably fine. And, like, it obviously depends on what you're trying to protect here. Like, if it's just profile photos, then it's probably not as critical. But I assume, given the nature of the business, that you are protecting financial information, things like that, where you would yeah.
Michael:You would wanna be, you know, protecting that stuff at a higher level. So yeah.
Jake:Personally identifiable information is the biggest, you know,
Michael:the biggest thing.
Jake:You don't wanna leak that one. Yep. Yeah. And so and I'm also quite sure that, you know, the the level of clientele that we're gonna be servicing, they're going to want to know that in addition to logical separation of those files, there's also going to be, you know, some sort of separation of credentials as well for this exact reason, for the reason we're talking about. Now the thing is I haven't exactly figured out how I'm gonna do this yet is the only trick.
Jake:Like, I don't know the actual architecture I'm gonna use to accomplish this. So one way I've thought about doing it is the and the interesting thing about this tenant app that we have is, like, the max number of tenants we'll ever have is, like, 15. Right? Like, it's it's not Yeah. Like, each each tenant can get set up manually.
Jake:Like Mhmm. I could store each one of the credentials in the ENV if I wanted to. You know what I'm saying? Like, could swap them out but based on the tenant just on using, like, some convention of the naming of the ENV and be done with it. So it's, like, what I could do is I could use a different I could even set up in the file systems dot PHP a different disk per tenant.
Jake:The the tenant could have their own disk, and then I would use the credentials. I could store the credentials in there, and then I'd swap out the disk and then be be good to go. So so that's that's an option as well. And that would probably happen during the the service provider, you know, just booting up the app, then you'd swap out the disk, and then you do all that stuff. Yeah.
Michael:I think I think that's probably an easy way to do it. If you were to configure a disk rather than dynamically switching the credentials of a rather than trying to swap the credentials used for a single disk at runtime.
Jake:Right. Right. Yes. Exactly. And then the hope there would be, the hope there would be that, you know, you wouldn't make the stupid mistake of saying, like, okay.
Jake:Well, when you're trying to go get the the documents for this claim, just use the team ID of that claim and then swap to that disk. It's like, no. No. No. The only time you ever swap the disk is at this time you boot the app, and that's based on the currently logged in tenant.
Jake:That's it. And no other places do you ever do that. You always reference the disc that's loaded into the existing, you know, the tenant, the users that's logged in. Never do it based on the actual claim itself. Yeah.
Jake:So, yeah, I think that that'd be the only way. So but I I think I would sleep better at night being knowing that that was the case. Yeah. That there's no way for them to swap that out, or if I did leak a claim, it's not gonna, like you know, it would just basically be like the claim's not there. It doesn't I I don't see any folder by that name.
Jake:So Yeah.
Michael:Yep. I think that's Okay. Cool. I think that's reasonable.
Jake:Okay. Cool. That that's helpful. I appreciate having that discussion. So, again, I, with that sort of, like, I'm policy thing, just as a heads up, like, I I can throw that in the gist log if that's helpful for anybody.
Jake:The really big benefit to me was that I didn't have to write a new JSON policy every time I wanted to make a new user that had access to a specific location inside that bucket. All I had to do was create a new user, attach that policy, and I was done. Attach one policy. And so all you have to do there is basically, reference the username and the path by just using I think it's actually a dollar sign. I think it's a dollar username, inside of the policy itself, and it will use the username of the, of the logged in user.
Jake:Now one other thing to notice there is as well, it's case sensitive. So, like, if you have Wilbur upper case, the capital w, or Wilbur lower case, those are 2 different locations, or 2 diff yeah. Yeah. The name of the user is case sensitive, and so it matters, when you're trying to look at that disk location. So, yeah, there you have it.
Jake:There you have it. Okay. Nice.
Michael:Yeah. I think I think you're covering your bases there given what you're storing. I think the the only decision really you need to make is do you wanna configure, right, n number of disks, or do you wanna figure out how to dynamically switch them at runtime?
Jake:I think I think having a number of disks is probably fine. The only the only thing that I will have to be careful about or just consider is that when I'm doing, like, the media stuff, Spassie media library, I think there's a way though. You could just say on disk. You just put it on a specific disk, like it's a fluent it's a fluent call. Yeah.
Jake:I can just do that. No problem. That should be easy enough.
Michael:And I don't know where I saw this recently. I think it might be, like, Stephen Baumann has been tweeting these kind of things recently where he's took and and maybe it was you that retweeted it, talking about putting queue names into an enab. And I think you could do the same thing with with your tenant, like, with your file system disks. Just and that way you can
Jake:run out of
Michael:and things like that. Yeah.
Jake:Yeah. We do we do that right now with any of our disks as we put them in. Now okay. This is actually an interesting one too. Let me so let me let me cover what you're talking about first, which is yes.
Jake:In file systems dot PHP, instead of having a string name for the disk, we use a enum there. Now we were using just classes and constants. Right? Because with the class and the constant, it always references the string value. There is you don't have to do arrow value, which looks so much nicer.
Jake:You could just say disk double colon wilber or disc double colon LMG or whatever you said you said yours was. Yep. Whereas now I have to do disc double colon Wilbur Arrow value, which, ugh, I do not like that. That's that sort of sucks, but you have to have the string representation of it. You can't do anything else.
Jake:So, wish there was a better way to do that, but there isn't. So, yes,
Michael:they're using
Jake:enums in that way.
Michael:Samuel, who who wrote tenancy for Laravel, also has this package, for enum augmentations, I guess you wanna call them. And one of the features of this package, one of the traits that it includes is the ability to make enums invocable. So you can you can do, you know, file system disc colon colon wilba and then caller as a static function, and it will return the string value. So that way, you get, you know, the ID support, you get the completion, and you also get, you know, the ability to to get the value of that in a member without having to then chain on our value. So that that makes sense.
Jake:Pretty good.
Michael:But, yeah, it is it is kind of annoying that PHP does not,
Jake:and for you automatically. Yeah.
Michael:Casting it to a string in in a, you know, in an array context like that.
Jake:Yeah. Yeah. Yeah. It's annoying, but whatever. So we've we've just swallowed hard and just been like, okay.
Jake:We're just gonna make it. We're just gonna do it that way. Arrow value it is. And so whatever. We deal with it.
Jake:But speaking of enums, tell me about your enums, thoughts here. Like, you Enums. You were good. Yeah, your Enum adventures. So you said something about maybe, like, making a little video course or something?
Jake:Or what what are you talking about?
Michael:Like a little mini thing. I don't I don't know exactly what it looks like, but the the kids had a sleepover at the grandparents' place on the weekend. So I had a little bit of time, which I spent, of course, most of that time getting my setup working for for recording video. But I just I just put together, like, a little 2, 3 minute off the cuff video talking about, you know, in terms. And we we we all have them now in PHP since version 8.1, and we'd love to use them, and we love talking about them.
Michael:And I think there's some interesting opportunities to to explore, like, usage of them beyond just, like, here is a thing that has like, it's either a fact enum that returns a string value or or it's just, a basic enumeration that just has case names. But there's there's a lot of different ways of using it. Like, PHP doesn't provide a nice way to return a list of options or, like, it gives you cases, but it doesn't allow you to target the values or the keys and things like that. So there's ways around that.
Jake:You gotta kinda build them all in with your own traits and all that nonsense.
Michael:So, yeah. There's there's no. Just just to kind of talk a little bit through that and and what that looks like, some options, you know, this this enum package that I mentioned is a good way to kind of bring that in in a way that you can use it across projects and across enums really easily without having to, you know, manage your own traits and things like that. But then also talking about more interesting use cases like, providing stateful functionality, to use, like, your invoice status. Example from your
Jake:Ah, yeah. My
Michael:Laracon talked last year. You know, if if you have a a status of, you know, draft and, active and paid and debt, for example. Like, you can attach descriptions to those and use them to label things in the in the UI of your application based on
Jake:Sure. Yeah.
Michael:The current state of that enum. So, you know, talking a little bit about that, talking a little bit about, you know, factory instantiation of enums and things like that. So there's there's some, like it's not it's not like a huge service area, which I thought it would be a good idea to do it because it's, like, fairly limited in scope, and you can kind of go, this is everything in quotes that that you can do and it's just done. But I think there's interesting exploration that, you know, you see bits and pieces every now and then, but not, a great deal of discussion around that kind of stuff. So I thought, you know, just as a little bit of fun.
Michael:Of course, since since that 3 minute video, I've had absolutely zero time to work on it.
Jake:Right. Right. I because when the
Michael:kids are home, there's there's no time, and I can't when the kids are asleep, because one of them sleeps, you know, obviously, that wall as we've discussed before, so I can't be in here recording videos at night. So
Jake:Yeah. Yeah. That's I I get it, dude. I'm I'm there with you. Like, I have to, I've been, I mean, it feels like we're in an eternal house project mode.
Jake:You know what I mean? Like, it just never ends. So I'm putting up casing and baseboards right now. But, yeah, I can't do it if the kids are in bed because I don't wanna wake the kids up. So it's like, you know, you only have so much time.
Jake:So today, all the kids were at a soccer game. So I came home from work and just got got to going on it because it was like, I'm not gonna bother anybody if I'm making lots of noise. And so Yeah. Tore it up, but that's how it is. Yeah.
Jake:No. I think that's I'm curious how many people in the PHP ecosystem are not using enums. I mean, I guess the prerequisite is you have to be on PHP 8.
Michael:8.1. Yeah.
Jake:8.1? And, so, I mean, you know, depending on what percentage of people are on 8 dot 1 or above, that's gonna be, you know, that. But then of the people who are on 8 dot 1 and above, who's not using enums? You know, I don't know. It's like one of those features.
Jake:It's one of the I I think you said it the other day. You're like, man, it's one of my favorite features of PHP now. We use it we use it everywhere, you know. And any place that I see a magic string, I'm like, nope. Nope.
Jake:Nope. Nope. Nope. Nope. Don't do that.
Jake:Please don't do that. Please use the enum.
Michael:We have we have this enam called yes, no.
Jake:Oh, I like that.
Michael:It has 2 members. Yes and no. But we because for historical reasons, a lot of our database actually stores yes and no in fields as opposed to
Jake:Instead of 1 or 0s? Yeah.
Michael:So in order for us to, like, operate in a sane way in our code with booleans and then convert them, we've got, like, this factory method on the yes no enum called yes no from boolean value. And that way we can handle situations like you pass in, like, some Boolean and then, like, if it's true, we return yes, and if it's false, we return no. Like, just that Genius.
Jake:I mean
Michael:those small little things. But you correlate all that behavior in one place, which means you can test that. Like, you can throw different things at it. You can decide whether or not you want to handle null. Like, is null an invalid state?
Michael:Does null return null from this enum? Or does null default to false? You know, all those kinds of different things that you that you co locate and that behavior is there. So you can do it anywhere that you need to, you know, anywhere we need to do that transformation from a boolean to a string of yes or no, we can do it all in that enums. Sorry.
Jake:And vice versa. Right? Because if from the database, you can cast to an enum. So you cast from the enum to the yes, no type or sorry. Well, yeah.
Jake:You cast from the database to the yes, no enum, and then you have all that behavior again. So, like, when you're referencing that value, that column, just, you know, you're dealing with the enum. So that's super handy, man. I mean, all that behavior you get and then plus just the confidence to know that I'm dealing with one of these values. You know?
Michael:And you know just You know, when when you're doing a match inside like, in the context of an enum, you you never have to put a default state in there really because you can only have an enam that exists in a valid, representable state. So yeah. And then this is, like, here's the documentation talks about this in the in the notion of, like, the enam exists to to prevent you from having a value that is in an unrepresentable state or something like that. Like, if the enum is instantiated, then the enum is it contains a valid state. It can't be anything other than what is defined in the enum.
Michael:You can't have an enum with a value of null.
Jake:So Yeah. Yeah. The only case in which you'd have to have a default state, and I've run into this a couple times, is so somebody will have a method called get options or get labels or get colors.
Michael:Mhmm.
Jake:Right? And so what they do is they start listing all the enum cases in the left and then listing all the values that they should be associated to on the right hand side, which is great, except for when you add a new case and you forget to add it into that method. Mhmm. And now you have a default state because you can have a valid enum value that does not have a state. And so instead, what we've tried to do is do something like and and so this is a case for at, attributes, PHP attributes.
Jake:And so what I will do is I will instead of having and this gets a little bit messy. It's not the it's not the right solution for everybody. But instead of having a get labels, and I'm sorry, I will still have to get labels, but what I will do is on the case itself, I will put an attribute of label on it, and I will define the label right above that case. So if I'm adding a new case, all I have to do is follow the convention and add that new label on that new case, and now my get labels says, give me all the cases and loop over all of them and give me the associated label. And if there's ever one that doesn't have a label, it throws an
Michael:error. Mhmm.
Jake:And so I do the same thing for colors. I do the same thing for whatever. So it's like all of that stuff is right there located on the case itself. Now like I said, does get a little bit messy sometimes if you have too many things you're trying to do, but it actually works pretty dang well, I gotta say. So that's another thing you could add to your enum talk is using attributes to co locate that stuff right up next to the case rather than in a match function.
Michael:Yeah. I like it.
Jake:I could send you an example of that too. Yeah.
Michael:I I
Jake:because it is a little bit tricky with the reflection. You know what I mean? You have to use that you know, you have to use the attribute and then the reflection stuff to get the option, or they get the label
Michael:or whatever. That is that is like I actually looked into like how to put your own attributes together. And because it is all meta programming, the only way to reference the attributes is to use the reflection API to do things to look for specific members of of a class. And then you've got to look to see it, like, is there an attribute attached and all this other stuff? I guess it's nice if you do it in such a way that it's reusable, and you can just put it anywhere.
Michael:But it's also like That's
Jake:what it is. Yeah. Yeah. That's what it is. And so, like, if you know, what I do is I have an attribute call or a trait called has labels.
Jake:And then has labels has that method on it, and then I already know the attribute is gonna be label, and then it just you know, I don't I only have to write it once. And now I know I have a labels function on there that automatically uses reflection and the label attribute to get the labels. So it's not difficult to implement, and, you know, the the trait says exactly what's on the you know, does exactly what's printed on the tin as you guys say. Yeah. I'll send you that, and I'll send everybody else who's interested in that too.
Jake:There actually was a Laravel News article that I used to sort of get me on this path. Although the Laravel News article was, like, adding your own attributes to your enums or something. That was a while back. Yeah.
Michael:Nice. Yep. That's good. Go go give credit to
Jake:the author.
Michael:Definitely definitely do that. Yeah. We'll reference that as well. That's interesting. Very good.
Jake:Awesome. Okay. One other thing. What do we got here? We got we got the testing of, batches.
Michael:Yeah. So you, you were doing this look, kinda grim. And I think the realization that we came to in that chat was that, yes, it is grim, but there's not really a better way of doing it.
Jake:The only yeah. No. There is no better way of doing it currently. So let me explain the situation. So I've got a action that is dispatching a batch.
Jake:So the action creates a claim, and then I have a batch that gets dispatched that or is that right? Yeah. I have a batch that has 2 jobs added to it, just like add notes cover page and add claim cover page. Those are the 2 jobs, and then I dispatch it. And then I have a then, which tells the batch when you are completed successfully, do this action.
Jake:Right? And then you have a catch, which says if anything fails, you should do this. Right? So that's the situation. Bus, jobs, here's the jobs, dispatch, then catch.
Jake:Right? Those are those are your sort of methods you have there. So, you know, what I wanna do is I want to assert in my test that there were 2 jobs dispatched, and that the 2 jobs that were dispatched were these 2 jobs. Now some people would call that, like, spell check testing, and I would agree. It is spell check testing.
Jake:But what I'm trying to do is I'm trying to prevent future developer, not me or me, from accidentally commenting one of those out or having something stupid happen. You know, some merge conflict comes in and they just delete it, and now my test is, you know, if I don't have this sort of spell check test in place, it's like, yep. Everything's fine. So I I that's what I'm trying to avoid. Right?
Jake:Yeah. I'm not testing the actual job, the the the add claim cover page or add notes cover page. I'm not testing the job. I'm testing that job separately, but I want to know that the batch is getting those specific jobs. Okay.
Jake:So Mhmm. The the way that you can do it right now is in your test, you batch fake, and then you batch a certain dispatched, and then within there, you get a pending batch. So that pending batch contains the jobs that are added to the batch. So you see pending pending job arrow jobs, that will give you that. And so then you can do assertions against that.
Jake:That just gives you a collection of them. Right? It just gives you a collection of jobs. And so in order to assert, you could say count count that there's 2, and that works fine. Yeah.
Jake:You can count there's 2. But then if you wanna assert that the 2 jobs that you are expecting to be there are there, you kinda have to, like, map to the get class of the job. You know, you kind of map over each of them, you know, return the class name of the job and then check to see if it contains the 2 jobs that you're expecting. That's that's sort of crappy. It doesn't feel good at all.
Jake:It feels like it should be something like pending batch arrow has job, my job. Pending batch has, you know, has arrow has job, my job. And then it should I I would want to do something like pending batch, then, you know, whatever. Did my then work? You know, I I shouldn't even actually have to do then.
Jake:I if I wanted to call then, I could just do it. So
Michael:Yeah. I feel Anyway. I feel like, number 1, I like these kind of smoke tests for events, for jobs, for for things like that, where you just wanna fake that this happened. Right? You don't Yeah.
Michael:You don't care the side effects of those jobs running or those events firing or whatever else. You just wanna make sure that given you hit some controller or something happens in your application, this expected behavior was fired. Like, these jobs were dispatched. And then, as you say, testing the actual behavior of 1 or more of those individual jobs is, you know, is the concern of instantiating that job,
Jake:calling it a test somewhere else.
Michael:Yeah. Like, a test somewhere else that does that. So, I feel like JMac has talked about this before, about, like, testing batch jobs or something like that. Maybe he's worked on it. Like, I'm I'm sure I've heard about it in passing somewhere.
Michael:And I feel like it was J Mac, but I could be wrong that it was him, around, you know, a better way of doing this stuff.
Jake:Yeah. So I mean, the what I what I ended up seeing and maybe throwing out as a suggestion, and if anybody feels inclined to do so, you should definitely do this. I think it's a great pull request, honestly, to the framework. We have this idea of a certable JSON inside of our JSON tests, which is awesome. It's really cool.
Jake:So you can say assert JSON, and then you have a closure, which has an assertable JSON. And so what that allows you to do is allows you to make all sorts of assertions against the JSON that's in there. You get this really nice class that has all these little helper methods to give you the ability to test all sorts of things in your JSON, the payload that's coming back. Super cool. So my suggestion would be here, when you say bus assert dispatched, instead of just getting the pending batch, what you would get is something like an assertable pending batch, and then it would that that assertable pending batch would have little helpers on it that would allow you to do exactly what we talked about.
Jake:Is this job in the list of jobs that's getting dispatched? You know, does my Venn, closure, when it's executed, have the existing have the side effects I would expect? That sort of stuff. And so this was an exam that that was some, a suggestion that somebody gave on Laravel, sorry, on Laracasts, forums was they were like, well, when I do my when I do my assert batched, I take that pending batch and I knew up a fake batch that I have passing in the pending batch, and then they just do exactly what I talked about. They have they've created all their little helper methods to do exactly that, test to see if the job is in there, etcetera.
Jake:So it's actually not that difficult of a PR to make to the framework, but it would be a pretty cool PR to make. So if anyone wants to scoop me on that one, go for it because I'm probably not gonna do it. But I think it's I think it could be really cool. And, yeah, David Hemphill said he talked to Taylor about it. And Taylor was like, yeah.
Jake:There's no better way to do it right now. And so not saying that there's not a better way it could be done, just that currently in the framework, there is no better way to do it. So if you're looking for your first pull request to the framework, go for it.
Michael:Pretty good one.
Jake:It would be a good one.
Michael:Excellent. I don't I don't think I've got anything else.
Jake:Okay. I I think this is a pretty valuable episode. I know we talked about some really good stuff in here. Yes.
Michael:Good stuff. Thanks. Thanks for the, the hot tips around the because that gives that gives me some ideas around progression from, like, this is what we used to do, pre PHP 8 point 1 and enums. This is how you might do it using, like, just an inline method. And then the attribute itself is nice because it gives you the ability to kind of do that in a consistent way across all of your, different emails without having to, like, know, implement the same match thing everywhere.
Michael:It's just it's just gonna be available. Correct.
Jake:Yeah. And it protects you against it protects you against that stupid thing that I talked about, which is, like, somebody adds a case and forgets to add it to the method, which has happened to me before. That's the reason I know it's a danger is because it actually has happened. And so what you end up having to do is have this default method that just throws an exception in the case that it's something other, and that's annoying too. That doesn't feel good either.
Jake:Yeah. And so the like I said, I'll send you a code snippet of what I have and what, you know, the nice thing about it, that redeeming quality is if there is ever a case that does not have a label on it, it throws that exception saying, well, you have a case that doesn't have a label. So you can't have a get labels attribute or whatever. So Yeah.
Michael:It's always funny testing, like, that kind of inbound behavior because you find yourself Yeah. You know, duplicating all of that stuff just to make sure that, like, yeah, I have set. And then, okay, I ran the test and it failed because I forgot to do it. So you can go back and and do it. But it's just like, now I've got a copy and paste the description from the enam into the test, and then, you know, if one changes, the other one has to change, and that kind of, you know, leads you down the path of flaky testing.
Michael:So yeah. I like I like this idea.
Jake:I will send it to you my friend. And maybe I'll throw it in a gist, and I will send it to the wider world as well for anybody who cares to do so. And I will find that Laravel News article as well and send that to you.
Michael:Yeah. I found I found that Laravel News article.
Jake:Sweet. Yeah. That's a good one. I mean, that's literally I mean, I don't need to share mine then. I mean, that's exactly what I did.
Jake:What he has there is exactly what
Michael:it is. From,
Jake:Rob Fonseca. Yep. Yep. So grab credit to Rob. Thanks, Rob.
Michael:It's good.
Jake:Good good call.
Michael:Cool. Alright, dude. The only other thing I have to say is we crossed into we only have 47, I think, early bird tickets left to Laracon for this year. So I think we're about 8 minutes away. So we are we are doing well.
Michael:We're having lots of stuff. We're getting into the, like, final stages of, you know, my side of the things now. You know, making sure that the speakers are all set, starting to finalize all of our Oive all the Taylor is setting us up the bomb over here with, just the the level of of production for Aragon US this year. So we've got some ideas. We've got some things that we're gonna do.
Michael:But we're looking forward
Jake:to it.
Michael:We just started storyboarding our, I say we. Nucleus started storyboarding and scripting the intro video for this year. So, you know, we did it last year, and obviously, we have to follow-up this year. But we've got some cool ideas for that as well that that we'll pursue, and some other fun fun stuff. So I'm looking forward to it.
Michael:It'll be here before we know.
Jake:You having to put a lot of work into, like, your intro talk or anything like that? Oh, boy. I'm talking about it.
Michael:I may have made a terrible mistake. Like, last year,
Jake:because it doing that last year. Yeah.
Michael:Well, because last year, there had been a 4 year gap since the last time we did our Sure.
Jake:No. That
Michael:makes sense. That makes sense. You know, it was a good idea to kind of set the tone and and set the same for, you know, why we do what we do.
Jake:Yeah.
Michael:I just don't know. Like, I have
Jake:How do you do that every year? It's hard to do every year. Yeah. Yeah. Yeah.
Michael:I don't think you need to do it every year.
Jake:No. I don't think
Michael:so either. I will I've got some things written down, like, I've got a document, and, like, I will do some kind of opening address, but I don't think I'm gonna tell a story like I did last year.
Jake:I mean, honestly, I again, let's go back to the Aaron Francis whatever blah blah blah. Sorry, Aaron. We should be giving you royalties or something. But, to intro Laravel or Laracon this year, he literally just I mean, it was honestly like a tiny little stand up routine that took, like, 2 minutes. Right?
Jake:It was it was funny. It was it was very chill, like but, you know, the thing is too is it's like you don't wanna put a ton of time into it either because I mean, let me see. How do I preface that? You want us to be good, but, like, also half the people in the room are just getting seated, like, when you kick it actually kick it off. It's just like, you don't wanna, like, stake all this time on it and then be, like, be really frustrated if half the people weren't listening because they were just stopping their chat they were having with somebody they haven't seen in a year.
Jake:So anyway
Michael:Yeah. I think I think this year is gonna be much more high level. Just, like, you know, the the general, like, how many how many of you here for your first time, you know, how many here for your 4th time?
Jake:Oh, totally.
Michael:Yeah. Just like that kind of stuff, you know, and and just set the tone, you know, set the rules and and things like that around expectations, and then, yeah, just launch straight into it this year, I think.
Jake:And what we all realized this year at Lyricon US is people are really just there to see the people anyway. I mean, like, the talks are great. You know what I mean? But, like, it was so heavy emphasized, like, just there was, like, a whole backroom that it was just, okay, people who wanna hang out and just wanna watch it on a screen, just go back there and chat. And a lot a lot of people did.
Jake:So it was cool. And so yeah. Same feel. Right? Don't put too much pressure on yourself.
Jake:Like, the fact the the thing that you're providing is the space for people to meet. That's that's what you're providing, and you're gonna do that regardless. So you've already won. You know? Yep.
Jake:So Alright, dude. Alright. Episode 166? 162. 162.
Jake:Find show notes for this episode at northmeetsouth.audio/162. Hit us up on the Twitters or the x atmichaeldorinda@jacobenorranorthsouthaudio. Rate us up in your pod podcatcher of choice. 5 stars would be amazing. And if you are looking for custom keyboard keys, you should check out dappkeys.com.
Jake:I have I sent another, I sent another picture today. Let me make sure it's DAP keys. It is DAP keys, I think. I think. I think.
Jake:I think. I think. Anyway Campfire. This dude, Austin Cameron what's that?
Michael:The campfire? That was sick.
Jake:Yeah. Austin Cameron, is this dude's name. Met him at Laracon, but he gave me a little LiveWire keycap and a little Campfire keycap. Holy crap. Both of them are so cool.
Jake:They're, like, an acrylic. Mhmm. They're awesome. I I can't wait until he opens up his site stuff because I'm going to be buying some of them. And and I told him, I was like, yeah.
Jake:I've got a low profile keyboard. And so he was like, oh, yeah. Maybe we can make a different mold for that one or blah blah blah. So he's gonna I think he's gonna try and do maybe, like, not a full size keycap, but not a low profile keycap either because you can't really get too much stuff into the acrylic if you do a super low profile. So he's, like, gonna do, like, a medium height, and I'm, like, super awesome.
Jake:So I couldn't be more excited. I'm so geeked out about these key caps. They look so awesome on my keyboard. I'll have to share. Yeah.
Jake:They look so fun. So, anyway, shout out to Austin. Thanks, dude. Alright, everybody. Until next time, 2 weeks.
Jake:We'll see you then. Peace.