-
المساهمات
1690 -
تاريخ الانضمام
-
تاريخ آخر زيارة
-
عدد الأيام التي تصدر بها
2
نوع المحتوى
ريادة الأعمال
البرمجة
التصميم
DevOps
التسويق والمبيعات
العمل الحر
البرامج والتطبيقات
آخر التحديثات
قصص نجاح
أسئلة وأجوبة
كتب
دورات
كل منشورات العضو شرف الدين حفني
-
ال stream هي واجهة تتيح للمبرمج قراءة وكتابة البيانات بشكل متواصل , في العادي إن أردت قراءة ملف ما تقوم بالتالي fs.readFile('/test.txt, 'utf8' , (err, data) => { if (err) { console.error(err) return } console.log(data) }) هنا تقوم الnode js بقراءة الملف كله على الذاكرة ومن ثم يمكنك إجراء العمليات عليه, هنا يوجد مشكلتان ﻻ يمكنك إجراء عمليات على الملف قبل إنتهاء قرائته كلياً إن كان حجم الملف كبير لن تستطيع الذاكرة إستيعابه مما قد يؤدى إلى خطأ Stack over flow ومن هنا يظهر دور الstream حيث تقوم بقراءة البيانات قطعة قطعة const fileSystem = require("fs"); var data = ""; const readStream = fileSystem.createReadStream("test.txt"); readStream.setEncoding("UTF8"); readStream.on("data", (chunk) => { data += chunk; }); readStream.on("end", () => { console.log(data); }); في هذا الكود قمنا بعمل إستماع للحدث(event listening) حيث كل مرة تصل فيها جزأ من البيانات يتم إطﻻق الحدث وتنفيذ الكود readStream.on("data", (chunk) => { data += chunk; }); وعند إنتهاء البيانات يتم إطﻻق حدث الإنتهاء وتنفيذ الكود readStream.on("end", () => { console.log(data); }); وكما تﻻحظ حتى نستطيع إستخدام الstream قمنا بإنشاء ما يسمى بالreadStream , وهى الstream التي تمكننا من قراءة البيانات ووجه عام يوجد أربع أنواع من الstream readable stream: مسؤلة عن قراءة البيانات writable stream: مسؤلة عن كتابة البيانات duplex stream: يمكنها قراءة البيانات وكتابة البيانات transform stream: تقوم بقراءة البيانات ومعالجتها بشكلٍ ما ومن ثم كتابتها بعد المعالجة
-
كلمة synchronized تستخدم من أجل منع أن يقوم اكثر من thread بالدخول إلى الدالة في نفس الوقت فمثلاً إن كان لدينا الكود اﻵتي public void getNumber() { setNumber(getNumber() + 1); } والذي يقوم بحساب عدد المرات التي يتم نداء الدالة فيها ,وكان لدينا إثنان threads وكلاً منهما حاول الدخول إلى نفس الدالة في ذات الوقت, وكان لدينا قيمة إبتدائية Number تساوي 5, فإذا من المفترض أن تكون قيمة الرقم ب7 , لكن بسبب دخول كﻻً من الthreads في نفس ذات الوقت نجد أن الرقم أصبح 6, لو كانت تلك المعلومات حساسة سيتسبب ذلك في مشاكل كثيرة , ولحل تلك المشكلة نقوم بجعلها thread safe عن طريق إضافة الكلمة synchronized والتي بدورها تجعل الدالة غير قابل الدخول عليها من قِبل أكثر من thread فيكون شكلها كالأتي public synchronized void getNumber() { setNumber(getNumber() + 1); } ومن الممكن أيضا إضافة الكلمة إلى blockمن الكود ليس دالة فقط, public void getTheCountOfThreads(){ synchronized (this) { setCount(getCount()+1); } }
-
post تستخدم عادةً لإنشاء العناصر بينما put تستخدم عادةً للتعديل , ولكن من الممكن في الput يقوم المستخدم بتحديد الرابط كليا مثلاً api/user/45 حيث هنا 45 هو المعرف الخاص بالمستخدم, بينما في post ﻻ نكن نعلم بعد رقم المعرف فيكتب /api/user إن قمت بإرسال نفس طلب الput مراراً وتكرارً ستحصل على نفس النتيجة بينما إن ارسلت نفس طلب الpost ستحصل كل مرة على نتيجة مختلفة يمكن عمل كاشينج للput بينما هذا غير ممكن للpost
-
مفهوم تعقيد الوقت(time complexity) يعبر عن الوقت الﻻزم لتنفيذ الخوارزمية, ولكن ﻻ يتم حسابه بالثانية أو الدقيقة بل بعدد السطور البرمجية أو بمعنى أصح عدد التعليمات البرمجية, فمثلاً إذا كان لدينا خوارزمية تقوم بالتالي: قراءة قيمة من المستخدم ضرب القيمة في عشرة طباعة القيمة الجديدة هنا نستطيع أن نقول أن عدد السطور البرمجية التي تم تنفيذها ثلث أسطر, ولكن تعقيد الوقت هنا يساوي 1, ما السبب؟ السبب أن تعقيد الوقت يتم حسابه بالنسبة للمدخلات, فمثلاً في المثال السابق لن يفرق إن أدخل المستخدم 10 أو 100 أو 11000000 في كل تلك الحالات سيكون لدينا نفس عدد التعليمات البرمجية, بينما إن قمنا بإنشاء البرنامج التالي: خذ مجموعة عناصر من المستخدم قم بزيادة رقم واحد على كل عنصر منهم إطبع العناصر الجديدة في تلك الحالة كل مازاد عدد العناصر زاد عدد التعليمات البرمجية التي يقوم الحاسب بتنفيذها ويوجد عدة طرق لحساب التعقيد الوقتي مثل: BigO: والتي تعبر عن القيمة التي يكون الوقت اقل او مساوى لها Big Omega: تعبر القيمة التي يكون الوقت اكبر او مساوي لها Big Theta: تعبر عن القيمة التي يكون الوقت مساوي لها أو نستطيع أن نقول أن ال BigO يعبر عن اسوأ حالة للخوارزمية, بينما الBig Omega يعبر عن افضل حالة للخوارزمية بينما Big Theta تعبر عن الحالة المتوسطة
- 1 جواب
-
- 1
-
حتى تفهم الفرق بينهما يجب أن نتكلم عن المشاكل التي يقومان بحلها, قبل وجود الwebsockets كان للحصول على بيانات يقوم العميل بإرسال طلب ويقوم الخادم بإرسال رد, ومن ثم ينغلق الإتصال بينهما , حسناً في حالة إن أردنا الحصول على بيانات حية (real time data) لم يكن ذلك سهلاً, فكان يجب عليك أن تقوم بإرسال طلب كل فترة زمنية قصيرة للحصول على أحدث البيانات setInterval(function(){ fetch(url) .then(res=>data=res.data) },1000) كالمثال في الأعلى, يقوم العميل بإرسال طلب كل ثانية بغرض التأكد من أن البيانات التي لديه هي أحدث بيانات لدى السيرفر, ولكن تلك الطريقة لم تكن جيدة بشكل كبير حيث أن تكلفة إرسال ومعالجة الطلب والرد كل ثانية مجهد بالنسبة لكلاً من الخادم والعميل وهنا تم إنشاء الwebsocket وهى بإختصار عبارة عن طبقة من الإتصال مبنية فوق بروتوكول http2 فكرتها أن يقوم العميل بإرسال طلب الإتصال حتى يتم فتح إتصال بينه وبين الخادم ومن ثم يكون كلاً من الخادم والعميل قادرين على إرسال وإستقبال الرسائل في اي وقت دون الحاجة لإنشاء طلب جديد كل مرةٍ . إذا ما هى الsocket.io? هي مكتبة يتم إستخدامها للتعامل مع البيانات الحية , تم بناؤها فوق الwebsocket ولها مميزات عديدة عن إستخدامك الwebsocket ,فمثﻻً بعض المتصفحات القديمة لا تدعم إستخدام الwebsocket في هذه الحالة تقوم الsocket.io بإستخدام الطريقة التقليدية للتعامل مع البيانات الحية , أيضا تقوم بإعادة الإتصال في حالة إنقطاعه بشكل تلقائى, على عكس الwebsocket لم تكن تقوم بإعادته تلقائياً بل كان يجب عليك أن تقوم بتلك المهمة بنفسك
- 4 اجابة
-
- 1
-
الكود النظيف clean code بإختصار هو الشفرة البرمجية السهل قرائتها والتعديل عليها, ولها عدد من الخصائص يمكن كتابتها على الشكل الأتي من السهل عند قرائته أن تفهم كيف يتم تنفيذه بشكل واضح من السهل أن تفهم عﻻقة الكائنات ببعضها البعض, فإذا كان لديناclass يسمى user و اخر يسمى bookفمن السهل معرفة ما العﻻقة بين المستخدم والكتاب من السهل معرفة وظيفة كل class وكل دالة, حيث يتم تقسيم الدوال والclasses بحيث يكون لكل فرد منهم وظيفة محدد ﻻ أكثر من السهل معرفة غرض كل متغير وكل سطر في الشيفرة البرمجية فﻻ يكون لديك متغيرات بأسامي مبهمة أو في مواضع عشوائية تصعب عملية الفهم على من يقرأ الشفرة الدوال تكون صغيرة ولكل class او دالة مسؤلية فﻻ يمكن أن تكون دالة مسؤلة عن الجمع وطباعة الناتج في نفس الوقت, بل تقسيمها إلى دالتين , واحدة للجمع والأخرى من أجل الطباعة وجود توثيق للدوال والclasses للرجوع إليه وقت الحاجة ليسهل الفهم يمكن توقع سلوك الدوال والclasses بسهولة سهل التعديل عليه
-
انماط التصميم(design patterns) ترمز لطريقة معينة لحل مشكلة شائعة نوعا ما في عالم الSoftware , مثلاً نوع من المشاكل هو كيفية إنشاء الكائنات؟ يوجد عدد ﻻ نهائي من الطرق لإنشاء الكائنات بالتأكيد حسب الموقف ولكن يوجد مواقف شائعة يمكننا مناقشتها والإهتمام بها, مثلاً إن كنا نريد إنشاء كائن وكان هذا الكائن لديه الصفات الأتية هذا الكائن مشترك بين عدد من الكائنات في البرنامج عملية إنشاء الكائن مكلفة وتستهلك كميةً لا بأس بها من موارد الجهاز هذا الكائن ليس له state معينة, او الstate الخاصة به مشتركة بين الكائنات في البرنامج طوال دورة حياة البرنامج( الstate نقصد بها حالة الكائن ,مثلاً إن كان يعبر عن إتصال بقاعدة البيانات, فهل حالة الكائن هي أن الإتصال مفتوح ؟ أم تم إغﻻق الإتصال؟ في هذه الحالة ليس من العقل أن نقوم بإنشاء الكائن في كل مرة نحتاجه بها , من المنطقي أن نقوم بإنشاء ذلك الكائن مرة واحدة ويقوم باقي الكائنات بإستدعائه في كل مرة كما في المثال الأتي class singleTone{ private static singleTone obj=new singleTone(); private singleTone(){} public static singleTone getInstance(){ return obj; } } الconstructor الخاصة بهذا الclass من النوع الخاص privateمما يعنى أن لا يمكننا إنشاء كائنات منه, الطريقة الوحيدة للحصول على كائن منه هي مناداة الدالة getInstance والتي بدورها تقوم بإرجاع الكائن الذي قمنا بإنشاءه سابقاً في بداية الclass , ففي هذه الحالة نستطيع ضمان أن لن يتم إنشاء هذا الكائن أكثر من مرة , وبالمناسبة هذا النمط يُسمى بال singletone pattern وقد وضعته حتى أوضح لك معنى انماط التصميم بشكل أفضل
- 3 اجابة
-
- 1
-
الlet يكون مجاله بداخل القوسين الذي عرف بداخلهم , بينما الvar يكون مجاله ضمن الدالة التي عرف بها, لنفهم هذا الأمر سنكتب الكود التالي كمثال: function print() { var firtname = "sharaf"; let lastname = "ashraf"; console.log(firtname, lastname); // sharaf ashraf { var fname = "sharaf1" let lname = "ashraf1"; console.log(fname, lname); // sharaf1 ashraf1 } console.log(fname); // sharaf1 console.log(lname); // ReferenceError } run(); نﻻحظ ان كلا من المتغيرين fname, lname تم تعريفهم في نفس المجال, لكن على الرغم من ذلك عند طباعتنا لهم خارج الأقواس, يتم طباعة المتغير fname لأنه من النوع var ولكن يحدث خطأ عند محاولة طباعة lname لأنه من النوع let كما بالإضافة إلى أن عند تعريف المتغير من النوع var يتم إعطائه قيمة إبتدائية ب"غير معرف" حتى قبل إنشائه, بينما المتغير let إن حاولنا الوصول إليه قبل تعريف لا يأتينا قيمة "غير معرف" إنما يأتينا خطأ من النوع ReferenceError
-
السؤال غير واضح بشكل ما, هل تريد تغيير الurl ام تغيير المتغيرات في router.query ? + ماذا تريد ان تحقق بالظبط حتى أستطيع مساعدتك
-
يوجد عدد من الclasses تمت إضافتها وأخرون تمت إزالتهم, أمثلة على ما تمت إزالته : orm – row form – inline list – inline card – deck حيث كان لهم وجود في الإصدار 4 ولكن تمت إزالتهم من الإصدار الخامس. أمثلة على ماتمت إضافته: gx-* (للتحكم في المسافة الأفقية بين العواميد) gy-* (للتحكم في المسافة الرأسية بين الصفوف) g-* (للتحكم في كلاً من المسافات الرأسية والعمودية) ويوجد عدد كبير من الإختﻻفات الأخرى بين الإصدارين مثل: لدى نظام الشبكات(grid system) في الإصدار الرابع 5 طبقات xs,sm,md,lg,xl بينما تمت إضافة طبقة جديدة للإصدار الخامس وهي الطبقة xxl للشاشات الأكبر حجماً لدى الإصدار الخامس دعم أكثر للألوان حيث يحتوي على عدد من الألوان أكبر من الإصدار السابق له تم التخلي عن إستخدام الjquery في الإصدار الخامس والإعتماد على الجافاسكريبت دون مكتبات تم التوقف عن دعم متصفح internet explorer الإصدارين 10&11 مظهر عناصر الformأصبح ثابتا على جميع أنظمة التشغيل, بينما كان متغيراً حسب نظام التشغيل في الإصدار السابق تلك أمثلة من الإختلافات ,لم اذكر لك جميع الإختلافات حتى لا تشعر بالتشتيت , إن أردت ذكرها لك يمكننى ذلك, تحياتى
-
هذه المشكلة تظهر عند عمل import لل draft.js عند العمل بnext js سبب الخطأ هو ان next jsتعمل على كلاً من العميل والخادم , وال window لا يعمل إلا عند العميل, فعند تشغيل الكود عند الخادم لا يعمل بشكل جيد , والحل أن تقوم بعمل import بعد أن يتم تحميل الصفحة, أى في الدالة componentDidMount او في الuseEffect hook إن كنت تستخدم الfunctional components, نقوم أولا بتعريف متغير يحمل component فارغ لحجز الdraft Editor let Editor = () => <></>; ثم نقوم بعمل state لل Editor [editorState, setEditorState] = useState(); بعدها نقوم بإستدعاء draftووضع قيمتها في المتغير الفارغ في الuseEffect useEffect(() => { Editor = require("react-draft-wysiwyg").Editor; setEditorState(true) },[]); ومن ثم عند عمل returnلل component ضع شرط اولاً ان يكون ال EditorState معرفة
-
الإثنان يتم إستخدامهما بنفس الطريقة لأن كﻻهما يقوم بعمل implement لنفس الواجهة البرمجية list ولكن يوجد فرق في طريقة عمل كل منهما: الarrayList تقوم بإستخدام الarray من أجل تخزين العناصر, بينما الLinkedList تقوم بإستخدام نوع من هياكل البيانات الذي يدعى doublyLinkedList والذي يعتمد بشكل أساسي على أن لكل عنصر ثﻻث خواص وهما القيمة, العنصر التالي, والعنصر السابق , على عكس المصفوفة التي تقوم بتخزين كل عنصر وتصل إليه بإستخدام الفهرسindex فﻻ يوجد عﻻقة بين العناصر وبعضها يوجد فرق في الأداء بينهما عند القيام على عمليات الإضافة والحذف على العناصر, حيث الlinkedList كما ذكرنا سابقاً تعتمد على ان لكل عنصر خواص القيمة والتالي والسابق, فإذا أردنا جدﻻ إضافة عنصر يمكن ذلك بكل سهولة عن طريق الإشارة إليه كما موضح من الشكل element a{ value:"sharaf", next: b } element b{ value"ashraf" next : null } إذا اردنا إضافة عنصر يمكن ذلك بسهولة عن طريق تعديل قيمة الخاصية next في العنصر b بينما في الarrayLit بسبب أنها تعتمد على المصفوفة في تخزين البيانات فيجب أن تقوم بحذف المصفوفة كلها وبنائها من جديد حتى تستطيع إضافة عنصر أو حذف عنصر الlinkedList يتصرف كlistلانه يقوم بعمل implement للlist interface بالإضافة لقيامه بعمل الdeque لأنه يقوم بعمل implement لواجهته , على عكس الarrayList التي تتصرف فقط ك list بوجه عام أداء الarrayList يتفوق في حالة إعتماد التطبيق على تخزين البيانات والوصول إليها بينما الLinkedList تتفوق في حالة إعتماد التطبيق على إضافة ومسح العناصر بشكل متردد
-
يوجد عدد من الفروقات بينهما يمكن وضعه في النقاط اﻵتية تكرار العناصر, القائمة "list"تسمح بتكرار العناصر بينما المجموعة "set" ﻻ تسمح بتكرار العناصر عند إضافة عناصر في القائمة يتم ظهورهم بنفس ترتيب إدخالهم, بينما في المجموعة ﻻ يتم الترتيب حسب الإدخال في القائمة يمكن الحصول على العنصر بإستخدام الindex بينمة في المجموعة ﻻ يمكن يتم إستخدام القائمة عادة عندما نريد الوصول إلى العناصر بشكل مستمر بإستخدام موقعهم في القائمة, بينما المجموعة يُفضل إستخدامها عندما نريد إنشاء مجموعة من العناصر المختلفة بدون تكرار
-
next js تختلف قليلاً عن إستخدامك للReact بدونها, في react كان بإمكانك فقط ان تضع الرابط للapi في ملف الpackage.json { ///dependency proxy:"www.example.com/" } ,ولكن في next js الأمر مختلف قليلاً فيجب عليك أن تقوم بعمل redirect للطلبات بدلا من أن تنتقل إلى الخادم الخاص بnext js تقوم بالإنتقال إلى الخادم الخارجى, يمكنك القيام بذلك بالتعديل على ملف الnext.js.config module.exports={ rewrites:async()=>{ return [ source:"/api/*", destination:"your api url" ] } } حيث تقوم بوضع الرابط الخاص بالapi لديكك في الdestination وتضع العنوان البديل في الsource , الأن متى قمت بإرسال طلبات إلى /api/ سيتم تحويلها إلى الapi في الdestination
-
لا يمكنك الحصول عليها بإستخدام getStaticProps لأن دالة الgetStaticProps والgetStaticPaths يتم تنفيذهم في الstatic site generation بينما الquery يتم تمريرها وقت التشغيل, من الممكن تنفيذ ما تريده بإستخدام getServerSideProps بدلاً منها كما في الشكل الأتي export async function getServerSideProps(context) { const query = { context } const { id } = query const user = await getUsers(id) return { props: { users } } } وتستطيع إستلام الusers في الcomponent كما بالشكل الأتى export default function UsersPage({ users}) { return ( <h1>hello world</h1> ) }
-
لتستطيع مناداة حقل من الكائنات التي بينها علاقة يمكنك إنشاء دوال في الكائنات حتى تساعد على إرجاع الحقل المطلوب , فمثلاً في حالتك تريد أن تحصل على إسم المؤلف, إذا يمكنك أولا إنشاء دالة عند الكتاب تساعدك على ذلك class PostAdmin(admin.ModelAdmin): list_display = ['title', 'get_author', ] def get_name(self, obj): return obj.author.name get_name.short_description = 'author_name' #Renames column head ومن ثم يمكنك في ملف الPerson أن تضع إسم هذه الدالة في الlist_display class PersonAdmin(admin.ModelAdmin): list_display = ['post.author_name',]
- 3 اجابة
-
- 1
-
الcharfield يحمل كحد أقصى 255 حرف, بينما الtextfield ليس لديه حد معين ويرجع ذلك إلى إختلاف الأنواع الموجودة في قواعد البيانات, حيث أنه يوجد varchar والتي يجب أن يكون لديه طول معين كحد أقصى ع عكس انواع مثل الText او الclob التي ليس لديها حد أقصى ,فعند إستخدام الtextfield يتم إنشاء تلك الأنواع التي ليس لها طول محدد, بينما عند إستخدام الcharfield يتم تحويله في قاعدة البيانات إلىvarchar(255) وعامةً متى وجدت البيانات لديها حد أقصى من الطول مثل الإسم أو العنوان فيفضل إستخدام الcharfield بينما البيانات الأخرى التي ليس لها طول ثابت مثل محتوى المقالة, وصف المنتج فيجب إستخدام الtextfield
- 2 اجابة
-
- 1
-
هل تقصد goto كما في لغة c++? إن كان ذلك مقصدك فإن react js ليست لغة وإنما هي مكتبة , السؤال الصحيح هل يمكن إستخدامها في لغة جافاسكريبت أم لا, للأسف جافاسكريبت لا تدعم الgoto ولكن ت دعم أشياء مشابهة مثل break تقوم بإستخدامها لإنهاء الحلقة التكرارية for, while ,do while for(i=0;i<5;i++){ console.log(i) if(i==3) break; } ستلاحظ أن ناتج الطباعة 1 2 3 لأن من بعد الرقم 3 تم إستخدام الكلمة break التي أنهت الحلقة continue بدلاً من الخروج من الحلقة فإنها تقوم فقط بتخطي اللفة الحالية for(int i=0; i<5;i++){ if(i==3) continue; console.log(i) } تلاحظ طباعة 1 2 4 5 , رقم 3 لم يطبع لأنه تم الخروج من اللفة وقتها
-
هذا الخطأ يُسمى CORS (خطأ اشتراك المصادر في الموارد) هذا الخطأ يحدث عندما يحاول موقع الوصول إلى موارد موجودة على نطاق أخر غير نطاقه, ولحل هذه المشكلة نتبع الخطوات الأتية : تثبيت الcors module npm i cors نقوم بإستدعاؤه const express = require('express') const cors = require('cors') const app = express() نقوم بوضعه كبرمجية وسيطة(middleware) app.use(cors({ origin: '*' })) إذا كنت تريد ان تجعل الapi متاحة لنطاقات معينة فلتمسح علامة ال* وضع بدلاً منها النطاقات
-
أولاً نقم بتثبيت mutler npm i multer بعد ذلك نقوم بإستدعائه والسماح لExpress بإستقبال البيانات من الforms عن طريق الbody-parser const multer = require('multer'); app.use(bodyParser.urlencoded({extended: true})) ونقم بإنشاء متغير الupload الخاص بmulter كما في الشفرة: var upload = multer({ dist:"your distination" }) عند الendpoint التي تريد إستقبال الملف فيها تضع اول parameter عنوان الendpoint والثاني upload.single('file') والثالث الدالة الخاصة بالendpoint ,ومن ثم يمكنك الوصول إلى الملف بإستخدام req.file
-
الcomposition وال aggregation هما نوعين من الإرتباط (association) ولكن يوجد عدة فروقات بينهما فمثلًا بالنسبة للcomposition تعنى أن العلاقة بينهما علاقة جزأية , بمعنى أن أحد الكائنين هو جزأ من الآخر ,كما هو الحال في المبنى وقالب الطوب أو السيارة والمحرك, فكل من المحرك وقالب الطوب هما أجزاء من المبنى والسيارة كل من الكائنين يعتمد على الأخر فلا يوجد سيارة بدون محرك ولا محرك بدون سيارة إذا كان هناك علاقة تركيب(composition) فلا يمكن للكائن المٌركب(composed) أن يتواجد بدون الكائن الأخر الaggregation تعنى أن العلاقة بينهم علاقة احتواء (has-a relationship) بمعنى أن الكائن الأول والثاني كل منهم يحتوي على الأخر ولكن بدون أن يكون جزأ منه مثل العلاقة بين المستخدم والمنشورات التي نشرها علاقة احادية الإتجاه, بمعنى أن المستخدم يمتلك المنشورات, لكن المنشورات لا تمتلك المستخدم لا تعتمد كائنات تلك العلاقة على بعضهم, فإذا حدث شئ للمستخدم لا يؤثر على المنشور ولا يؤثر المنشور على المستخدم
-
تريد تخزين الصور في قاعدة البيانات ام على المساحة التخزينية؟
-
أعتقد سبب المشكلة أنك في الحقيقة لا تستخدم mysql وإنما تستخدم mariadb إذا كنت تستخدم xampp فإعلم أن قاعدة البيانات الإفتراضية هي mariadb والتي تختلف قواعد كتابتها قليلًا عن قاعدة بيانات mysql ,لديك حلين أن تقوم بتحميل قاعدة بيانات mysql وتعمل عليها الحل الأسهل أن تقوم بتغيير الكود حتى يكون مناسب مع mariadb كما في الشكل الآتي CREATE TRIGGER `on_comment` BEFORE INSERT ON `article_likers` FOR EACH ROW update articles set likes=likes+1 where articles.id= NEW.article_id حيث أن المشكلة تكمن في كلمتين BEGIN--END , عند إزالتهم ستلحظ أن الخطأ لم يعد موجودًا