This course is still being released! Check back later for more chapters.

Get Notified About this Course!

We will send you messages regarding this course only
and nothing else, we promise.
You can unsubscribe anytime by emailing us at:
privacy@symfonycasts.com
Login to bookmark this video
Buy Access to Course
05.

Dynamic Data

|

Share this awesome video!

|

Keep on Learning!

With a Subscription, click any sentence in the script to jump to that part of the video!

Login Subscribe

Okay! We made our first API request! This generates a unique checkout URL for our customer and opens the LemonSqueezy checkout page so they can buy the product. But when we set this up, we hard-coded a lot of things. It’s time to make it dynamic!

Use Dynamic Data in the Checkout Object

Let's start with the Store ID. That's unique for both our test and live environments, so it makes sense to set it as an environment variable. Open the .env file and, below the LEMON_SQUEEZY_API_KEY, write LEMON_SQUEEZY_STORE_ID= and set that to the store ID value. You can find that in OrderController.php.

35 lines | .env
// ... lines 1 - 17
LEMON_SQUEEZY_STORE_ID=132127
// ... lines 19 - 35

Now, in config/services.yaml, under parameters, add a new one - env(LEMON_SQUEEZY_STORE_ID) - and set that to %env(LEMON_SQUEEZY_STORE_ID)%’. Back in our controller, replace the ID value with $this->getParameter('env(LEMON_SQUEEZY_STORE_ID)').

26 lines | config/services.yaml
// ... lines 1 - 5
parameters:
env(LEMON_SQUEEZY_STORE_ID): '%env(LEMON_SQUEEZY_STORE_ID)%'
// ... lines 8 - 26

Store Variant IDs in the Database

For the variant ID, let's create a new field on the Product entity. At your terminal, run:

bin/console make:entity

Update the Product entity, and call the new field lsVariantId. This will be a string, with a default field length, and let's make it "nullable". Press Enter to finish and then head over to src/Entity/Product.php to see our changes. If we scroll down... ah, there it is! We should probably make this unique as well. Looking good! Down here, we can see that it also created a getter and setter. Convenient!

112 lines | src/Entity/Product.php
// ... lines 1 - 9
class Product
{
// ... lines 12 - 31
#[ORM\Column(length: 255, unique: true, nullable: true)]
private ?string $lsVariantId = null;
// ... lines 34 - 99
public function getLsVariantId(): ?string
{
return $this->lsVariantId;
}
public function setLsVariantId(?string $lsVariantId): static
{
$this->lsVariantId = $lsVariantId;
return $this;
}
}

Now, back in our terminal, create a migration with:

bin/console make:migration

Let's check it out! In migrations/... down here... it looks like a new column was added. Nice! Up here, we can add a description:

Add a column to store the LS variant ID on Product.

Back in our terminal, run the migration with:

bin/console doctrine:migrations:migrate

Now, in src/DataFixtures/AppFixtures.php, set our new field to the variant ID from the LemonSqueezy dashboard. You can find that by clicking on "Store", "Products", the three dots at the end of our product here, and selecting "Copy variant ID". Paste that and... tada! The first one is done! But what kind of designer lemonade stand would we be if we only had one kind of lemonade to choose from? Let's add more based on our fixtures!

Copy this description and, back in our dashboard, create a new product. We'll call this one "Watermelon E-Lemonade" and paste. Set the price to "$1.99", add an image, and "Publish product". Copy our new product's variant ID and add that to our product in AppFixtures.php. Awesome! Let's do the same thing for the next four products.

66 lines | src/DataFixtures/AppFixtures.php
// ... lines 1 - 9
class AppFixtures extends Fixture
{
public function load(ObjectManager $manager): void
{
// ... lines 14 - 19
ProductFactory::new()->create([
// ... lines 21 - 24
'lsVariantId' => '737914',
]);
ProductFactory::new()->create([
// ... lines 28 - 31
'lsVariantId' => '737915',
]);
// ... lines 34 - 63
}
}

Done! Now let’s reload the fixtures with:

bin/console doctrine:fixtures:load

Back in the controller, inside createLsCheckoutUrl(), retrieve products in the shopping cart with $products = $cart->getProducts(). And we'll set $variantId to $products[0]->getLsVariantId() for now. Finally, below $response, set the variant ID to a $variantId variable.

103 lines | src/Controller/OrderController.php
// ... lines 1 - 13
class OrderController extends AbstractController
{
// ... lines 16 - 66
private function createLsCheckoutUrl(HttpClientInterface $lsClient, ShoppingCart $cart): string
{
// ... lines 69 - 72
$products = $cart->getProducts();
$variantId = $products[0]->getLsVariantId();
// ... line 75
$response = $lsClient->request(Request::METHOD_POST, 'checkouts', [
'json' => [
'data' => [
// ... line 79
'relationships' => [
// ... lines 81 - 86
'variant' => [
'data' => [
// ... line 89
'id' => $variantId,
],
],
],
],
],
]);
// ... lines 97 - 100
}
}

Set the Correct Quantity

Okay, let's try to check out! Go back to the homepage and choose a new product this time. Set the quantity to "2", add it to the cart, then click the checkout button. Nice! We're on the checkout page, and this is the correct product but... not the correct quantity.

To fix that, back in our code, under type, add attributes... checkout_data... variant_quantities... another empty array, and inside that, write variant_id => $variantId and quantity => $quantity. Above, under the variantId, add $quantity = $cart->getProductQuantity() with $products[0] as the argument. If we go to the cart page and click the "checkout" button again... yes! We have the correct product and the correct quantity!

114 lines | src/Controller/OrderController.php
// ... lines 1 - 74
$quantity = $cart->getProductQuantity($products[0]);
// ... line 76
$response = $lsClient->request(Request::METHOD_POST, 'checkouts', [
'json' => [
'data' => [
// ... line 80
'attributes' => [
'checkout_data' => [
'variant_quantities' => [
[
'variant_id' => $variantId,
'quantity' => $quantity,
],
],
],
],
// ... lines 91 - 104
],
],
]);
// ... lines 108 - 111
}
// ... lines 113 - 114

Pre-fill User Data

If I scroll up... hm... where did this email come from? I'm an authenticated LemonSqueezy store owner, so this is pre-filled for me. But what if I try to check out as a customer in incognito mode? I'll open a new tab in incognito mode, log in again with lemon@example.com / lemonpass as the password. Now choose a product, quantity, add it to the cart, click "checkout", and... aha! The user data is empty! The user can just fill this in themselves, so it's not a big deal, but I bet we can save them some time and pre-fill this from our app, since they already shared their name and email when they signed up. Let's do it!

Over in OrderController::checkout(), add a new argument - #[CurrentUser] ?User $user - and below, pass $user to createLsCheckoutUrl(). Down here, in that method, add a third argument: ?User $user.

117 lines | src/Controller/OrderController.php
// ... lines 1 - 12
use Symfony\Component\Security\Http\Attribute\CurrentUser;
// ... lines 14 - 15
class OrderController extends AbstractController
{
// ... lines 18 - 57
#[Route('/checkout', name: 'app_order_checkout')]
public function checkout(
// ... lines 60 - 62
#[CurrentUser] ?User $user,
): Response {
$lsCheckoutUrl = $this->createLsCheckoutUrl($lsClient, $cart, $user);
// ... lines 66 - 67
}
// ... line 69
private function createLsCheckoutUrl(HttpClientInterface $lsClient, ShoppingCart $cart, ?User $user): string
{
// ... lines 72 - 114
}
}

Below $quantity, add $attributes = and set it to the array of attributes from the request options. We can copy and paste this to make it easy.

119 lines | src/Controller/OrderController.php
// ... lines 1 - 69
private function createLsCheckoutUrl(HttpClientInterface $lsClient, ShoppingCart $cart, ?User $user): string
{
// ... lines 72 - 79
$attributes = [
// ... lines 81 - 88
];
// ... line 90
$response = $lsClient->request(Request::METHOD_POST, 'checkouts', [
'json' => [
'data' => [
'type' => 'checkouts',
'attributes' => $attributes,
// ... lines 96 - 109
],
],
]);
// ... lines 113 - 116
}
// ... lines 118 - 119

We'll set this to $attributes, and up here, add if ($user). Inside, write $attributes['checkout_data']['email'] = $user->getEmail(). And below, $attributes['checkout_data']['name'] = $user->getFirstName().

123 lines | src/Controller/OrderController.php
// ... lines 1 - 69
private function createLsCheckoutUrl(HttpClientInterface $lsClient, ShoppingCart $cart, ?User $user): string
{
// ... lines 72 - 89
if ($user) {
$attributes['checkout_data']['email'] = $user->getEmail();
$attributes['checkout_data']['name'] = $user->getFirstName();
}
// ... lines 94 - 120
}
// ... lines 122 - 123

Perfect! Let's try checking out in incognito mode again. Go back to the homepage, click on the cart where we already have two items waiting, click the checkout button, and... the user data is pre-filled! Awesome!

So far, we've only tried purchasing one flavor of lemonade at a time. Let's try to buy more than one type next.