소스 검색

added Comments (DB, Dao, Business Object, Controller) & added some new tests

markus 1 주 전
부모
커밋
5465a2aacf

+ 10 - 10
composer.json

@@ -5,18 +5,18 @@
     "minimum-stability": "dev",
     "minimum-stability": "dev",
     "prefer-stable": true,
     "prefer-stable": true,
     "require": {
     "require": {
-        "n2n/n2n": "^7.4",
-        "n2n/n2n-batch": "^7.4",
-        "n2n/n2n-context": "^7.4",
-        "n2n/n2n-mail": "^7.4",
-        "n2n/n2n-impl-persistence-meta": "^7.4",
-        "n2n/n2n-impl-persistence-orm": "^7.4",
-        "n2n/n2n-impl-web-dispatch": "^7.4",
-        "n2n/n2n-impl-web-ui": "^7.4"
+        "n2n/n2n": "^7.5",
+        "n2n/n2n-batch": "^7.5",
+        "n2n/n2n-context": "^7.5",
+        "n2n/n2n-mail": "^7.5",
+        "n2n/n2n-impl-persistence-meta": "^7.5",
+        "n2n/n2n-impl-persistence-orm": "^7.5",
+        "n2n/n2n-impl-web-dispatch": "^7.5",
+        "n2n/n2n-impl-web-ui": "^7.5"
     },
     },
     "require-dev": {
     "require-dev": {
-        "n2n/hangar": "^7.4",
-        "n2n/n2n-test" : "^7.4",
+        "n2n/hangar": "^7.5",
+        "n2n/n2n-test" : "^7.5",
         "phpunit/phpunit" : "^9.5"
         "phpunit/phpunit" : "^9.5"
     },
     },
     "autoload" : {
     "autoload" : {

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 458 - 164
composer.lock


+ 31 - 5
src-php/app/internship/bo/Article.php

@@ -3,7 +3,9 @@ namespace internship\bo;
 
 
 use n2n\reflection\ObjectAdapter;
 use n2n\reflection\ObjectAdapter;
 use n2n\persistence\orm\attribute\ManyToMany;
 use n2n\persistence\orm\attribute\ManyToMany;
-use n2n\persistence\orm\attribute\ManyToOne;
+use n2n\persistence\orm\attribute\OneToMany;
+use n2n\persistence\orm\CascadeType;
+use n2n\persistence\orm\attribute\OrderBy;
 
 
 class Article extends ObjectAdapter implements \JsonSerializable {
 class Article extends ObjectAdapter implements \JsonSerializable {
 	public int $id;
 	public int $id;
@@ -13,11 +15,34 @@ class Article extends ObjectAdapter implements \JsonSerializable {
 
 
 	public string $title;
 	public string $title;
 
 
-	#[ManyToMany(Category::class, 'articles')]
+
+	#[OrderBy(array('name' => 'ASC'))]
+	#[ManyToMany(Category::class, 'articles', cascade: CascadeType::PERSIST)]
 	public \ArrayObject $categories;
 	public \ArrayObject $categories;
 
 
-	/* #[ManyToOne(Comment::class, 'articles')] */
-	// public \ArrayObject $comments;
+	#[OneToMany(Comment::class, 'article', cascade: CascadeType::PERSIST, orphanRemoval: true)]
+	public \ArrayObject $comments;
+
+	function __construct() {
+		$this->categories = new \ArrayObject();
+		$this->comments = new \ArrayObject();
+	}
+
+	private function getCategoryIds() {
+		$categories = array();
+		foreach($this->categories as $category) {
+			$categories[] = $category->basicJsonSerialize();
+		}
+		return $categories;
+	}
+
+	private function getCommentIds() {
+		$comments = array();
+		foreach($this->comments as $comment) {
+			$comments[] = $comment->basicJsonSerialize();
+		}
+		return $comments;
+	}
 
 
 	function basicJsonSerialize() {
 	function basicJsonSerialize() {
 		return [
 		return [
@@ -32,7 +57,8 @@ class Article extends ObjectAdapter implements \JsonSerializable {
 		$basicJson = $this->basicJsonSerialize();
 		$basicJson = $this->basicJsonSerialize();
 
 
 		$basicJson['categoryName'] = $this->categoryName;
 		$basicJson['categoryName'] = $this->categoryName;
-		$basicJson['categories'] = $this->categories;
+		$basicJson['categories'] = $this->getCategoryIds();
+		$basicJson['comments'] = $this->getCommentIds();
 
 
         return $basicJson;
         return $basicJson;
     }
     }

+ 15 - 10
src-php/app/internship/bo/Category.php

@@ -5,6 +5,7 @@ namespace internship\bo;
 use n2n\persistence\orm\attribute\ManyToMany;
 use n2n\persistence\orm\attribute\ManyToMany;
 use nql\bo\BlogArticle;
 use nql\bo\BlogArticle;
 use n2n\reflection\ObjectAdapter;
 use n2n\reflection\ObjectAdapter;
+use n2n\persistence\orm\CascadeType;
 
 
 class Category extends ObjectAdapter implements \JsonSerializable {
 class Category extends ObjectAdapter implements \JsonSerializable {
 
 
@@ -15,15 +16,11 @@ class Category extends ObjectAdapter implements \JsonSerializable {
 	/**
 	/**
 	 * @var \ArrayObject<Article>
 	 * @var \ArrayObject<Article>
 	 */
 	 */
-	#[ManyToMany(Article::class)]
+	#[ManyToMany(Article::class, cascade: CascadeType::NONE)]
 	public \ArrayObject $articles;
 	public \ArrayObject $articles;
 
 
-	public function getBlogArticles() {
-		return $this->blogArticles;
-	}
-
-	public function setBlogArticles(\ArrayObject $blogArticles) {
-		$this->blogArticles = $blogArticles;
+	function __construct() {
+		$this->articles = new \ArrayObject();
 	}
 	}
 
 
 	private function getArticleIds() {
 	private function getArticleIds() {
@@ -34,11 +31,19 @@ class Category extends ObjectAdapter implements \JsonSerializable {
 		return $articles;
 		return $articles;
 	}
 	}
 
 
-	function jsonSerialize(): mixed {
+	function basicJsonSerialize() {
 		return [
 		return [
 				'id' => $this->id,
 				'id' => $this->id,
-				'name' => $this->name,
-				'articles' => $this->getArticleIds()
+				'name' => $this->name
 		];
 		];
 	}
 	}
+
+	function jsonSerialize(): mixed {
+
+		$basicJson = $this->basicJsonSerialize();
+
+		$basicJson['articles'] = $this->getArticleIds();
+
+		return $basicJson;
+	}
 }
 }

+ 29 - 5
src-php/app/internship/bo/Comment.php

@@ -2,13 +2,37 @@
 
 
 namespace internship\bo;
 namespace internship\bo;
 
 
-class Comment extends ObjectAdapter {
-	/*private static function _annos(AnnoInit $ai) {
-		$ai->p('blogArticle', new AnnoManyToOne(BlogArticle::getClass()));
-	}*/
+use n2n\persistence\orm\attribute\ManyToOne;
+use n2n\reflection\ObjectAdapter;
+
+class Comment extends ObjectAdapter implements \JsonSerializable {
 
 
 	public int $id;
 	public int $id;
+
 	public string $author;
 	public string $author;
+
 	public string $text;
 	public string $text;
-	public Article $blogArticle;
+
+	#[ManyToOne(Article::class)]
+	public ?Article $article = null;
+
+//	function __construct(Article $article) {
+//		$this->article = $article;
+//	}
+
+	function basicJsonSerialize() {
+		return [
+				'id' => $this->id,
+				'author' => $this->author,
+				'text' => $this->text
+		];
+	}
+
+	public function jsonSerialize(): mixed {
+		$basicJson = $this->basicJsonSerialize();
+
+		// $basicJson['articleId'] = $this->article->id;
+
+		return $basicJson;
+	}
 }
 }

+ 48 - 0
src-php/app/internship/bo/News.php

@@ -3,9 +3,57 @@
 namespace internship\bo;
 namespace internship\bo;
 
 
 use n2n\reflection\ObjectAdapter;
 use n2n\reflection\ObjectAdapter;
+use n2n\persistence\orm\attribute\Table;
+use n2n\persistence\orm\attribute\Inheritance;
+use n2n\persistence\orm\InheritanceType;
+use n2n\persistence\orm\attribute\DiscriminatorValue;
+use n2n\persistence\orm\attribute\DiscriminatorColumn;
+use n2n\persistence\orm\attribute\EntityListeners;
+use n2n\persistence\orm\attribute\AttributeOverrides;
+use n2n\persistence\orm\attribute\MappedSuperclass;
+use n2n\persistence\orm\attribute\ManagedFile;
+use nql\bo\Member;
+use n2n\persistence\orm\attribute\ManyToOne;
+use n2n\persistence\orm\attribute\Embedded;
+use n2n\persistence\orm\attribute\Column;
+use n2n\persistence\orm\attribute\Id;
+use n2n\io\managed\FileManager;
+use n2n\persistence\orm\attribute\AssociationOverrides;
+use n2n\persistence\orm\attribute\JoinColumn;
+use n2n\persistence\orm\CascadeType;
+use n2n\persistence\orm\attribute\OneToMany;
+use n2n\persistence\orm\attribute\JoinTable;
+use n2n\persistence\orm\attribute\OrderBy;
+use n2n\persistence\orm\attribute\OneToOne;
+use n2n\persistence\orm\attribute\ManyToMany;
 
 
+#[Table('newsarticle')]
+/* #[Inheritance(InheritanceType::TABLE_PER_CLASS)] */
+/* #[DiscriminatorValue('textItem')] */
+/* #[DiscriminatorColumn('type')] */
+/* #[AttributeOverrides([
+		'id' => 'news_id',
+		'title' => 'news_title',
+		'description' => 'news_description',
+		'text' => 'news_text'
+])] */
+/*	#[MappedSuperclass] */
+/*	#[OneToMany('assignement.assignementGroup', Member::class)]*/
+/* #[ManyToOne(targetEntity: BlogArticle::class, cascade: null, cascadeType: CascadeType::ALL, fetch: FetchType::EAGER)] */
+/*	#[EntityListeners(LastModListener::class)] */
+/*	#[OneToOne(Article::class)] */
+/*	#[ManyToMany('articles', Article::class)] */
 class News extends ObjectAdapter implements \JsonSerializable {
 class News extends ObjectAdapter implements \JsonSerializable {
 	public int $id;
 	public int $id;
+	/* #[OrderBy]
+		#[Embedded(Address::class)]
+		#[AttributeOverrides(['forename' => 'bill_forename',
+		'surname' => 'bill_surname'])]
+		#[Column('firstname')]
+	*/
+	/* #[ManagedFile(FileManager::TYPE_PUBLIC)] */
+	/* #[AssociationOverrides(array( 'assignementGroup' => new JoinColumn('group_id')))] */
+	/* #[JoinColumn('article_id')] */
 	public string $text;
 	public string $text;
 
 
 	public function jsonSerialize(): mixed {
 	public function jsonSerialize(): mixed {

+ 27 - 0
src-php/app/internship/controller/CommentApiController.php

@@ -0,0 +1,27 @@
+<?php
+
+namespace internship\controller;
+
+use n2n\web\http\controller\ControllerAdapter;
+use n2n\context\attribute\Inject;
+use internship\model\CommentDao;
+use n2n\web\http\PageNotFoundException;
+
+class CommentApiController extends ControllerAdapter {
+	#[Inject]
+	private CommentDao $commentDao;
+
+	function getDoComments(): void {
+
+		$this->sendJson($this->commentDao->getComments());
+	}
+
+	function getDoComment(int $commentId): void {
+		$comment = $this->commentDao->getCommentById($commentId);
+		if($comment === null) {
+			throw new PageNotFoundException();
+		} else {
+			$this->sendJson($comment);
+		}
+	}
+}

+ 2 - 4
src-php/app/internship/model/ArticleDao.php

@@ -4,6 +4,7 @@ namespace internship\model;
 use n2n\persistence\orm\EntityManager;
 use n2n\persistence\orm\EntityManager;
 use internship\bo\Article;
 use internship\bo\Article;
 use n2n\context\attribute\RequestScoped;
 use n2n\context\attribute\RequestScoped;
+use n2n\context\attribute\Inject;
 
 
 /**
 /**
  * Benutze diese Klasse um Datenbankabfragen auszuführen.
  * Benutze diese Klasse um Datenbankabfragen auszuführen.
@@ -12,12 +13,9 @@ use n2n\context\attribute\RequestScoped;
  */
  */
 #[RequestScoped]
 #[RequestScoped]
 class ArticleDao {
 class ArticleDao {
+	#[Inject]
 	private EntityManager $em;
 	private EntityManager $em;
 
 
-	private function _init(EntityManager $em): void {
-		$this->em = $em;
-	}
-
 	/**
 	/**
 	 * Gebe alle {@see Article}-Objekte, nach id absteigend sortiert, zurück.
 	 * Gebe alle {@see Article}-Objekte, nach id absteigend sortiert, zurück.
 	 *
 	 *

+ 2 - 4
src-php/app/internship/model/CategoryDao.php

@@ -5,15 +5,13 @@ namespace internship\model;
 use n2n\context\attribute\RequestScoped;
 use n2n\context\attribute\RequestScoped;
 use n2n\persistence\orm\EntityManager;
 use n2n\persistence\orm\EntityManager;
 use internship\bo\Category;
 use internship\bo\Category;
+use n2n\context\attribute\Inject;
 
 
 #[RequestScoped]
 #[RequestScoped]
 class CategoryDao {
 class CategoryDao {
+	#[Inject]
 	private EntityManager $em;
 	private EntityManager $em;
 
 
-	private function _init(EntityManager $em): void {
-		$this->em = $em;
-	}
-
 	/**
 	/**
 	 * Gebe alle {@see Category}-Objekte, nach id absteigend sortiert, zurück.
 	 * Gebe alle {@see Category}-Objekte, nach id absteigend sortiert, zurück.
 	 *
 	 *

+ 40 - 0
src-php/app/internship/model/CommentDao.php

@@ -0,0 +1,40 @@
+<?php
+
+namespace internship\model;
+
+use n2n\persistence\orm\EntityManager;
+use n2n\context\attribute\RequestScoped;
+use internship\bo\Comment;
+use n2n\context\attribute\Inject;
+
+#[RequestScoped]
+class CommentDao {
+	#[Inject]
+	private EntityManager $em;
+
+	/**
+	 * Gebe alle {@see Comment}-Objekte, nach id absteigend sortiert, zurück.
+	 *
+	 * @return Comment[]
+	 */
+	function getComments(): array {
+		// http://localhost/php-storm/internship-playground/src-php/public/api/comment/comments/
+
+		$criteria = $this->em->createSimpleCriteria(Comment::getClass(), array(), array('id' => 'DESC'));
+		return $criteria->toQuery()->fetchArray();
+	}
+
+	function getCommentById(int $id): ?Comment {
+		// http://localhost/php-storm/internship-playground/src-php/public/api/comment/comment/2
+		return $this->em->find(Comment::getClass(), $id);
+	}
+
+	/* function getCommentById(int $id) {
+		$criteria = $this->em->createCriteria();
+		$criteria->select('c.id', 'commentId')
+				->select('c.article.id', 'articleId')
+				->from(Comment::class , 'c')
+				->where(['c.id'=>$id]);
+		return $criteria->toQuery()->fetchSingle();
+	} */
+}

+ 3 - 1
src-php/test/bootstrap.php

@@ -3,6 +3,7 @@ use n2n\core\N2N;
 use n2n\core\FileN2nCache;
 use n2n\core\FileN2nCache;
 use n2n\io\IoUtils;
 use n2n\io\IoUtils;
 use n2n\core\TypeLoader;
 use n2n\core\TypeLoader;
+use n2n\persistence\ext\PdoPool;
 
 
 ini_set('display_errors', 1);
 ini_set('display_errors', 1);
 error_reporting(E_ALL);
 error_reporting(E_ALL);
@@ -40,4 +41,5 @@ $sql = preg_replace("/[\r\n]+/", "\n", $sql);
 $sql = str_replace('UNSIGNED ', '', $sql);
 $sql = str_replace('UNSIGNED ', '', $sql);
 file_put_contents('huii.sql', $sql);
 file_put_contents('huii.sql', $sql);
 
 
-N2N::getPdoPool()->getPdo()->exec($sql);
+N2N::getN2nContext()->lookup(PdoPool::class)->getPdo()->exec($sql);
+

+ 31 - 4
src-php/test/internship/controller/ArticleControllerTest.php

@@ -10,6 +10,8 @@ use n2n\web\http\StatusException;
 use n2n\web\http\PageNotFoundException;
 use n2n\web\http\PageNotFoundException;
 use internship\bo\Article;
 use internship\bo\Article;
 use n2n\web\http\BadRequestException;
 use n2n\web\http\BadRequestException;
+use ArrayObject;
+use internship\bo\Category;
 
 
 
 
 class ArticleControllerTest extends TestCase {
 class ArticleControllerTest extends TestCase {
@@ -25,13 +27,18 @@ class ArticleControllerTest extends TestCase {
 		$article1 = ArticleTestEnv::setUpArticle('Title 3', 'Lorem ipsum 3', 'teaser');
 		$article1 = ArticleTestEnv::setUpArticle('Title 3', 'Lorem ipsum 3', 'teaser');
 		$article2 = ArticleTestEnv::setUpArticle('Title 2', categoryName: 'news');
 		$article2 = ArticleTestEnv::setUpArticle('Title 2', categoryName: 'news');
 		$article3 = ArticleTestEnv::setUpArticle('Title 1', categoryName: 'news');
 		$article3 = ArticleTestEnv::setUpArticle('Title 1', categoryName: 'news');
+		$cat = new Category();
+		$cat->name = 'Category 1';
+		$cat->articles = new ArrayObject([$article1, $article2]);
+		$article1->categories = new ArrayObject([$cat]);
+		$article3->categories = new ArrayObject([$cat]);
 		//$article4 = ArticleTestEnv::setUpArticle('Title 4');
 		//$article4 = ArticleTestEnv::setUpArticle('Title 4');
 		//var_dump($article4);
 		//var_dump($article4);
 		$tx->commit();
 		$tx->commit();
 
 
-		$this->article1Id = $article1->getId();
-		$this->article2Id = $article2->getId();
-		$this->article3Id = $article3->getId();
+		$this->article1Id = $article1->id;
+		$this->article2Id = $article2->id;
+		$this->article3Id = $article3->id;
 	}
 	}
 
 
 	/**
 	/**
@@ -99,7 +106,7 @@ class ArticleControllerTest extends TestCase {
 				->bodyJson([
 				->bodyJson([
 					'title' => 'Title POST',
 					'title' => 'Title POST',
 					'text' => 'Text POST',
 					'text' => 'Text POST',
-					'categoryName' => 'sport',
+					'categoryName' => 'sport'
 				])
 				])
 				->exec();
 				->exec();
 
 
@@ -178,6 +185,7 @@ class ArticleControllerTest extends TestCase {
 
 
 		$tx = TestEnv::createTransaction(true);
 		$tx = TestEnv::createTransaction(true);
 		$this->assertSame(3, TestEnv::temUtil()->count(Article::class));
 		$this->assertSame(3, TestEnv::temUtil()->count(Article::class));
+		$this->assertSame(1, TestEnv::temUtil()->count(Category::class));
 		$tx->commit();
 		$tx->commit();
 
 
         TestEnv::http()->newRequest()
         TestEnv::http()->newRequest()
@@ -186,6 +194,25 @@ class ArticleControllerTest extends TestCase {
 
 
 		$tx = TestEnv::createTransaction(true);
 		$tx = TestEnv::createTransaction(true);
         $this->assertSame(2, TestEnv::temUtil()->count(Article::class));
         $this->assertSame(2, TestEnv::temUtil()->count(Article::class));
+		$this->assertSame(1, TestEnv::temUtil()->count(Category::class));
+		$tx->commit();
+    }
+
+	function testDeleteCat() {
+
+		$tx = TestEnv::createTransaction(true);
+		$this->assertSame(3, TestEnv::temUtil()->count(Article::class));
+		$this->assertSame(1, TestEnv::temUtil()->count(Category::class));
+		$tx->commit();
+
+		$tx = TestEnv::createTransaction();
+		$cat = TestEnv::tem()->find(Category::class, 1);
+        TestEnv::tem()->remove($cat);
+		$tx->commit();
+
+		$tx = TestEnv::createTransaction(true);
+        $this->assertSame(3, TestEnv::temUtil()->count(Article::class));
+		$this->assertSame(0, TestEnv::temUtil()->count(Category::class));
 		$tx->commit();
 		$tx->commit();
     }
     }
 
 

+ 110 - 0
src-php/test/internship/controller/CommentControllerTest.php

@@ -0,0 +1,110 @@
+<?php
+
+namespace internship\controller;
+
+use PHPUnit\Framework\TestCase;
+use internship\test\CommentTestEnv;
+use n2n\test\TestEnv;
+use internship\bo\Article;
+use internship\test\ArticleTestEnv;
+use n2n\web\http\StatusException;
+use util\GeneralTestEnv;
+use internship\bo\Comment;
+use n2n\web\http\PageNotFoundException;
+
+class CommentControllerTest extends TestCase {
+	private int $article1Id;
+	private int $comment1Id;
+	private int $comment2Id;
+	private int $comment3Id;
+
+	function setUp(): void {
+		GeneralTestEnv::tearDown();
+
+		$tx = TestEnv::createTransaction();
+		$article1 = ArticleTestEnv::setUpArticle('Title 1', 'Lorem ipsum 1', 'sport');
+		$comment1 = CommentTestEnv::setUpComment($article1, 'Markus Rutz', 'Hallo das ist ein Test (0) :-)');
+		$comment2 = CommentTestEnv::setUpComment($article1, 'Markus Rutz', 'Hallo das ist ein Test (1) :-)');
+		$comment3 = CommentTestEnv::setUpComment($article1, 'Markus Rutz', 'Hallo das ist ein Test (2) :-)');
+		$tx->commit();
+
+		$this->article1Id = $article1->id;
+		$this->comment1Id = $comment1->id;
+		$this->comment2Id = $comment2->id;
+		$this->comment3Id = $comment3->id;
+	}
+
+	/**
+	 * @throws StatusException
+	 */
+	function testGetDoComments() {
+		$response = TestEnv::http()->newRequest()
+				->get(['api', 'comment', 'comments'])
+				->exec();
+
+		$commentStructs = $response->parseJson();
+		$this->assertCount(3, $commentStructs);
+
+		$this->assertEquals('Hallo das ist ein Test (2) :-)', $commentStructs[0]['text']);
+		$this->assertEquals('Hallo das ist ein Test (1) :-)', $commentStructs[1]['text']);
+		$this->assertEquals('Hallo das ist ein Test (0) :-)', $commentStructs[2]['text']);
+	}
+
+	/**
+	 * @throws StatusException
+	 */
+	function testGetComment() {
+		$response = TestEnv::http()->newRequest()
+				->get(['api', 'comment', 'comment', $this->article1Id])
+				->exec();
+
+		$commentStructs = $response->parseJson();
+
+		$this->assertEquals('Hallo das ist ein Test (0) :-)', $commentStructs['text']);
+	}
+
+	/**
+	 * @throws StatusException
+	 */
+	function testGetCommentNotFound() {
+		$this->expectException(PageNotFoundException::class);
+
+		$response = TestEnv::http()->newRequest()
+				->get(['api', 'comment', 'comment', 1000])
+				->exec();
+	}
+
+	/**
+	 * @throws StatusException
+	 */
+	function testDeleteComment() {
+		$tx = TestEnv::createTransaction();
+		$comment1 = TestEnv::tem()->find(Comment::class, 1);
+		TestEnv::tem()->remove($comment1);
+		$tx->commit();
+
+		$tx = TestEnv::createTransaction(true);
+		$this->assertSame(2, TestEnv::temUtil()->count(Comment::class));
+		$tx->commit();
+	}
+
+	/**
+	 * @throws StatusException
+	 */
+	function testDeleteArticleAndOrphanRemovalOfComments() {
+		$tx = TestEnv::createTransaction(true);
+		$this->assertSame(1, TestEnv::temUtil()->count(Article::class));
+		$this->assertSame(3, TestEnv::temUtil()->count(Comment::class));
+		$tx->commit();
+
+		$tx = TestEnv::createTransaction();
+		$article = TestEnv::tem()->find(Article::class, 1);
+		TestEnv::tem()->remove($article);
+		$tx->commit();
+
+		$tx = TestEnv::createTransaction(true);
+		$this->assertSame(0, TestEnv::temUtil()->count(Article::class));
+		$this->assertSame(0, TestEnv::temUtil()->count(Comment::class));
+		$tx->commit();
+	}
+}

+ 28 - 0
src-php/test/internship/test/CommentTestEnv.php

@@ -0,0 +1,28 @@
+<?php
+
+namespace internship\test;
+
+use internship\bo\Article;
+use n2n\util\HashUtils;
+use n2n\test\TestEnv;
+use internship\bo\Comment;
+
+class CommentTestEnv {
+	static function setUpComment(Article $article, string $author, ?string $text = null): Comment {
+
+		// $uniqueID = HashUtils::base36Uniqid(false);
+
+		//$article1 = ArticleTestEnv::setUpArticle('Title 1', 'Lorem ipsum 1', 'sport');
+
+		$comment = new Comment();
+		$comment->article = $article;
+		$comment->author = $author;
+		$comment->text = $text;
+
+		TestEnv::em()->persist($article);
+		TestEnv::em()->persist($comment);
+		TestEnv::em()->flush();
+
+		return $comment;
+	}
+}

+ 57 - 1
src-php/var/bak/backup-bak.sql

@@ -1,6 +1,62 @@
 -- Mysql Backup of internship_playground
 -- Mysql Backup of internship_playground
--- Date 2026-07-02T12:48:09+00:00
+-- Date 2026-08-11T13:25:04+00:00
 -- Backup by 
 -- Backup by 
 
 
 /*!40101 SET NAMES utf8mb4 */;
 /*!40101 SET NAMES utf8mb4 */;
 
 
+DROP TABLE IF EXISTS `category`;
+CREATE TABLE `category` ( 
+	`id` INT UNSIGNED NOT NULL AUTO_INCREMENT, 
+	`name` VARCHAR(255) NOT NULL, 
+	PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_unicode_ci ;
+
+INSERT INTO `category` (`id`, `name`)
+VALUES ( '1',  'international'),
+( '2', 'national'),
+( '3', 'sport');
+
+DROP TABLE IF EXISTS `category_articles`;
+CREATE TABLE `category_articles` ( 
+	`article_id` INT UNSIGNED NOT NULL, 
+	`category_id` INT UNSIGNED NOT NULL, 
+	PRIMARY KEY (`article_id`, `category_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_unicode_ci ;
+
+INSERT INTO `category_articles` (`article_id`, `category_id`)
+VALUES ( '1',  '2'),
+( '1', '3'),
+( '2', '3');
+
+DROP TABLE IF EXISTS `comment`;
+CREATE TABLE `comment` ( 
+	`id` INT UNSIGNED NOT NULL AUTO_INCREMENT, 
+	`author` VARCHAR(32) NULL DEFAULT NULL, 
+	`text` TEXT NULL DEFAULT NULL, 
+	`article_id` INT UNSIGNED NULL DEFAULT NULL, 
+	PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_unicode_ci ;
+
+
+DROP TABLE IF EXISTS `news`;
+CREATE TABLE `news` ( 
+	`id` INT UNSIGNED NOT NULL AUTO_INCREMENT, 
+	`title` VARCHAR(50) NULL DEFAULT NULL, 
+	`description` VARCHAR(255) NULL DEFAULT NULL, 
+	`text` TEXT NULL DEFAULT NULL, 
+	PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_unicode_ci ;
+
+
+DROP TABLE IF EXISTS `order`;
+CREATE TABLE `order` ( 
+	`id` INT UNSIGNED NOT NULL AUTO_INCREMENT, 
+	`product_name` VARCHAR(50) NOT NULL, 
+	`bill_forename` VARCHAR(50) NOT NULL, 
+	`bill_surname` VARCHAR(50) NOT NULL, 
+	`delivery_forename` VARCHAR(50) NULL DEFAULT NULL, 
+	`delivery_surname` VARCHAR(50) NULL DEFAULT NULL, 
+	PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_unicode_ci ;
+
+

+ 77 - 12
src-php/var/bak/backup.sql

@@ -1,14 +1,79 @@
--- Mysql Backup of internship-playground
--- Date 2023-05-01T12:38:25+02:00
--- Backup by nikolai
+-- Mysql Backup of internship_playground
+-- Date 2026-08-11T13:16:37+00:00
+-- Backup by 
+
+/*!40101 SET NAMES utf8mb4 */;
 
 
 DROP TABLE IF EXISTS `article`;
 DROP TABLE IF EXISTS `article`;
-CREATE TABLE `article` (
-        `id` INT NOT NULL AUTO_INCREMENT,
-        `category_name` VARCHAR(255) NOT NULL ,
-        `title` VARCHAR(255) NOT NULL ,
-        `text` TEXT NOT NULL,
-        PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_unicode_ci ;
-INSERT INTO article VALUES (1, 'sport', 'Formula 1 Rennen endet im Drama', 'Das gestrige Rennen endete im Gerängel, Fans zofften sich weil Lewis Hamilton eine Bananenschale auf der Rennstrecke so positionierte, dass Max Verstappen darauf ausgerutscht und aus dem Rennen ausgeschieden ist.');
-INSERT INTO article VALUES (2, 'international', 'Es regnet', 'Aus unbekannten und mysteriösen Gründen regnet es schon seit geraumer Zeit.');
+CREATE TABLE `article` ( 
+	`id` INT NOT NULL AUTO_INCREMENT, 
+	`category_name` VARCHAR(255) NOT NULL, 
+	`title` VARCHAR(255) NOT NULL, 
+	`text` TEXT NOT NULL, 
+	PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_unicode_ci ;
+
+INSERT INTO `article` (`id`, `category_name`, `title`, `text`)
+VALUES ( '1',  'sport',  'Formula 1 Rennen endet im Drama',  'Das gestrige Rennen endete im Gerängel, Fans zofften sich weil Lewis Hamilton eine Bananenschale auf der Rennstrecke so positionierte, dass Max Verstappen darauf ausgerutscht und aus dem Rennen ausgeschieden ist.'),
+( '2', 'international', 'Es regnet', 'Aus unbekannten und mysteriösen Gründen regnet es schon seit geraumer Zeit.'),
+( '3', 'international', 'Es regnet', 'Aus unbekannten und mysteriösen Gründen regnet es schon seit geraumer Zeit.'),
+( '4', 'international', 'Es regnet 3', 'Aus unbekannten und mysteriösen Gründen regnet es schon seit geraumer Zeit. 3'),
+( '5', 'international', 'Es regnet 5', 'Aus unbekannten und mysteriösen Gründen regnet es schon seit geraumer Zeit. 5'),
+( '7', 'international', 'Es regnet 5', 'Aus unbekannten und mysteriösen Gründen regnet es schon seit geraumer Zeit. 5');
+
+DROP TABLE IF EXISTS `category`;
+CREATE TABLE `category` ( 
+	`id` INT UNSIGNED NOT NULL AUTO_INCREMENT, 
+	`name` VARCHAR(255) NOT NULL, 
+	PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_unicode_ci ;
+
+INSERT INTO `category` (`id`, `name`)
+VALUES ( '1',  'international'),
+( '2', 'national'),
+( '3', 'sport');
+
+DROP TABLE IF EXISTS `category_articles`;
+CREATE TABLE `category_articles` ( 
+	`article_id` INT UNSIGNED NOT NULL, 
+	`category_id` INT UNSIGNED NOT NULL, 
+	PRIMARY KEY (`article_id`, `category_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_unicode_ci ;
+
+INSERT INTO `category_articles` (`article_id`, `category_id`)
+VALUES ( '1',  '2'),
+( '1', '3'),
+( '2', '3');
+
+DROP TABLE IF EXISTS `comment`;
+CREATE TABLE `comment` ( 
+	`id` INT UNSIGNED NOT NULL AUTO_INCREMENT, 
+	`author` VARCHAR(32) NULL DEFAULT NULL, 
+	`text` TEXT NULL DEFAULT NULL, 
+	`article_id` INT UNSIGNED NULL DEFAULT NULL, 
+	PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_unicode_ci ;
+
+
+DROP TABLE IF EXISTS `news`;
+CREATE TABLE `news` ( 
+	`id` INT UNSIGNED NOT NULL AUTO_INCREMENT, 
+	`title` VARCHAR(50) NULL DEFAULT NULL, 
+	`description` VARCHAR(255) NULL DEFAULT NULL, 
+	`text` TEXT NULL DEFAULT NULL, 
+	PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_unicode_ci ;
+
+
+DROP TABLE IF EXISTS `order`;
+CREATE TABLE `order` ( 
+	`id` INT UNSIGNED NOT NULL AUTO_INCREMENT, 
+	`product_name` VARCHAR(50) NOT NULL, 
+	`bill_forename` VARCHAR(50) NOT NULL, 
+	`bill_surname` VARCHAR(50) NOT NULL, 
+	`delivery_forename` VARCHAR(50) NULL DEFAULT NULL, 
+	`delivery_surname` VARCHAR(50) NULL DEFAULT NULL, 
+	PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_unicode_ci ;
+
+

+ 46 - 0
src-php/var/bak/migrate.sql

@@ -0,0 +1,46 @@
+DROP TABLE IF EXISTS `category`;
+CREATE TABLE `category` (
+                            `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
+                            `name` VARCHAR(255) NOT NULL,
+                            PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_unicode_ci ;
+
+
+DROP TABLE IF EXISTS `category_articles`;
+CREATE TABLE `category_articles` (
+                                     `article_id` INT UNSIGNED NOT NULL,
+                                     `category_id` INT UNSIGNED NOT NULL,
+                                     PRIMARY KEY (`article_id`, `category_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_unicode_ci ;
+
+
+DROP TABLE IF EXISTS `comment`;
+CREATE TABLE `comment` (
+                           `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
+                           `author` VARCHAR(32) NULL DEFAULT NULL,
+                           `text` TEXT NULL DEFAULT NULL,
+                           `article_id` INT UNSIGNED NULL DEFAULT NULL,
+                           PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_unicode_ci ;
+
+
+DROP TABLE IF EXISTS `news`;
+CREATE TABLE `news` (
+                        `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
+                        `title` VARCHAR(50) NULL DEFAULT NULL,
+                        `description` VARCHAR(255) NULL DEFAULT NULL,
+                        `text` TEXT NULL DEFAULT NULL,
+                        PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_unicode_ci ;
+
+
+DROP TABLE IF EXISTS `order`;
+CREATE TABLE `order` (
+                         `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
+                         `product_name` VARCHAR(50) NOT NULL,
+                         `bill_forename` VARCHAR(50) NOT NULL,
+                         `bill_surname` VARCHAR(50) NOT NULL,
+                         `delivery_forename` VARCHAR(50) NULL DEFAULT NULL,
+                         `delivery_surname` VARCHAR(50) NULL DEFAULT NULL,
+                         PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_unicode_ci ;

+ 2 - 1
src-php/var/etc/.gitignore

@@ -3,4 +3,5 @@
 /n2n
 /n2n
 /n2n-web
 /n2n-web
 /n2n-impl-persistence-orm
 /n2n-impl-persistence-orm
-/n2n-persistence
+/n2n-persistence
+/n2n-batch

+ 3 - 1
src-php/var/etc/internship/app.ini

@@ -2,7 +2,9 @@
 controllers[/] = "internship\controller\IsRootController"
 controllers[/] = "internship\controller\IsRootController"
 controllers[/user] = "internship\\controller\\UserApiController"
 controllers[/user] = "internship\\controller\\UserApiController"
 controllers[/api/category] = "internship\\controller\\CategoryApiController"
 controllers[/api/category] = "internship\\controller\\CategoryApiController"
+controllers[/api/comment] = "internship\\controller\\CommentApiController"
 
 
 [orm]
 [orm]
 entities[] = "internship\bo\Article"
 entities[] = "internship\bo\Article"
-entities[] = "internship\bo\Category"
+entities[] = "internship\bo\Category"
+entities[] = "internship\bo\Comment"

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.