├── .gitignore
├── docker-compose.yml
├── src
├── Item.php
└── GildedRose.php
├── composer.json
├── Dockerfile
├── phpunit.xml
├── example.php
├── Makefile
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | # Composer
2 | /vendor/
3 | composer.lock
4 |
5 | # PHPUnit
6 | .phpunit.result.cache
7 | /coverage/
8 |
9 | # IDE
10 | .idea/
11 | .vscode/
12 | *.swp
13 | *.swo
14 | *~
15 |
16 | # OS
17 | .DS_Store
18 | Thumbs.db
19 |
20 | # Docker
21 | .docker/
22 |
23 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3.8'
2 |
3 | services:
4 | php:
5 | build:
6 | context: .
7 | dockerfile: Dockerfile
8 | container_name: gilded-rose-php
9 | volumes:
10 | - .:/app
11 | working_dir: /app
12 | stdin_open: true
13 | tty: true
14 |
--------------------------------------------------------------------------------
/src/Item.php:
--------------------------------------------------------------------------------
1 | name = $name;
14 | $this->sellIn = $sellIn;
15 | $this->quality = $quality;
16 | }
17 |
18 | public function __toString(): string
19 | {
20 | return "{$this->name}, {$this->sellIn}, {$this->quality}";
21 | }
22 | }
23 |
24 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "gilded-rose/kata",
3 | "description": "Gilded Rose Kata in PHP",
4 | "type": "project",
5 | "require": {
6 | "php": ">=8.2"
7 | },
8 | "require-dev": {
9 | "phpunit/phpunit": "^10.0"
10 | },
11 | "autoload": {
12 | "psr-4": {
13 | "GildedRose\\": "src/"
14 | }
15 | },
16 | "autoload-dev": {
17 | "psr-4": {
18 | "GildedRose\\Tests\\": "tests/"
19 | }
20 | },
21 | "scripts": {
22 | "test": "phpunit"
23 | }
24 | }
25 |
26 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.2-cli
2 |
3 | # Install system dependencies
4 | RUN apt-get update && apt-get install -y \
5 | git \
6 | unzip \
7 | && rm -rf /var/lib/apt/lists/*
8 |
9 | # Install Composer
10 | COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
11 |
12 | # Set working directory
13 | WORKDIR /app
14 |
15 | # Copy composer files
16 | COPY composer.json ./
17 |
18 | # Install PHP dependencies
19 | RUN composer install --no-interaction --prefer-dist --optimize-autoloader
20 |
21 | # Copy application files
22 | COPY . .
23 |
24 | CMD ["bash"]
25 |
26 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 | tests
11 |
12 |
13 |
14 |
15 | src
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/example.php:
--------------------------------------------------------------------------------
1 | updateQuality();
35 | }
36 |
37 | echo "Ejecución completada con éxito! ✓\n";
38 |
39 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: help up down build shell test example install clean
2 |
3 | # Colors for output
4 | BLUE := \033[0;34m
5 | GREEN := \033[0;32m
6 | YELLOW := \033[0;33m
7 | NC := \033[0m # No Color
8 |
9 | help: ## Muestra esta ayuda
10 | @echo "$(BLUE)Gilded Rose - Comandos disponibles:$(NC)"
11 | @echo ""
12 | @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf " $(GREEN)%-15s$(NC) %s\n", $$1, $$2}'
13 | @echo ""
14 |
15 | up: ## Levanta el contenedor de Docker
16 | @echo "$(BLUE)Levantando contenedor...$(NC)"
17 | docker-compose up -d
18 | @echo "$(GREEN)✓ Contenedor levantado$(NC)"
19 |
20 | down: ## Detiene y elimina el contenedor
21 | @echo "$(BLUE)Deteniendo contenedor...$(NC)"
22 | docker-compose down
23 | @echo "$(GREEN)✓ Contenedor detenido$(NC)"
24 |
25 | build: ## Construye la imagen de Docker
26 | @echo "$(BLUE)Construyendo imagen...$(NC)"
27 | docker-compose build
28 | @echo "$(GREEN)✓ Imagen construida$(NC)"
29 |
30 | shell: ## Abre una terminal dentro del contenedor
31 | @echo "$(BLUE)Abriendo shell en el contenedor...$(NC)"
32 | docker-compose exec php bash
33 |
34 | test: ## Ejecuta los tests con PHPUnit
35 | @echo "$(BLUE)Ejecutando tests...$(NC)"
36 | docker-compose exec php vendor/bin/phpunit
37 | @echo "$(GREEN)✓ Tests completados$(NC)"
38 |
39 | example: ## Ejecuta el ejemplo de funcionamiento
40 | @echo "$(BLUE)Ejecutando ejemplo...$(NC)"
41 | @echo ""
42 | docker-compose exec php php example.php
43 |
44 | install: ## Instala las dependencias de Composer
45 | @echo "$(BLUE)Instalando dependencias...$(NC)"
46 | docker-compose exec php composer install
47 | @echo "$(GREEN)✓ Dependencias instaladas$(NC)"
48 |
49 | clean: down ## Limpia contenedores, volúmenes e imágenes
50 | @echo "$(BLUE)Limpiando recursos de Docker...$(NC)"
51 | docker-compose down -v --rmi local
52 | @echo "$(GREEN)✓ Limpieza completada$(NC)"
53 |
54 |
--------------------------------------------------------------------------------
/src/GildedRose.php:
--------------------------------------------------------------------------------
1 | items = $items;
18 | }
19 |
20 | public function updateQuality(): void
21 | {
22 | foreach ($this->items as $item) {
23 | if ($item->name != 'Aged Brie' && $item->name != 'Backstage passes to a TAFKAL80ETC concert') {
24 | if ($item->quality > 0) {
25 | if ($item->name != 'Sulfuras, Hand of Ragnaros') {
26 | $item->quality = $item->quality - 1;
27 | }
28 | }
29 | } else {
30 | if ($item->quality < 50) {
31 | $item->quality = $item->quality + 1;
32 | if ($item->name == 'Backstage passes to a TAFKAL80ETC concert') {
33 | if ($item->sellIn < 11) {
34 | if ($item->quality < 50) {
35 | $item->quality = $item->quality + 1;
36 | }
37 | }
38 | if ($item->sellIn < 6) {
39 | if ($item->quality < 50) {
40 | $item->quality = $item->quality + 1;
41 | }
42 | }
43 | }
44 | }
45 | }
46 |
47 | if ($item->name != 'Sulfuras, Hand of Ragnaros') {
48 | $item->sellIn = $item->sellIn - 1;
49 | }
50 |
51 | if ($item->sellIn < 0) {
52 | if ($item->name != 'Aged Brie') {
53 | if ($item->name != 'Backstage passes to a TAFKAL80ETC concert') {
54 | if ($item->quality > 0) {
55 | if ($item->name != 'Sulfuras, Hand of Ragnaros') {
56 | $item->quality = $item->quality - 1;
57 | }
58 | }
59 | } else {
60 | $item->quality = $item->quality - $item->quality;
61 | }
62 | } else {
63 | if ($item->quality < 50) {
64 | $item->quality = $item->quality + 1;
65 | }
66 | }
67 | }
68 | }
69 | }
70 | }
71 |
72 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Gilded Rose Kata - PHP
2 |
3 | ## ¿En qué consiste?
4 |
5 | Bienvenido a **Gilded Rose**, una pequeña posada con una ubicación privilegiada en una ciudad prominente, regentada por la amable posadera Allison. También compra y vende mercancías de la mejor calidad.
6 |
7 | Desafortunadamente, los productos van bajando de calidad a medida que se aproxima su fecha de venta. Tienes un sistema que actualiza el inventario automáticamente. Fue desarrollado por un tipo razonable llamado Leeroy, que ahora se dedica a nuevas aventuras.
8 |
9 | Tu tarea es **añadir una nueva funcionalidad** al sistema, pero hay un problema: el código es un desastre de `ifs` anidados que nadie entiende bien. Además, hay un goblin en la esquina que te apuñalará si tocas la clase `Item`.
10 |
11 | ### El sistema
12 |
13 | Cada artículo tiene tres propiedades:
14 | - **name**: Nombre del artículo
15 | - **sellIn**: Días restantes para venderlo
16 | - **quality**: Valor de calidad (0-50)
17 |
18 | ### Reglas del negocio:
19 |
20 | 1. Al final de cada día, `sellIn` y `quality` disminuyen
21 | 2. Pasada la fecha de venta (`sellIn < 0`), la calidad se degrada el doble de rápido
22 | 3. La calidad nunca es negativa ni mayor a 50
23 | 4. **"Aged Brie"** incrementa su calidad con el tiempo (mejora como el vino)
24 | 5. **"Sulfuras"** nunca cambia (es un artículo legendario)
25 | 6. **"Backstage passes"** (pases para conciertos):
26 | - +2 calidad cuando quedan ≤10 días
27 | - +3 calidad cuando quedan ≤5 días
28 | - Calidad = 0 después del concierto (nadie los quiere)
29 |
30 | ### Tu misión:
31 |
32 | Refactorizar el código legacy para que sea mantenible y añadir soporte para artículos **"Conjured"** (conjurados), que degradan su calidad el doble de rápido que los artículos normales.
33 |
34 | ⚠️ **RESTRICCIÓN: NO modificar la clase `Item`** (el goblin te está vigilando)
35 |
36 | ## Cómo empezar
37 |
38 | ```bash
39 | # 1. Clonar y entrar
40 | git clone
41 | cd gilded-rose-php
42 |
43 | # 2. Levantar Docker
44 | make up
45 |
46 | # 3. Ejecutar el ejemplo
47 | make example
48 |
49 | # 4. Ejecutar los tests
50 | make test
51 |
52 | # 5. Cuando termines
53 | make down
54 | ```
55 |
56 | ## Comandos disponibles
57 |
58 | El proyecto incluye un `Makefile` con los siguientes comandos:
59 |
60 | | Comando | Descripción |
61 | |---------|-------------|
62 | | `make help` | Muestra todos los comandos disponibles |
63 | | `make up` | Levanta el contenedor de Docker |
64 | | `make down` | Detiene y elimina el contenedor |
65 | | `make build` | Construye la imagen de Docker |
66 | | `make shell` | Abre una terminal dentro del contenedor |
67 | | `make test` | Ejecuta los tests con PHPUnit |
68 | | `make example` | Ejecuta el ejemplo de funcionamiento |
69 | | `make install` | Instala las dependencias de Composer |
70 | | `make clean` | Limpia contenedores, volúmenes e imágenes |
71 |
72 | ### Flujo de trabajo típico
73 |
74 | ```bash
75 | # Iniciar el proyecto
76 | make up
77 |
78 | # Ver el ejemplo funcionando
79 | make example
80 |
81 | # Ejecutar los tests
82 | make test
83 |
84 | # Entrar al contenedor para trabajar
85 | make shell
86 |
87 | # Cuando termines
88 | make down
89 | ```
90 |
--------------------------------------------------------------------------------