Browse Source

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

markus 1 week ago
parent
commit
5465a2aacf

+ 10 - 10
composer.json

@@ -5,18 +5,18 @@
     "minimum-stability": "dev",
     "prefer-stable": true,
     "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": {
-        "n2n/hangar": "^7.4",
-        "n2n/n2n-test" : "^7.4",
+        "n2n/hangar": "^7.5",
+        "n2n/n2n-test" : "^7.5",
         "phpunit/phpunit" : "^9.5"
     },
     "autoload" : {

File diff suppressed because it is too large
+ 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\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 {
 	public int $id;
@@ -13,11 +15,34 @@ class Article extends ObjectAdapter implements \JsonSerializable {
 
 	public string $title;
 
-	#[ManyToMany(Category::class, 'articles')]
+
+	#[OrderBy(array('name' => 'ASC'))]
+	#[ManyToMany(Category::class, 'articles', cascade: CascadeType::PERSIST)]
 	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() {
 		return [
@@ -32,7 +57,8 @@ class Article extends ObjectAdapter implements \JsonSerializable {
 		$basicJson = $this->basicJsonSerialize();
 
 		$basicJson['categoryName'] = $this->categoryName;
-		$basicJson['categories'] = $this->categories;
+		$basicJson['categories'] = $this->getCategoryIds();
+		$basicJson['comments'] = $this->getCommentIds();
 
         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 nql\bo\BlogArticle;
 use n2n\reflection\ObjectAdapter;
+use n2n\persistence\orm\CascadeType;
 
 class Category extends ObjectAdapter implements \JsonSerializable {
 
@@ -15,15 +16,11 @@ class Category extends ObjectAdapter implements \JsonSerializable {
 	/**
 	 * @var \ArrayObject<Article>
 	 */
-	#[ManyToMany(Article::class)]
+	#[ManyToMany(Article::class, cascade: CascadeType::NONE)]
 	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() {
@@ -34,11 +31,19 @@ class Category extends ObjectAdapter implements \JsonSerializable {
 		return $articles;
 	}
 
-	function jsonSerialize(): mixed {
+	function basicJsonSerialize() {
 		return [
 				'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;
 
-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 string $author;
+
 	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;
 
 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 {
 	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 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 internship\bo\Article;
 use n2n\context\attribute\RequestScoped;
+use n2n\context\attribute\Inject;
 
 /**
  * Benutze diese Klasse um Datenbankabfragen auszuführen.
@@ -12,12 +13,9 @@ use n2n\context\attribute\RequestScoped;
  */
 #[RequestScoped]
 class ArticleDao {
+	#[Inject]
 	private EntityManager $em;
 
-	private function _init(EntityManager $em): void {
-		$this->em = $em;
-	}
-
 	/**
 	 * 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\persistence\orm\EntityManager;
 use internship\bo\Category;
+use n2n\context\attribute\Inject;
 
 #[RequestScoped]
 class CategoryDao {
+	#[Inject]
 	private EntityManager $em;
 
-	private function _init(EntityManager $em): void {
-		$this->em = $em;
-	}
-
 	/**
 	 * 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\io\IoUtils;
 use n2n\core\TypeLoader;
+use n2n\persistence\ext\PdoPool;
 
 ini_set('display_errors', 1);
 error_reporting(E_ALL);
@@ -40,4 +41,5 @@ $sql = preg_replace("/[\r\n]+/", "\n", $sql);
 $sql = str_replace('UNSIGNED ', '', $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 internship\bo\Article;
 use n2n\web\http\BadRequestException;
+use ArrayObject;
+use internship\bo\Category;
 
 
 class ArticleControllerTest extends TestCase {
@@ -25,13 +27,18 @@ class ArticleControllerTest extends TestCase {
 		$article1 = ArticleTestEnv::setUpArticle('Title 3', 'Lorem ipsum 3', 'teaser');
 		$article2 = ArticleTestEnv::setUpArticle('Title 2', 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');
 		//var_dump($article4);
 		$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([
 					'title' => 'Title POST',
 					'text' => 'Text POST',
-					'categoryName' => 'sport',
+					'categoryName' => 'sport'
 				])
 				->exec();
 
@@ -178,6 +185,7 @@ class ArticleControllerTest extends TestCase {
 
 		$tx = TestEnv::createTransaction(true);
 		$this->assertSame(3, TestEnv::temUtil()->count(Article::class));
+		$this->assertSame(1, TestEnv::temUtil()->count(Category::class));
 		$tx->commit();
 
         TestEnv::http()->newRequest()
@@ -186,6 +194,25 @@ class ArticleControllerTest extends TestCase {
 
 		$tx = TestEnv::createTransaction(true);
         $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();
     }
 

+ 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
--- Date 2026-07-02T12:48:09+00:00
+-- Date 2026-08-11T13:25:04+00:00
 -- Backup by 
 
 /*!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`;
-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-web
 /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[/user] = "internship\\controller\\UserApiController"
 controllers[/api/category] = "internship\\controller\\CategoryApiController"
+controllers[/api/comment] = "internship\\controller\\CommentApiController"
 
 [orm]
 entities[] = "internship\bo\Article"
-entities[] = "internship\bo\Category"
+entities[] = "internship\bo\Category"
+entities[] = "internship\bo\Comment"

Some files were not shown because too many files changed in this diff