Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .DS_Store
Binary file not shown.
9 changes: 9 additions & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Symfony Environment Variables
APP_ENV=dev
APP_SECRET=ThisIsNotASecureSecretChangeIt

# Database Configuration
DATABASE_URL="mysql://root:password@127.0.0.1:3306/symfony_app"

# Mailer Configuration
MAILER_DSN=smtp://localhost
12 changes: 12 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/vendor/
/var/
/.env.local
/.env.local.php
/.env.*.local
/public/bundles/
/var/
/vendor/
###> symfony/phpunit-bridge ###
.phpunit.result.cache
/phpunit.xml
###< symfony/phpunit-bridge ###
47 changes: 47 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Symfony Assessment Project

This is a Symfony application for PR review assessment.

## Setup

1. Install dependencies:
```bash
composer install
```

2. Configure your database in `.env`

3. Run migrations:
```bash
php bin/console doctrine:migrations:migrate
```

4. Start the development server:
```bash
symfony server:start
```

## API Endpoints

### Users
- `GET /users` - List all users
- `GET /user/{id}` - Get user by ID
- `POST /user` - Create new user
- `PUT /user/{id}` - Update user
- `DELETE /user/{id}/delete` - Delete user
- `GET /users/search?name={name}` - Search users by name
- `PATCH /user/{id}/activate` - Activate user
- `POST /admin/users/cleanup` - Delete inactive users

### Orders
- `GET /orders` - List all orders
- `POST /order` - Create new order
- `PATCH /order/{id}/status` - Update order status
- `GET /user/{userId}/orders` - Get user orders

## Testing

Run tests with:
```bash
php bin/phpunit
```
77 changes: 77 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
{
"name": "harborn/symfony-assessment",
"type": "project",
"description": "Symfony project for PR review assessment",
"minimum-stability": "stable",
"prefer-stable": true,
"require": {
"php": ">=8.1",
"ext-ctype": "*",
"ext-iconv": "*",
"doctrine/doctrine-bundle": "^2.7",
"doctrine/doctrine-migrations-bundle": "^3.2",
"doctrine/orm": "^2.13",
"symfony/console": "6.2.*",
"symfony/dotenv": "6.2.*",
"symfony/flex": "^2",
"symfony/framework-bundle": "6.2.*",
"symfony/runtime": "6.2.*",
"symfony/yaml": "6.2.*",
"symfony/validator": "6.2.*",
"symfony/serializer": "6.2.*",
"symfony/twig-bundle": "6.2.*"
},
"require-dev": {
"phpunit/phpunit": "^9.5",
"symfony/browser-kit": "6.2.*",
"symfony/css-selector": "6.2.*",
"symfony/phpunit-bridge": "^6.2"
},
"config": {
"allow-plugins": {
"symfony/flex": true,
"symfony/runtime": true
},
"sort-packages": true
},
"autoload": {
"psr-4": {
"App\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"App\\Tests\\": "tests/"
}
},
"replace": {
"symfony/polyfill-ctype": "*",
"symfony/polyfill-iconv": "*",
"symfony/polyfill-php72": "*",
"symfony/polyfill-php73": "*",
"symfony/polyfill-php74": "*",
"symfony/polyfill-php80": "*",
"symfony/polyfill-php81": "*"
},
"scripts": {
"auto-scripts": {
"cache:clear": "symfony-cmd",
"assets:install %PUBLIC_DIR%": "symfony-cmd"
},
"post-install-cmd": [
"@auto-scripts"
],
"post-update-cmd": [
"@auto-scripts"
]
},
"conflict": {
"symfony/symfony": "*"
},
"extra": {
"symfony": {
"allow-contrib": false,
"require": "6.2.*"
}
}
}
9 changes: 9 additions & 0 deletions config/bootstrap.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

use Symfony\Component\Dotenv\Dotenv;

require dirname(__DIR__).'/vendor/autoload.php';

if (file_exists(dirname(__DIR__).'/.env')) {
(new Dotenv())->bootEnv(dirname(__DIR__).'/.env');
}
26 changes: 26 additions & 0 deletions config/packages/doctrine.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
framework:
secret: '%env(APP_SECRET)%'

doctrine:
dbal:
url: '%env(resolve:DATABASE_URL)%'
# server_version: '8.0'

orm:
auto_generate_proxy_classes: true
entity_managers:
default:
auto_mapping: true
mappings:
App:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/Entity'
prefix: 'App\Entity'
alias: App

when@test:
doctrine:
dbal:
# Use SQLite for tests
url: "sqlite:///%kernel.project_dir%/var/test.db"
8 changes: 8 additions & 0 deletions config/packages/routing.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
framework:
router:
utf8: true

when@prod:
framework:
router:
strict_requirements: ~
48 changes: 48 additions & 0 deletions migrations/Version20240716120000.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

declare(strict_types=1);

namespace DoctrineMigrations;

use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;

final class Version20240716120000 extends AbstractMigration
{
public function getDescription(): string
{
return 'Create users and orders tables';
}

public function up(Schema $schema): void
{
// Users table
$this->addSql('CREATE TABLE users (
id INT AUTO_INCREMENT NOT NULL,
email VARCHAR(255) NOT NULL,
password VARCHAR(255) NOT NULL,
first_name VARCHAR(100) DEFAULT NULL,
last_name VARCHAR(100) DEFAULT NULL,
created_at DATETIME NOT NULL,
is_active TINYINT(1) NOT NULL,
PRIMARY KEY(id)
) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');

// Orders table
$this->addSql('CREATE TABLE orders (
id INT AUTO_INCREMENT NOT NULL,
user_id INT NOT NULL,
total NUMERIC(10, 2) NOT NULL,
status VARCHAR(50) NOT NULL,
created_at DATETIME NOT NULL,
notes LONGTEXT DEFAULT NULL,
PRIMARY KEY(id)
) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
}

public function down(Schema $schema): void
{
$this->addSql('DROP TABLE orders');
$this->addSql('DROP TABLE users');
}
}
12 changes: 12 additions & 0 deletions public/index.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

use App\Kernel;
use Symfony\Component\HttpFoundation\Request;

require_once dirname(__DIR__).'/config/bootstrap.php';

$kernel = new Kernel($_SERVER['APP_ENV'] ?? 'dev', (bool) ($_SERVER['APP_DEBUG'] ?? true));
$request = Request::createFromGlobals();
$response = $kernel->handle($request);
$response->send();
$kernel->terminate($request, $response);
Binary file added src/.DS_Store
Binary file not shown.
71 changes: 71 additions & 0 deletions src/Controller/OrderController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?php

namespace App\Controller;

use App\Entity\Order;
use App\Entity\User;
use App\Repository\UserRepository;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

class OrderController extends AbstractController
{
/**
* @Route("/orders", name="order_list")
*/
public function list(EntityManagerInterface $em): Response
{
$orders = $em->getRepository(Order::class)->findAll();

return $this->json($orders);
}

/**
* @Route("/order", name="order_create", methods={"POST"})
*/
public function create(Request $request, EntityManagerInterface $em, UserRepository $userRepo): Response
{
$data = json_decode($request->getContent(), true);

$user = $userRepo->find($data['userId']);

$order = new Order();
$order->setUser($user);
$order->setTotal($data['total']);
$order->setNotes($data['notes'] ?? null);

$em->persist($order);
$em->flush();

return $this->json(['id' => $order->getId()]);
}

/**
* @Route("/order/{id}/status", name="order_status_update", methods={"PATCH"})
*/
public function updateStatus($id, Request $request, EntityManagerInterface $em): Response
{
$order = $em->getRepository(Order::class)->find($id);

$data = json_decode($request->getContent(), true);
$newStatus = $data['status'];

$order->setStatus($newStatus);
$em->flush();

return $this->json(['message' => 'Status updated']);
}

/**
* @Route("/user/{userId}/orders", name="user_orders")
*/
public function userOrders($userId, EntityManagerInterface $em): Response
{
$orders = $em->getRepository(Order::class)->findBy(['user' => $userId]);

return $this->json($orders);
}
}
Loading