Building the Create & Edit Link Components - Laravel Link Shortener [PART 6]

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey welcome to the sixth and final video of the url shortener with laravel series uh in this video we're going to be finishing up the entire system making the create and edit components making all the test pass and kind of just buttoning everything up since the last video i've actually changed a couple things just outside the the series because i found some issues in the test very small things which i'll go over now starting off i actually edited the php unit file and i uncommented these two lines here i noticed that the refresh database trait that we use at the top of the link test didn't actually refresh the database between tests and i figured out that this is why so the phpunit.xml file defines basically what your tests run in or how they run and the next thing i fixed was actually inside the link test this is a good example i just wrapped these in bool val because for whatever reason sometimes these would return a 0 or 1 instead of true or false and there were some issues there it wasn't asserting that it's true even though it's a value of one and so just wrapping this in bowl val finds the actual boolean value of it and that was an easy fix and the last thing i changed actually was the example test so typically i delete this typically i delete this and because it's it's a pretty useless test but in this case in the last video because we switched the main route to just a redirect to the login page this test broke because it used to be like this it was expecting a 200 status from the main route and instead it got a redirect to the login page so now i just changed this to login and it obviously hitting the login page returns to 200 so this test passes but usually i would just delete this and that's pretty much all i did for the updates you could see all this in the github repository and we can now get started with the rest of the video so i think just to get going i actually had this idea i wanted to put a create button right here so this is our index page after we log in you can see where our pagination is working we set this all up in the last video but i want a create button here because i feel like that'd be really useful if you want to just create something quickly currently there's no actual way to get to the create page so i feel like that'd be a good place to put a button to do this i actually just need to open up the index.blade.php this is the file that basically slots in the the livewire component into the app.blade.php file so this kind of like wraps that component and then slots it into the the main template file and so i want to put the button up here which means that i need to justify between with this links label here right so the way i'm going to do this is just by wrapping this in a div and putting the the link tag below it now i did copy this button actually from the included breeze buttons because i thought it looked cool the only downside is that there's a ton of classes associated with this this button to make it look the way it does so it might take me a while to type it out and we want to go to the links.create okay so there's our create button and it's going to be uh justified between with the links label here the h2 and item centered so it's centered horse so it's centered vertically and so there's a lot of classes required to make the button look the way it does and this is a great candidate for like a refactor and to pull these styles out into something that's reusable but for the purpose of this tutorial i think it's fine let's take a look at how this looks on the page links.create is not defined okay so we actually need to add an s here that's my mistake and we can see that we have our create button here if we click it of course nothing will come up because our component doesn't have anything in it but at least it works and it goes to the correct route which is a win so we can now actually get started on creating the create component which is very exciting and then after that we'll create the edit component because it actually relies heavily on the create one so let's get started on that okay so the first thing i want to do is just open up let's clear this open up the create.blade.php file in here we can see that we're just outputting the create link component for the live wire component and there's nothing around it and that's why uh it doesn't look styled when we go to the create page so just before i get started on the actual component i want to make sure that this template is actually wrapping the livewire component with the layerville breeze dashboard stuff so the way we do this is basically the same as the index and actually i might go ahead and just copy the index in here so we save some time so let's do this this is the index one so we replace this with create link and that's the correct live wire component and we can replace this with create and we don't actually need this button which means we also don't need this div here and in here we're just going to leave this as padding 6. and i believe that the rest of it's okay the way it is so let's actually add some text within the create link template here for the the component and see how what that looks like when it's rendered so let's go to the create page perfect looks really great so right in here we're actually going to shrink down this and we're going to limit the width of it and within there we're going to put our create form so our create form is going to be defined or built within this template file we could just start with a form tag and make sure that we're binding to an actual method within the component although we haven't actually built these methods yet so i'm going to bind to a save link method that i will create later on and within this form we want to just create a couple divs as holders for the different inputs and on this page it's only going to be a url input and also a slug input so it's relatively simple okay so what i've done here is actually created the two text inputs that i need to get this done so the first one is the url and the other one is the slug a couple things to note here is i'm using the x input component that comes with breeze and i'm just trying to reuse whatever components come with it just to reduce the time i need to develop stuff although there's really not that much being reused from here like i'm still adding my own classes to it i added block margin top and bottom of two and also full width to it and on the url one i've actually also added required because url is required and autofocus i want the cursor to automatically be set on this uh form field for the slug i actually didn't add the required or autofocus because i put autofocus up here and the slug's not actually required so if it's not entered it will be automatically generated on the back end okay so what i've done down here is actually create two buttons one to reset the form which is this button here and one to submit the form uh one tricky thing to note about livewire is that the wire submit prevent you define up here so in our case save link will only be triggered will actually be triggered by any submit button that you put within that form so both these buttons are in it if you define one as type button and the other one is type submit only this button will submit the form this one will actually one click uh trigger this reset form action so that's something to know if you want only one button to work make sure that only one of them is defined as types of bit and so now this page is actually done let's uh reload and see what happens and it looks pretty good although i did mention that i want the form to be more narrow so i think what we need to do is actually set that in here and the way i'm going to do this is actually to set this to max with 2xl and leave mx auto so it's centered and hopefully that does the trick and it sure does so i think this looks good this button could maybe be a little bit darker so we can fix that too there i think that's perfect so now if i enter a url and a slug here it and hit save it should create this of course none of this logic actually exists and you can see that i'm binding to a wire model slug and wire model url here but if we open up the create link component nothing is actually in there so now the way to complete the crate form is to actually set up the entire component the way i'm going to start with this is the way i usually start it's just going to be defining the public properties we need at the top so i've already referenced these inside the template which is public url and public slug and i'm also going to define some rules which is just within like a protected variable here protected array and these are the basic validation rules by convention livewire will actually use whatever rules are defined here match it by key to the public properties and then validate if you ask it to based on these rules which is really cool and i'll actually demonstrate this below so for url i want it to be required url and max length of 255. for the slug i want this to be nullable alpha dash because i don't want any spaces or any weird characters inside the slug unique for the links table and the slug column i don't know if that column should be defined here if it's necessary i think it's intelligent enough to match this key to the the column inside the database but i'm going to define it anyways i'm going to make it min of 3 so the length and also max of 100 so we have those now i also want to quickly just go ahead and define that reset form method before we jump into the save link method because i think that's simpler so what i want to do is just name it reset form and within here i want to call this reset which will reset the values within the public properties to whatever they are just by default which is empty and i also want to call this arrow reset validation because even though we may reset the values inside the public properties if there is a validation error already present on the ui and we just reset the values within those properties the validation errors won't actually disappear so it's really helpful that this method is provided now i want to actually define an updated method this is something also built into the livewire so you just pass in a property name i'm just going to call it property and you basically just include a this validate only here and pass in that property what will happen is any time one of these public properties are updated it'll actually run the validator right away in our case because we are binding wire to the to the model but with lazy it'll only validate when the cursor moves away from that text field it's not going to validate on every keystroke which is very annoying and also can get quite expensive on the back end i think because there's a ton of calls going back and forth so in my opinion it's just better to use lazy unless you need extreme precision so the only method method we have left to define here now is save link and this might get a little bit tricky let's just start with the basics i'm going to call this arrow validate this will actually validate using these rules i've defined up here like i explained before and then i want to create a link make sure that model is imported create i want to use the url we have inside the property so this url for the slug i want to use either this slug or string random 50 which i'll explain in a moment and i need to make sure that this is actually imported as well and lastly i want to use the user id of the current user so i could have created this through the user the authenticated user like as a relationship because authenticated user has a links relationship but i personally find it better to just link models together using just id columns if we're already creating them and so i'm just going to set this to off user id i believe there's a shorthand for this but i don't remember it and i need a semicolon here i'm going to return redirect to the index route so links okay so we can actually test it now so let's try a random string here and that should complain that that's not a url and it sure does we could put two characters in here so it triggers the validator to fail the slug must be at least three characters if we click reset it resets everything which is perfect if i go in here and do let's say google.com this is a test and create there we go we see a link was created with our custom slug let's try to create one with a url that exists so this is a test and we can already see we can't even submit actually it's already validated that the slug has already been taken so we won't be able to submit that because that slug already exists inside the table so i've actually just gone ahead and reduced this string random to 20. but so let's try let's try creating another one if i go and just create a facebook.com let's say facebook2.com create so it's creating this random slug now the reason i did this and i don't want to leave it this way is because this has a pretty decent probability of collision sooner or later maybe not if i'm the only user of this url shortener but at some point it probably would happen if you have more than one user if you're interested in kind of knowing some some of the math behind this i would look into the birthday problem that was really interesting to read about and and watch a couple videos about so the way we solve this is actually by hashing the id of the link we just created it's not the prettiest solution because it's actually two queries but if we just save this to link here use the string random 20 just temporarily and basically just do if not this slug if this slug is null we want to update the link specifically the slug column to the hash id let's make sure that's uh imported of the links id right so in this case it a hash id of the links id since ids increment and there only be one id this hash id will always be unique and there won't be collisions so in this case if we go now and create this and try again let's say google dot and click create we can now see we have a six character hash id and if you're interested that hash id is six characters because we've defined it as a length of six in here we're using the main connection here and that's why that's working the way it is so the create page is actually done believe it or not it's very simple but it is done so if we go to the link test and see if our crate test passed now we'll just try one can create link with slug let's try this one and it passes that's great so let's try one more just out of curiosity and it passes two so that's great looks like our create is done we can now move on to the edit page so we're going to go through very much like a similar process for the edit page although the first thing i want to do is make sure that our edit url is correct right the actual route because i noticed in the previous video we didn't actually include the link id in here for route model binding right so if we include this we can actually pass that into the controller which we can go ahead and do now this should be link and link and we could pass this like like so with link link and now we can go to the edit.blade.php and we can see it looks almost identical to what the create one looked like before we added all the html around it we're actually gonna go and just copy this because it's much simpler and and will save time it's almost identical so i'm gonna take this and replace the create component with it and in here it's important to also just pass in the link so you pass in an array as a second parameter so the key is the the name of the variable you want available inside your livewire component and then this is the actual thing the value let's refresh here and click again and now it looks like we have the the correct page of course nothing's coming up here because we haven't created a form yet but at least we know that we have the the layout mostly correct so let's get started on the actual component and of course this would be edit edit link.blade.php that's the livewire component we also want to open up the create link dotblade.php i'm just going to copy this because there is a lot of reusable code in there and paste that we do not need the reset button and we can rename this as save i'm going to keep calling this save link because it still makes sense in the update context and we can leave the url we can leave the slug because that will be updatable the one thing i need to add is actually a drop down for the is enabled because i want to be able to toggle that on and off so what i'm going to do is first create another div to basically just wrap all the html elements for the form and then add the label the select and the error parts to it so okay so what i've done is actually just created that div wrapper the label for the enabled i binded this select to the is underscore enabled public property that doesn't actually exist yet but we'll get to that i just dialed it with block margin top bottom of two with full rounded shadow and then borders and and other things that i kind of took from the breeze package although they don't actually include a select drop down which is interesting to me but i kind of improvised and made it look sort of similar and then i just included the error stuff below that so that should be fine now i think if we just reload the page it might work and it does of course this button needs to be moved a little bit and also there's no data coming through because obviously there's no actual component logic built yet but at least the form renders and it looks half decent i'm gonna fix this button now and then we could probably move on found the issue okay so i didn't actually close this div and that's why it's not acting correctly on the uh the button there so the first thing i'm gonna do just like the last time is actually define the public properties and i'm going to start with the link id i chose to make these camel case and i'll explain why in a second so i chose to make this camel case because i know that when i define the rules in here i kind of want to use this built-in functionality because i think it's really a clean way of validating within a live wire component but i need i'm pretty sure the keys need to match the the names of the public properties almost exactly i would think so i want to make them both camel case just to make sure that there's no issues there i'm not sure if this really badly breaks the convention of livewire or laravel but it's not my favorite thing to do okay so those are the rules i'm just going to go ahead and define that same updated method for validation i'm going to define a mount method so if you're not familiar with what mount is in the component life cycle i would very much recommend checking out the livewire documentation for that but basically this method is called when the component is mounted so early on in the life cycle and this is very good for us because this is where the link is passed in that i passed in through the edit link sorry through the edit blade.php file right here so that's where this enters the component and within here we could actually assign the different properties so this link id is equal to link id this url is equal to sorry link url this slug is equal to link slug now the alternative to this is actually just creating a link up here and assigning link this arrow link to link i prefer splitting it up because it's just cleaner on in the template side to have separate properties for each different column within the link model it's just a personal preference it would be cleaner inside the component itself to not have this split up separately but i actually like doing it this way okay so that's our mounted method now our data should be set using the passed in link and now we can actually go ahead and well actually before we do that maybe we could actually see the data pop up within the form and we sure do so this link is actually enabled if i refresh it's still enabled even if i set no obviously so it's loading the data correctly and these are also the correct data coming from the columns of that link and so we can actually just finish this up by defining that save link method and in here i'm just going to query for the link so link find or fail this link id for those of you wondering uh you can't really set a model to a public property from what i understand and so i think the best way is to actually query in the save method though i'm not 100 sure this is typically how i build livewire stuff and it's worked for me great so i'm going to keep doing it this way within here i'm just going to pass in this validate this will actually return the validated array of data so it'll update just using that array no need to over complicate things we've already done so up here and so right here i'll return a redirect to the index route which is just links and from here we just need to add one more check and we basically need to check that the slug that's passed in is unique against every single other link in the database other than its own so if a user is updating a link and they're submitting the same slug that the link already has saved in the database that should be fine but if the user updates the slug to something that's already existing in the database then that can't be allowed so what we need to do is basically check for uniqueness except for our own link so let's make a method that acts sort of like a custom validator and i'm just going to call it in here so if this check slug exists we need to return this add error which is uh built into live wire for the slug and that error should read this slug is already taken and this is a very handy little tool that comes with livewire uh you can just append to the airbag on your own so you don't need to rely on their validation that's that's provided with livewire this is really cool and in here we can define a method that's very simple so check slug exists and within here we can just query for a link where the slug is equal to this slug first and we return if if the link exists and the link id does not equal this link id so if the link exists and the link is not the link that we're currently editing that means that there is a collision and we can't allow that slug to be saved and that's when we add the error here to slug that's the key with the error this slug is already taken so if i go back to the page now actually let's go to the dashboard let's grab this this lug here let's edit this one and try to save it with this this slug is already taken perfect so that won't be allowed but if we just try our own custom one and save it'll actually update to that we can actually even update the url and that works and we can set this to disabled and you can see it says inactive here so everything works perfectly now let's also try this here if we go here notice that redirects is currently zero if we redirect to this oh we can't because it's actually disabled if we try this one for example which is also redirect zero let's try to redirect to this it'll take us to facebookto.com which obviously doesn't exist but you can see that redirects went up which is awesome so the next step for me outside of this video series would actually be just making this like a dynamic data table like you'd see in my one of my previous tutorials i've actually done two on data tables i think and that'd be a fun project i'd also would like to add like a search or something and maybe extend the the tracking of redirects but that's like a later project i think for now this would be a great replacement to the to my current url shortener and i'm going to deploy this and use it i think it'd be fine if you have any questions please leave them down below right before i end i'd actually like to run the entire test suite fingers crossed i hope everything passes looks like we have one failure can update link let's see what's happening there okay so it says that the it's trying to assert true here but it's not asserting true so i know for a fact that this link has an is enabled column so let's let's see what this link actually shows if we run this test here dd it out and it looks like that column's actually not showing up so my thinking is that the factory is not correct link factory and it's not there so if we just include is enabled here and set it by default to true because it defaults that way in the database and save this and rerun tests looks like all tests pass so that's great so that's it for this series thank you so much for watching i hope you learned something from it it was actually very difficult to get everything pieced together but i'm starting to get used to the whole youtube thing so if you found this useful have any questions any criticisms leave them below prs are welcome to this project if you really want to add to it and use it for yourself it'll be available and the github link is in the description below as always subscribing is the best way to support this channel i do plan on making more videos i find this to be a lot of fun so thank you for watching and i hope to see you in the next video
Info
Channel: David Grzyb
Views: 1,543
Rating: undefined out of 5
Keywords:
Id: QXREyrnKabU
Channel Id: undefined
Length: 28min 22sec (1702 seconds)
Published: Sat Jan 23 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.