Skip to content

Commit ccde693

Browse files
committed
Add test
1 parent 8db386c commit ccde693

File tree

9 files changed

+204
-1
lines changed

9 files changed

+204
-1
lines changed

src/Turbo/CONTRIBUTING.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ Start a Mercure Hub:
77
-e MERCURE_PUBLISHER_JWT_KEY='!ChangeMe!' \
88
-e MERCURE_SUBSCRIBER_JWT_KEY='!ChangeMe!' \
99
-p 3000:3000 \
10-
dunglas/mercure caddy run -config /etc/caddy/Caddyfile.dev
10+
dunglas/mercure caddy run --config /etc/caddy/Caddyfile.dev
1111

1212
Install the test app:
1313

@@ -29,6 +29,7 @@ Start the test app:
2929
- `http://localhost:8000/authors`: broadcast
3030
- `http://localhost:8000/artists`: broadcast
3131
- `http://localhost:8000/songs`: broadcast
32+
- `http://localhost:8000/cart_products`: broadcast
3233

3334
## Run tests
3435

src/Turbo/tests/BroadcastTest.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,4 +104,19 @@ public function testBroadcastWithProxy(): void
104104
// this part is from the stream template
105105
$this->assertSelectorWillContain('#artists', ', updated)');
106106
}
107+
108+
public function testBroadcastWithCompositePrimaryKey(): void
109+
{
110+
($client = self::createPantherClient())->request('GET', '/cartProducts');
111+
112+
// submit first to create the entities
113+
$client->submitForm('Submit', ['title' => 'product 1']);
114+
$this->assertSelectorWillContain('#cartProducts', 'product 1');
115+
116+
// submit again to update the quantity
117+
$client->submitForm('Submit');
118+
$this->assertSelectorWillContain('#cartProducts', '2x product 1');
119+
// this part is from the stream template
120+
$this->assertSelectorWillContain('#cartProducts', ', updated)');
121+
}
107122
}

src/Turbo/tests/app/Entity/Cart.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace App\Entity;
13+
14+
use Doctrine\DBAL\Types\Types;
15+
use Doctrine\ORM\Mapping as ORM;
16+
17+
/**
18+
* @author Jason Schilling <[email protected]>
19+
*/
20+
#[ORM\Entity]
21+
class Cart
22+
{
23+
#[ORM\Id]
24+
#[ORM\GeneratedValue(strategy: 'AUTO')]
25+
#[ORM\Column(type: Types::INTEGER)]
26+
public ?int $id = null;
27+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace App\Entity;
13+
14+
use Doctrine\DBAL\Types\Types;
15+
use Doctrine\ORM\Mapping as ORM;
16+
use Symfony\UX\Turbo\Attribute\Broadcast;
17+
18+
/**
19+
* @author Jason Schilling <[email protected]>
20+
*/
21+
#[Broadcast]
22+
#[ORM\Entity]
23+
class CartProduct
24+
{
25+
#[ORM\Id]
26+
#[ORM\ManyToOne(targetEntity: Cart::class)]
27+
#[ORM\JoinColumn(nullable: false, onDelete: 'CASCADE')]
28+
public ?Cart $cart = null;
29+
30+
#[ORM\Id]
31+
#[ORM\ManyToOne(targetEntity: Product::class)]
32+
#[ORM\JoinColumn(nullable: false, onDelete: 'CASCADE')]
33+
public ?Product $product = null;
34+
35+
#[ORM\Column(type: Types::INTEGER)]
36+
public int $quantity = 1;
37+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace App\Entity;
13+
14+
use Doctrine\DBAL\Types\Types;
15+
use Doctrine\ORM\Mapping as ORM;
16+
17+
/**
18+
* @author Jason Schilling <[email protected]>
19+
*/
20+
#[ORM\Entity]
21+
class Product
22+
{
23+
#[ORM\Id]
24+
#[ORM\GeneratedValue(strategy: 'AUTO')]
25+
#[ORM\Column(type: Types::INTEGER)]
26+
public ?int $id = null;
27+
28+
#[ORM\Column]
29+
public string $title = '';
30+
}

src/Turbo/tests/app/Kernel.php

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313

1414
use App\Entity\Artist;
1515
use App\Entity\Book;
16+
use App\Entity\Cart;
17+
use App\Entity\CartProduct;
18+
use App\Entity\Product;
1619
use App\Entity\Song;
1720
use Composer\InstalledVersions;
1821
use Doctrine\Bundle\DoctrineBundle\DoctrineBundle;
@@ -137,6 +140,7 @@ protected function configureRoutes(RoutingConfigurator $routes): void
137140
$routes->add('artists', '/artists')->controller('kernel::artists');
138141
$routes->add('artist', '/artists/{id}')->controller('kernel::artist');
139142
$routes->add('artist_from_song', '/artistFromSong')->controller('kernel::artistFromSong');
143+
$routes->add('cart_products', '/cartProducts')->controller('kernel::cartProducts');
140144
}
141145

142146
public function getProjectDir(): string
@@ -305,4 +309,55 @@ public function artistFromSong(Request $request, EntityManagerInterface $doctrin
305309
'song' => $song,
306310
]));
307311
}
312+
313+
public function cartProducts(Request $request, EntityManagerInterface $doctrine, Environment $twig): Response
314+
{
315+
$cartProduct = null;
316+
if ($request->isMethod('POST')) {
317+
$cartId = $request->get('cartId');
318+
$productId = $request->get('productId');
319+
320+
if (!$cartId || !$productId) {
321+
$cart = new Cart();
322+
323+
$product = new Product();
324+
325+
if ($title = $request->get('title')) {
326+
$product->title = $title;
327+
}
328+
329+
$cartProduct = new CartProduct();
330+
$cartProduct->cart = $cart;
331+
$cartProduct->product = $product;
332+
$cartProduct->quantity = 1;
333+
334+
$doctrine->persist($cart);
335+
$doctrine->persist($product);
336+
$doctrine->persist($cartProduct);
337+
$doctrine->flush();
338+
} else {
339+
$cartProduct = $doctrine->find(CartProduct::class, [$cartId, $productId]);
340+
341+
if (!$cartProduct) {
342+
throw new NotFoundHttpException();
343+
}
344+
345+
++$cartProduct->quantity;
346+
347+
if ($remove = $request->get('remove')) {
348+
$doctrine->remove($cartProduct);
349+
$doctrine->remove($cartProduct->product); // for cleanup
350+
$doctrine->remove($cartProduct->cart); // for cleanup
351+
} else {
352+
$doctrine->persist($cartProduct);
353+
}
354+
355+
$doctrine->flush();
356+
}
357+
}
358+
359+
return new Response($twig->render('cart_products.html.twig', [
360+
'cartProduct' => $cartProduct,
361+
]));
362+
}
308363
}

src/Turbo/tests/app/templates/base.html.twig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
<li><a href="{{ path('books') }}">Books (broadcast)</a></li>
1515
<li><a href="{{ path('songs') }}">Songs (broadcast)</a></li>
1616
<li><a href="{{ path('artists') }}">Artists (broadcast)</a></li>
17+
<li><a href="{{ path('cart_products') }}">CartProducts (broadcast)</a></li>
1718
</ul>
1819
</nav>
1920

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
2+
{% block create %}
3+
<turbo-stream action="append" target="cart_products">
4+
<template>
5+
<div id="{{ 'cart_product_' ~ id }}">{{ entity.quantity }}x {{ entity.product.title }} (cart: {{ entity.cart.id }}, product: {{ entity.product.id }})</div>
6+
</template>
7+
</turbo-stream>
8+
{% endblock %}
9+
10+
{% block update %}
11+
<turbo-stream action="update" target="{{ 'cart_product_' ~ id }}">
12+
<template>
13+
{{ entity.quantity }}x {{ entity.product.title }} (cart: {{ entity.cart.id }}, product: {{ entity.product.id }}, updated)
14+
</template>
15+
</turbo-stream>
16+
{% endblock %}
17+
18+
{% block remove %}
19+
<turbo-stream action="remove" target="{{ 'cart_product_' ~ id }}"></turbo-stream>
20+
{% endblock %}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{% extends 'base.html.twig' %}
2+
3+
{% block body %}
4+
<h1>Create Cart, Product and CartProduct, increase quantity on update</h1>
5+
6+
<div id="cart_products" {{ turbo_stream_listen('App\\Entity\\CartProducts') }}></div>
7+
8+
<turbo-frame id="api">
9+
<form method="post" enctype="application/x-www-form-urlencoded">
10+
<input placeholder="Title" name="title">
11+
<input placeholder="Cart ID" name="cartId" value="{{ cartProduct ? cartProduct.cart.id }}">
12+
<input placeholder="Product ID" name="productId" value="{{ cartProduct ? cartProduct.product.id }}">
13+
<label><input type="checkbox" name="remove" value="remove"> Remove</label>
14+
<button>Submit</button>
15+
</form>
16+
</turbo-frame>
17+
{% endblock %}

0 commit comments

Comments
 (0)