كثير من المواقع الإلكترونية دائما ما يكون لديها صفحة لإدراة المحتويات الخاصة بالموقع وخصوصا تلك التي تنشر المقالات والأخبار…خذ فرضا مثل موقعنا هذا (انفورماتيك) فأنت الآن تقرأ هذه النصوص وبها العديد من الخصائص والتنسيقات كحجم الخطوط وعرضها وخواصها بصورة عامة.
الصندق النصي TextBox او منطقة النصوص TextArea جميعهم لا يملكون تلك الخصائص الخاصة بتنسيق النصوص ووضعها في شكل محتوى منسق…فقط تقوم بعرض النص كما تمّ إدخاله.
هنالك العديد من محررات النصوص التي تتيح لمدير إدارة المحتوى ان يتحكم في شكل ونسق المقالات التي تنشر على الموقع ومن تلك المحررات ما سنقوم بعرضه في هذه المقالة المحرر TinyMCE وهو محرر مفتوح المصدر؛ ما يعني بإمكانك التعديل عليه والإضافة للمتطلبات التي تريدها أنت كمبرمج…لتسهيل عمل مدير إدارة المحتوى للموقع الذي قمت بتطويره.
*** لكي تكمل هذا المحتوى أو هذا المشروع ستحتاج لفيجوال ستديو 2013 أو فيجوال ستديو 2012 او أي نسخة أخرى بعده كـ 2015 وبمجرد تثبيتك للفيجوال ستديو 2013 على جهازك سيقوم بتثبيت قاعدة البيانات المحلية للغة الإستعلامات المهيكلة SQL Server Express LocalDB وهي خفيفة وتتيح لك العمل على قواعد البيانات داخل بيئة الفيجوال ستديو نفسه…وان كان لديك النسخة الكاملة SQL Server Management Studio أيضا بإمكانك استخدامها اذا كنت لا تريد استخدام LocalDB.
بيئة العمل الخاصة بي دائما ما تتكون في VS 2013 و SQL Server Management Studio 2012
حسنا لنبدأ:
سنقوم بعمل مشروع لنشر مقالات حيث تتكون المقالة من رقم وكاتب المقالة وجسم المقالة وسنقوم بربطها بقاعدة البيانات SQL Server.
قم بفتح الفيجوال ستديو وقم بإنشاء مشروع ويب جديد…من النافذة التي تظهر لك قم بإختيار الفريم وورك 4.5 وقم بإختيار مشروع الـ ASP.NET MVC 4 Web Application وقم بتسمية المشروع بـ TinyEditorWithMVCApp وأضغط Ok كما موضح بالصورة أدناه.
ستظهر لك نافذة أخرى قم بإختيار هيكل المشروع Basic واللغة التي سنستخدمها في صفحات الـ HTML ستكون الـ Razor Page وقم بضغط OK كما موضع بالصورة أدناه.
قم بإنشاء قاعدة بيانات جديدة بإسم TestDB وقم بتنفيذ الإستعلام التالي في صفحة استعلام جديدة على نفس قاعدة البيانات:
CREATE TABLE [dbo].[Posts] ( [PostID] INT IDENTITY (1, 1) NOT NULL, [AuthorName] NVARCHAR (200) NOT NULL, PRIMARY KEY CLUSTERED ([PostID] ASC) [Body] NVARCHAR (MAX) NOT NULL, )
الإستعلام السابق يقوم بإنشاء جدول بإسم Post به مجموعة من الأعمدة او الحقول (ثلاثة حقول) وهي كالتالي – رقم المقال – اسم كاتب المقال – جسم المقال. حيث رقم المقال سيكون مفتاح رئيسي – دلالي ومن النوع الفريد بحيث لا يتكرر وستقوم قاعدة البيانات بتوليده تلقائيا.
افتح ملف التهيئة web.config وقم بلصق شفرة الإتصال التالي لقاعدة البيانات التي أنشئتها في الفقرة السابقة لتعمل مع التطبيق:
<connectionStrings> <add name="PostEFDbContext" providerName="System.Data.SqlClient" connectionString="Data Source=(localdb)\v11.0;Initial Catalog=TestDB;Integrated Security=True" /> </connectionStrings>
بالنسبة للجزع الخاص بنص الإتصال كما ترى؛ اسم السيرفر الخاص بقاعدة البيانات هو الذي تم تثبيته مع الفيجوال على جهازي Work station كالتالي (localdb)\v11.0 و في حال كنت تعمل على اسم سيرفر أخر قم بتهيئته بدلا من المكتوب في الجزع الخاص بالإتصال مع قاعدة البيانات ولا تنسى أيضا ان تقوم بكتابة شفرة الإتصال تلك في سطر واحد؛ وان لم تفعل فلن يتم الإتصال بين تطبيقك وقاعدة البيانات.أيضا ستلاحظ ان اسم الإتصال هو PostEFDbContext وهو سيكون اسم الفئة Class التي سننشئها (لاحقا) والتي ستتم عبر تقنية الـ Entity Framework Code First وتكون تلك الفئة مهمتها ربط التطبيق والفئات التي ستكون كجداول مع قاعدة البيانات في الخطوة التالية.وبإمكانك تعريف الإتصال مع قاعدة البيانات بصورة صريحة أيضا إذا أردت من خلال تعريف الـ Constructor لإسم الفئة تلك.
قم بإنشاء فئة Class جديدة بالضغط على المحرك (ماوس) بالزر الأيمن وقم بإختيار Class كما موضع بالصورة التالية … وقم بتسمية الفئة بـ Post.
قم بكتابة الشفرة التالية داخل الفئة Post التي أنشئتها :
public class Post { public int PostID { get; set; } public string AuthorName { get; set; } public string Body { get; set; } }
قم بإنشاء فئة Class أخرى باسم PostEFDbContext وقم بكتابة الشفرة التالية داخلها ولا تنسى استدعاء فضاء الاسماء الخاص بالـ Entity FrameWork:
public class PostEFDbContext : DbContext { public DbSet<Post> Posts { get; set; } }
حسنا … ماذا تعني تلك الفئات Classes التي أنشأناها سابقا؟
الفئة الأولى Post في الحقيقة تحتوي على نفس حقول الجدول الذي أنشأناه في قاعدة البيانات TestDB وهي الفئة المحركة للتطبيق ضمنيا للعمل كأنها الجدول الموجود بقاعدة البيانات خاصتنا. بالنسبة للفئة Class الأخرى PostEFDbContext فهي بمثابة الرابط بين التطبيق وقاعدة اليانات وهنا يأتي دور الـ EF Code First والتي تخبر قاعدة البيانات عن طريق الفرع الخاص بتهيئة الإتصال بملف الـ web.config بأن الفئة PostEFDbContext هي المسؤولة في التطبيق بإعتبارها كجدول وهمي Virtual table يربطنا بالجدول الحقيقي بقاعدة البيانات. وإذا لاحظت الخاصية Property الوحيدة في تلك الفئة اسمها Posts شبيهة بإسم الجدول الذي أنشأناه في قاعدة البيانات. وهذه الفئة ترث من فئة اخرى وهي DbContext ومهمتها تفعيل الجميل الاربعة في اللغة المهيكلة CRUD .
*** الآن قمنا بتهيئة التطبيق للعمل مع قاعدة البيانات…الأن سنقوم بالعمل على كيفية استخدام محرر النصوص TinyMCE للعمل مع الحقل Body ليتيح لنا التنسيق لمحتويات هذا الحقل.
أولا قم بالضغط بالزر الأيمن على المحرك (ماوس) على اسم التطبيق ستظهر لك قائمة قم بإختيار Manage NuGet Packages في محرر نص البحث قم بإدخال TinyMCE كما موضح بالصورة التالية… ستظهر لك المكتبة قم بالضغط على Install لتثبيتها، ستظهر لك شاشة أخرى للتأكيد قم بالضغط على Accept كما موضع بالصورة التالية أيضا.
بإمكانك استخدام الـ Console أيضا اذا لتثبيت المكتبة بكتابة السطر التالي:
PM> Install-packages TinyMCE –Version 4.7.13
في ملف الـScript ستقوم المكتبة بتثبيت ملف جديد باسم tinymce به جميع الملفات الجاهزة للإستخدام للإستفادة من تلك المكتبة.
قم بإنشاء فئة تحكم Controller وقم بإعطائها الإسم HomeController وقم بإختيار الهيكلية الفارغة Empty MVC controller وقم بالضغط على Ok.
قم بلصق الكود التالي على الـ Controller ولا تنسى استدعاء فضاء اسماء ملف الـ Models:
public HomeController() { } private PostEFDbContext _db = new PostEFDbContext(); // // GET: /Home/ [HttpGet] public ActionResult Index() { return View(_db.Posts.ToList()); } [HttpGet] public ActionResult AddPost() { return View(); } [HttpPost] public ActionResult AddPost(Post post) { if (ModelState.IsValid) { Post newpost = _db.Posts.Add(post); _db.SaveChanges(); return RedirectToAction("Index",newpost); } return View(); }
في فئة التحكم تلك لدينا اسلوبين Methods الأولى Index تقوم بعرض جميع الحقول الموجودة بقاعدة البيانات. والثانية AddPost مهمتها إضافة حقل جديد لقاعدة البيانات. وفي اول الفئة قمنا بإنشاء مثيل Instance لفئة تهيئة الاتصال بقاعدة البيانات لتتيح لنا العمل مع الجدول Post الموجود في قاعدة البيانات. أيضا لم نقم بإستخدام الـ Dependency Injection لذلك قمنا بتعريف صريح للـ Constructor الإفتراضي لفئة التحكم نفسها.
ولتبسيط العمل لم أقم بإنشاء فئة Class تكون كمستوع لجميع الإستعلامات للتطبيق Repository بل قمت بكتابة الإستعلامات جميعها في فئة التحكم نفسها.
في الإسلوب AddPost لدينا خاصيتين الاولى لطلب صفحة الـ HTML وتعرف كـ Request والأخرى لحفظ التفاصيل التي نريد اضافتها في الـ Request وتعرف بالـ Response وفي بيئة الـ MVC توجد خاصيتين تعرفان بـ HttpGet والـ HttpPost.
قم بعمل Build للمشروع.
قم بالضغط بالزر الأيمن للمحرك (ماوس) على الإسلوب Index وقم بإختيار Add View وحدد الخواص التالية كما واضحة بالصورة التالية واضغط Ok:
هنا قمنا بإنشاء صفحة الـ Html والتي ستعرض لنا جميع الحقول الموجودة في قاعدة البيانات، قم بلصق الشفرة التالية في صفحة الـ Index:
@model IEnumerable<TinyEditorWithMvcApp.Models.Post> @{ ViewBag.Title = "Index"; Layout = "~/Views/Shared/_Layout.cshtml"; } <h2>All Post</h2> <div id="post"> @foreach (var p in Model) { <p>@p.AuthorName</p> <div id="body"> @Html.Raw(p.Body) </div> } </div>
كرر نفس الخطوة السابقة وأنشئ صفحة Html للإسلوب AddPost وألصق في صفحة الـ Html الشفرة التالية:
@model TinyEditorWithMvcApp.Models.Post @{ ViewBag.Title = "AddPost"; Layout = "~/Views/Shared/_Layout.cshtml"; } <h2>Add new Post</h2> <html> <head> <meta name="viewport" content="width=device-width"/> <title>TintMCE App</title> <script src="~/Scripts/tinymce/tinymce.min.js"></script> <script type="text/javascript"> tinyMCE.init({ mode: "textareas", theme: "modern", plugins: "advlist,code,bbcode,hr,link,paste,save", theme_advanced_toolbar_location: "top", theme_advanced_toolbar_align: "center", theme_advanced_statusbar_location: "bottom", forced_root_block: false, }); </script> </head> <body> <div> @using (Html.BeginForm("AddPost", "Home", FormMethod.Post)) { <div> @Html.TextBoxFor(model=>model.AuthorName) </div> <div> @Html.TextAreaFor(model=>model.Body) </div> <div> <input type="submit" value="Save Post"/> </div> } </div> </body> </html>
في صفحة الـ Html الخاصة بالصفحة AddPost قمنا بعمل مرجع لمكتبة الـ TinyMCE في الـ Element الخاصة بالـ Head من صفحة الـ Html كالتالي:
<script src="~/Scripts/tinymce/tinymce.min.js"></script>
أيضا في نفس الـ Element قمنا بتعريف خواص تلك المكتبة التي نود تهيئتها كالتالي:
<script type="text/javascript"> tinyMCE.init({ theme: "modern", mode: "textareas", plugins: "advlist,code,bbcode,hr,link,paste,save", theme_advanced_toolbar_location: "top", theme_advanced_statusbar_location: "bottom", theme_advanced_toolbar_align: "center", forced_root_block: false, }); </script>
ولو نظرت للصورة التالية بمجرد كتابتك للعنصر tinyMCE ستظهر معك قائمة منسدلة بجميع الأساليب التي يمكنك العمل عليها مع تلك المكتبة
اذا لاحظت هنا قمنا بربط المكتبة مع حقل الـ Body من خلال تعريف الـ mode الخاصة في المكتبة للـ Element التالية Textareas وهي كالمعرّف العادي Id مثلما نفعل عندما نريد تعريف ملف Css عادي فرضا لو كان لدي العلامة Tag التالية:
<div id=”test”> Hello </div>
سأقوم في ملف الـ Css كتعريفها كـ Selector في حال أردت تنسيقها. فالـ mode في مكتبة الـ tinymce تعتبر كـ Selector.
أخيرا قبل تشغيل التطبيق على متصفحك…هنالك شفرة دائما ما أقوم بكتابتها على جميع التطبيقات التي أنشئها بتقنية الـ MVC وهي شفرة تقوم بتسريع عرض صفحة الـ Html لتطبيقاتي…قم بفتح ملف الـ Global وقم بلصق الشفرة التالية في داخل الإسلوب Method التي تسمى Application_Start()
ViewEngines.Engines.Clear(); ViewEngines.Engines.Add(new RazorViewEngine());
لو تذكر بداية التطبيق اخترنا محرك عرض الصفحات Razor ولأن الـ MVC بها محركيين افتراضيين تستخدمها عند تشغيل التطبيق على المتصفح وتقوم بالبحث في الـ Root الخاص بالتطبيق لعرض الصفحة المطلوبة والمحرك الآخر هو WebForm ففي هذه الشفرة قمنا بتنظيف (وليس مسح) جميع المحركات في السطر الأول وفي السطر الثاني حددنا لمنصة الـ MVC ان تقوم بإستخدام الـ Razor فقط بدلا من ان تقوم بالبحث بالمحركين عند طلب صفحة مــا.
الأن قم بتشغيل التطبيق واكتب الرابط التالي:
http://yourport/Home/AddPost
ستظهر معك الصفحة التالية:
بإمكانك أضافة اسم الكاتب وجسم المقالة لديك والضغط على زر الحفظ بعدها سيعرض التطبيق الصفحة الرئيسية Index والتي سيكون بها جميع الحقول التي ستضيفها لقاعدة البيانات.
إذا كنت لا تريد عرض جميع المواضيع بإمكانك إضافة اسلوب Method داخل فئة التحكم Controller ولتكن اسمها على سبيل المثال GetPost وتأخذا معامل Parameter واحد وستكون كالتالي:
[HttpGet] public ActionResult GetPost(int id) { var p = _db.Posts.FirstOrDefault(o=>o.PostID==id); return View(p); }
قم بإنشاء صفحة Html خاصة بها كما شرحنا كيفية ذلك واستخدم الـ Model الخاص بالفئة Post لعرض حقلي اسم الكاتب وجسم المقالة لمقال واحد فقط.
وبإمكانك إستدعائها من على المتصفح كتالي إذا أردت استدعاء المقالة التي تحمل الPostId بالرقم 1:
http://yourport/Home/GetPost/1
الآن تعلمنا العديد من الأشياء:
كيفية استخدام الـ EF Code First
كيفية ربط قاعدة البيانات بالتطبيق.
كيفية تضمين مكتبة محرر النصوص TinyMCE.
كيفية تسريع التطبيق للبحث عن الصفحات في الـ Root الخاصة بالتطبيق.