Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 25fff49

Browse files
Merge branch 'finalize-crud-docker' into develop
2 parents 738aaf0 + 7cf52e9 commit 25fff49

File tree

15 files changed

+933
-150
lines changed

15 files changed

+933
-150
lines changed

‎.docker/db/dump.sql‎

Lines changed: 30 additions & 57 deletions
Large diffs are not rendered by default.

‎README.md‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ For me, on WSL2,
3232
- It is automatically up as running `docker-compose up -d` above.
3333
- If you need to persist data continually, just uncomment `# ./.docker/db/data:/var/lib/mysql` AND comment `./.docker/db/dump.sql:/docker-entrypoint-initdb.d/dump.sql` on the docker-compose.yml.
3434
- The transaction isolation level is at 'READ-COMMITTED' on the docker-compose.yml.
35+
- If you consider the safety of 'gap-lock' or something, set it to 'REPEATABLE-READ' on the docker-compose.yml,
3536

3637
## Debugging
3738
On the 'docker-compose.yml',
@@ -46,6 +47,30 @@ Additionally, set the port to be 9002.
4647
## Test APIs
4748
Postman API files are on `./reference/postman`
4849

50+
## PHP Source Codes
51+
52+
These are what I have done and they all are on `./reference/postman`.
53+
54+
```
55+
Api/Auth/LoginController/login
56+
Api/CourseController/index (Get all paginated courses, TO DO : check paginated parameters)
57+
Api/CourseController/delete (Admin : activate course)
58+
Api/CourseController/restore (Admin : deactivate course)
59+
Api/LessonController/store (Lesson : Start, End)
60+
```
61+
62+
The term "NOT exist" means it could be soft-deleted or could NOT exist.
63+
```json
64+
{
65+
"message": "The given data was invalid.",
66+
"errors": {
67+
"course_id": [
68+
"The course_id (course id) does NOT exist."
69+
]
70+
}
71+
}
72+
```
73+
4974
## Test Codes
5075

5176
T.T. Not yet.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
namespace App\Exceptions\database;
4+
5+
use Exception;
6+
7+
class NotUniqueException extends \RuntimeException
8+
{
9+
public function __construct($message = null)
10+
{
11+
$message = $message ?: 'Not unique data.';
12+
parent::__construct($message, 409);
13+
}
14+
15+
}

‎app/Http/Controllers/Api/CourseController.php‎

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,22 +40,24 @@ public function delete($id)
4040
try {
4141

4242
// These are all "Soft Delete".
43-
Course::find($id)->delete();
44-
Enrollment::where('course_id', $id)->delete();
45-
Lesson::whereIn('enrollment_id', Enrollment::where('course_id', $id)->get()->pluck('id')->toArray())->delete();
43+
Course::query()->where('id', $id)->delete();
44+
Enrollment::query()->where('course_id', $id)->delete();
45+
Lesson::query()->whereIn('enrollment_id',
46+
Enrollment::withTrashed()->where('course_id', $id)->get()->pluck('id')->toArray())->delete();
4647

4748
DB::commit();
4849

49-
}catch (\Throwable $e){
50+
}
51+
catch (\Throwable $e){
5052
DB::rollBack();
5153
throw $e;
5254
}
53-
return response([], 200);
55+
return response(null, 200);
5456
}
5557

5658
/**
5759
*
58-
* 관리자가 Course 를 활성화 할 경우. (Middleware 에서 현재 사용자가 Admin 으로 되어야 함.)
60+
* 관리자가 Course 를 활성화 할 경우. (Middleware 에서 현재 사용자가 Admin 으로 되어야 함.)
5961
* @param $id
6062
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response
6163
* @throws \Throwable
@@ -66,9 +68,10 @@ public function restore($id)
6668

6769
try {
6870

69-
Course::find($id)->restore();
70-
Enrollment::where('course_id', $id)->restore();
71-
Lesson::whereIn('enrollment_id', Enrollment::where('course_id', $id)->get()->pluck('id')->toArray())->restore();
71+
Course::withTrashed()->where('id', $id)->restore();
72+
Enrollment::withTrashed()->where('course_id', $id)->restore();
73+
Lesson::withTrashed()->whereIn('enrollment_id',
74+
Enrollment::withTrashed()->where('course_id', $id)->get()->pluck('id')->toArray())->restore();
7275

7376
DB::commit();
7477

‎app/Http/Controllers/Api/LessonController.php‎

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55

66
use App\Exceptions\database\ForeignKeyException;
7+
use App\Exceptions\database\NotUniqueException;
78
use App\Exceptions\database\RowNotFoundException;
89
use App\Http\Controllers\Controller;
910
use App\Http\DTOs\LessonStoreDTO;
@@ -31,19 +32,42 @@ public function store(LessonStoreRequest $request)
3132

3233
$enrollment = Enrollment::getOne($lessonStoreDTO->getCourseId(), $lessonStoreDTO->getStudentId());
3334
if(!$enrollment){
34-
throw new RowNotFoundException("Couldn't find the enrollment. (Course ID : " . $lessonStoreDTO->getCourseId() . ", Student ID : " . $lessonStoreDTO->getStudentId() . ")");
35+
// 관리자가 CourseController 에서 Soft Delete 를 했다면 여기로 옴.
36+
throw new RowNotFoundException("The enrollment is NOT available. (Course ID : " . $lessonStoreDTO->getCourseId() . ", Student ID : " . $lessonStoreDTO->getStudentId() . ")");
3537
}
3638

37-
Lesson::create([
38-
'enrollment_id' => $enrollment->id,
39-
'status' => $lessonStoreDTO->getStatus(),
40-
'result' => $lessonStoreDTO->getResult(),
41-
'recording' => $lessonStoreDTO->getRecording()
42-
]);
39+
try {
40+
41+
$lesson = Lesson::query()->where('enrollment_id', $enrollment->id)
42+
->where('status', $lessonStoreDTO->getStatus())->first();
43+
if($lesson){
44+
throw new NotUniqueException("Enrollment ID : " . $enrollment->id . " has already been " . strtolower($lessonStoreDTO->getStatus()) . "ed.");
45+
}
46+
47+
$lesson = Lesson::query()->create([
48+
'enrollment_id' => $enrollment->id,
49+
'status' => $lessonStoreDTO->getStatus(),
50+
'result' => $lessonStoreDTO->getResult(),
51+
'recording' => $lessonStoreDTO->getRecording()
52+
]);
53+
}catch (\Throwable $e){
54+
55+
$matches = array();
56+
57+
// 상기 Lesson::query()->where 문이 진행되는 동안, 다른 Transaction 에서 이미 등록한 경우.
58+
// SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '3-Start' for key
59+
// 에서 3은 id / 하이픈 뒤는 Status
60+
if($e->getCode() == "23000" && preg_match('/Duplicate entry \'[0-9]+?-(Start|End)\'/', $e->getMessage(), $matches)){
61+
throw new NotUniqueException("Enrollment ID : " . $enrollment->id . " has already been " . strtolower($matches[1]) . "ed.");
62+
}else{
63+
throw $e;
64+
}
65+
66+
}
4367

4468
// 이메일 발송의 경우 laravel-queue 를 사용하여 구현. (Dockerfile 에서 supervisor 를 설치하여 이를 관리 (동시에 몇 개를 실행해야 할 지, 실패 시 재시도 횟수 등) 해야 함.)
4569

46-
return response()->json(null, 201);
70+
return response()->json($lesson, 201);
4771
}
4872

4973
}

‎app/Http/DTOs/CourseIndexDTO.php‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77

88
class CourseIndexDTO extends DataTransferObject
99
{
10-
private $language;
11-
private $type;
10+
public $language;
11+
public $type;
1212

1313
public static function fromRequest(CourseIndexRequest $request): CourseIndexDTO
1414
{

‎app/Http/Requests/CourseIndexRequest.php‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,19 @@ public function rules()
2828
'type' => ['nullable', 'in:Voice,Video,Chat']
2929
];
3030
}
31+
32+
33+
/**
34+
* Get the error messages for the defined validation rules.
35+
*
36+
* @return array
37+
*/
38+
public function messages()
39+
{
40+
return [
41+
'language.in' => 'The selected language is invalid.',
42+
'type.in' => 'The selected type is invalid.',
43+
];
44+
}
45+
3146
}

‎app/Http/Requests/LessonStoreRequest.php‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,17 @@ public function rules()
3636
'recording' => ['nullable', new RecordingNotAvailableStatusStart]
3737
];
3838
}
39+
40+
/**
41+
* Get the error messages for the defined validation rules.
42+
*
43+
* @return array
44+
*/
45+
public function messages()
46+
{
47+
return [
48+
'status.required' => 'The status field is required.',
49+
'status.in' => 'The selected status is invalid. Valid values are Start or End.',
50+
];
51+
}
3952
}

‎app/Models/Course.php‎

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,16 @@ class Course extends Model
1515
use SoftDeletes;
1616
use HasFactory;
1717

18+
protected $perPage = 2;
19+
1820
/**
1921
* The table associated with the model.
2022
*
2123
* @var string
2224
*/
2325
protected $table = 'courses';
2426

25-
protected $fillable = ['students_id', 'course_id',];
27+
protected $fillable = ['students_id', 'course_id',];
2628

2729
/**
2830
* The attributes that should be mutated to dates.
@@ -65,7 +67,7 @@ public function enrollments(): \Illuminate\Database\Eloquent\Relations\HasMany
6567

6668
public static function getAvailableCourses(string $language = null, string $type = null): ?\Illuminate\Contracts\Pagination\LengthAwarePaginator
6769
{
68-
$query = self::query()->where('available', true);
70+
$query = self::query()->where('deleted_at', null);
6971

7072
if ($language) {
7173
$query->where('language', $language);
@@ -75,15 +77,20 @@ public static function getAvailableCourses(string $language = null, string $type
7577
$query->where('type', $type);
7678
}
7779

78-
return $query->latest()->paginate();
80+
$now = now();
81+
82+
// DB 와 서버 모두 UTC
83+
return $query->where('available_from', '<=', $now)
84+
->where('available_until', '>=', $now)->latest()->paginate();
7985
}
8086

81-
public static function getAvailableOne(string $id = null)
87+
public static function getAvailableOne(int $id = null)
8288
{
8389
$now = now();
8490

8591
return self::query()->where('available_from', '<=', $now)
8692
->where('available_until', '>=', $now)->find($id);
8793

8894
}
95+
8996
}

‎app/Models/Enrollment.php‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@
99
use Illuminate\Contracts\Pagination\Paginator;
1010
use Illuminate\Database\Eloquent\Relations\BelongsTo;
1111
use Illuminate\Database\Eloquent\Factories\HasFactory;
12+
use Illuminate\Support\Facades\Log;
1213

1314
class Enrollment extends Model
1415
{
16+
use SoftDeletes;
1517
use HasFactory;
1618

1719
/**
@@ -70,4 +72,5 @@ public static function getOne(int $course_id, int $student_id) : ?Enrollment
7072
{
7173
return static::where('course_id', $course_id)->where('student_id', $student_id)->first();
7274
}
75+
7376
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /