سلام وقت بخیر
من ثبت نام با موبایل انجام دادم و کد برای کاربر ارسال میشه زمانی که میخام شماره تماس وریفای کنم ارور زیر دارم
Call to a member function activeCode() on null
متد scope وریفای
public function scopeVerifyCode($query , $code, $user)
{
return !! $user->activeCode()->whereCode($code)->where('expired_at' , '>' , now())->first();
}
مشکل از ورودی ها هست ؟ به چه شکل باید بنویسم؟
کدهای کنترلر
public function token(Request $request , User $user)
{
$request->validate([
'token' => 'required'
]);
$status = ActiveCode::verifyCode($request->token , $user->phone);
if(! $status) {
return redirect(route('phone.token'));
}
if(auth()->loginUsingId($user->id,$request->get('auth.remember'))) {
$user->activeCode()->delete();
return redirect('/home');
}
return redirect(route('phone.token'));
}
دوستان لطفا اگه کسی میدونه راهنمایی کنید ممنون میشم
سلام دوست عزیز
scopeVerifyCode که نوشتید $user میخاد
شما user->phone ارسال کردید
$status = ActiveCode::verifyCode($request->token , $user->phone);
phone رو حذف کنید چک کنید .
به شکل زیر
$status = ActiveCode::verifyCode($request->token , $user);
من از scope در لاراول استفاده نکردم ممنون میشم توضیح بدید که چرا برای رفع نیازتون در لاگین از یک متد static که به همین شکل هم بتونید فراخوانی کنید استفاده نکردید؟؟
برداشت من از مستندات چیزی که الان سرچ زدم اینه که جنبه ی استفاده ی زنجیره ای برای کد داره که بتونی یه سری فیلتر داشته باشی و دلیل این که اولین پارامترش هم query هست به صورت پیشفرض همینه و شما اصلا نیاز به query نداشتی پس به نظرم استفاده نادرستی بوده از scope.
ممنون میشم بیشتر توضیح بدید نیت چی بوده .
@salar.mohammad2013
به همین شکل که فرمودید انجام دادم ولی دوباره برمیگرده به همین صفحه ای که کد تایید باید ارسال بشه
من طبق آموزشی که از راکت تهیه کردم پیش رفتم البته تو دوره اعتبارسنجی برای ورود بود نه ثبت نام و من الان میخام یک بار بعد از ثبت نام کد ارسال بشه و برای ورود یوزنیم و پسورد داشته باشم
اینجا هم میخام بعد از اینکه کد تایید ارسال شد و اگه درست بود کد تایید از دیتابیس حذف بشه و کاربر به صفحه مورد نظر هدایت بشه
شما میفرمایید برای وریفای کد نیازی به استفاده از متد scop نیست؟به چه شکل باید بنویسم ؟
ببین مقوله رو برای خودت پیچیده نکن
پسورد که نمیشه داشت و اشتباهه نگهداریش چون باید Hash بشه
بحث ثبت نام یا ورود فرقی با هم در کلیت ندارند وقتی قراره شخصی سازی بشه
شما متدی داری برای تولید یک کد با یک زمان انقضا
کد چک میشه و اگر درست بود کاربر لاگین یا ایجاد میشه که روال رو مشخصه میدونید و مشکل توی پیاده سازیشه.
خب
در مرحله ی اول بیا و متدی که نوشتی رو کامنت کن و کدت رو کامل بنویس بدون متد اجرا کن ببین مشکل چیه
بدون متد اول کارتو راه بنداز
مثلا به شکل زیر
public function token(Request $request , User $user)
{
$request->validate([
'token' => 'required'
]);
$count = $user->activeCode()->whereCode($code)->where('expired_at' , '>' , now())->count();
if(! $count) {
return redirect(route('phone.token'));
}
if(auth()->loginUsingId($user->id,$request->get('auth.remember'))) {
$user->activeCode()->delete();
return redirect('/home');
}
return redirect(route('phone.token'));
}
مورد دیگه بخش اخر کدته
if(auth()->loginUsingId($user->id,$request->get('auth.remember'))) {
کار متد loginUsingIdمشخصه و قراره لاگین کنه طرف رو قرار بر چک کردن نداره که این متد
توی if چرا گزاشتی؟ چیو باهاش چک کنی اخه؟
اصلا بعیده مقدار بازگشتی ای بده توی مستنداتش چیزی بابت مقدار بازگشتش نگفته
if نمیخاد دیگ اگر token اشتباهه ریدایرکت میکنی اگ درسته لاگین میکنی و پاک میکنی توکن های ذخیره شده رو
باز مجدد تهش کد زیر گزاشتی
return redirect(route('phone.token'));
در چه شرایطی قراره این کد اجرا شه؟
یا توکن درست نیست که اول کاری ریدایرکت میکنی
یا درسته که لاگین میکن میفرسی به home حالت سوم جیه؟
به این شکل نوشتم باز برمیگرده به صفحه ای که کاربر باید کد تایید وارد کنه
بله این بخش کلا نمیدونم چطوری پیاده سازی کنم که کد تایید درست بود کاربر هدایت بشه به صفحه home و اگر اشتباه بود تو همون روت بمونه و کد درست وارد کنه
public function token(Request $request , User $user)
{
$request->validate([
'token' => 'required'
]);
$count = $user->activeCode()->whereCode($request->token)->where('expired_at' , '>' , now())->count();
if(! $count) {
return redirect(route('phone.token'));
}
auth()->loginUsingId($user->id,$request->get('auth.remember'));
$user->activeCode()->delete();
return redirect('/home');
}
منظورم از پسورد این هست دفعات بعدی هر وقت کاربر خواست وارد سایت بشه نیازی به ارسال کد از طریق شماره موبایل نباشه و فقط شماره موبایل به عنوان یوزنیم و پسورد وارد کنه
اعتبارسنجی فقط برای ثبت نام میخام اتجام بشه
سلام عزیز
ببین اگر فقط برای ثبت نام میخایی اعتبار سنجی من فرضم اینه که صفحه ی ورود و ثبت نامت یکیه که مشکل داری باهاش وگرنه که دلیلی بر مشکل نیست
خب خیلی راحت کافیه چک کنی این شماره موبایل از قبل ثبت نام کرده یا نه
اگر ثبت نام شده بود توکن نفرستی براش و پسورد ازش بخایی
راه دیگش که بسته به شرایط پیاده سازیت میتونی استفاده کنی اینه که یه فیلد بزاری توی دیتابیس مثلا با نام is_verifaied و به صورت boolean قرار بدیش و بعد از اعتبار سنجی مقدارش true کنی و هر بار اینو چک کنی
در رابطه با مشکل ریدایرکت غلط باید برای هر خط کدت dd بزاری ببینی چه چیزی اونطور که مد نظرته پیش نمیره و داده ی نامتعارفیه.
شاید اصلا نام token اشتباه بود validation تورو ریدایرکتت کنه
کلیت کدت ب نظر اوکیه
خط به خط برو ببین چیه مشکل
سلام
نه فرم ثبت نام و ورود جدا هست
من میخام ثبت نام چندمرحله ای باشه بنظر شما این روش درسته که بعد از اعتبار سنجی کاربر هدایت کنم به صفحه home و اینجا چک کنم که اگر اطلاعات صفحات بعدی وارد شد کاربر به صفحه home دسترسی داشته باشه ؟
و اینجا بیام از isverifaied استفاده کنم و از این طریق بررسی کنم ؟ و تو این شرایط هم باید از نوع boolean باشه ؟
نام توکن درست هست ولی هنوز متوجه مشکل نشدم که چرا اشتباه میخونه
ببینید مگ شما نمیگید از آموزش راکت استفاده میکنید؟
هیچ وقت ما کسی رو به صفحه ای که نمیدونیم دسترسی داره یا نه هدایت نمیکنیم که بعدش بیاییم چک کنیم ببینیم جه خبره
شما باید از middleware auth استفاده کنی که قبل از ریدایرکت چک کنه خودش و اصلا باز نکنه صفحه رو و نیاز به چک کردن شما نباشه دیک کسی که لاگینه دسترسی داره
اگر نه پیشرفته تره موضوع دسترسی پله ای شما باید از gate ها استفاده کنی
توی راکت همون پروژه محور لاراول این موارد رو توضیح داده
مقوله های کوچیکی نیستن که بتونم راحت با تایپ و اینا توضیح بدم
باید سرچ کنی راجبشون زیاد
اگ بتونی این دوره که لینک دادم رو ببینی خیلی خوبه
@salar.mohammad2013
دقیقا همین دوره رو تهیه کردم
ولی تو این دوره برای احراز هویت با لاگین هست و برای ثبت نام نیست
تو این دوره از نوتیفیکیشن و سشن استفاده شده ولی برای این پروژه نیازی به نوتیفیکیشن نیست
منظور هم همینه اول چک بشه
فعلا من تو مرحله اول دارم هدایت میکنم به روت home ولی میخام چک کنم اگه اطلاعات همه وارد شد روت home رو ببینه
برای چک کردنش مثل همون سیستم مدیریت ادمین و کاربر هست درسته ؟ که اگه ادمین بود یه دسترسی باشه و کاربر بود دسترسی دیگه سوال من این هست
چون ثبت نام من چند مرحله ای هست بخوام از سشن استفاده کنم ممکنه کاربر اطلاعاتشو نصفه رها کنه و بعدا بخواد اطلاعات بعدی وارد کنه و اینجا باز به مشکل میخوره
ببین هیچ فرقی توش نیست
برای ثبت نام تو اطلاعات رو میگیری و در نهایت پسورد رو هش میکنی و در جدول یوزر ذخیره میکنیش تموم
مشکل چه بخشیه ک سخته برات؟
من مشکلت رو متوجه نمیشم الان
برای کاربر و ادمین اره باید از middleware استفاده کنی
اگر فقط لاگین مهمه برات middleware(auth) اگ سطح دسترسی داری هم که میتونی از can و gate ها استفاده کنی
در کل برای ثبت نام خودت باید کاربر ایجاد کنی همین
اصلا پیشفرض لاراول در نظر نگیر بساز راحت یک کاربر بعد این که توکن رو اعتبار سنحی کردی
قبلا دنبال کردن و نوتیف داشت بحثا الان نمیبینم
پیامت نمیاد براام
تگم کن توی جوابات که پیام بیاد
@salar.mohammad2013
من اول تو متد register کاربر ایجاد کردم و کد برای کاربر ارسال کردم و کاربر هدایت کردم به روت token
از پیش فرض لاراول هم استفاده نکردم
بعد تو متد token که بالاتر ارسال کردم میخام اعتبارسنجی کنم اگه کد وارد شده درسته کاربر هدایت بشه به صفحه مورد نظر
که دقیقا همینجا مشکل دارم
خب توکن ارسالی رو توی دیتابیس ببین
و request رو هم کامل dd بگیر به ما نشون بده به همراه user
دقیقا اولین خط قبل از validation قرار بده dd
dd($user);
خروجی
App\Models\User {#298 ▼ // app\Http\Controllers\Auth\RegisterController.php:81
#connection: null
#table: null
#primaryKey: "id"
#keyType: "int"
+incrementing: true
#with: []
#withCount: []
+preventsLazyLoading: false
#perPage: 15
+exists: false
+wasRecentlyCreated: false
#escapeWhenCastingToString: false
#attributes: []
#original: []
#changes: []
#casts: []
#classCastCache: []
#attributeCastCache: []
#dates: []
#dateFormat: null
#appends: []
#dispatchesEvents: []
#observables: []
#relations: []
#touches: []
+timestamps: true
#hidden: array:2 [▶]
#visible: []
#fillable: array:17 [▶]
#guarded: array:1 [▶]
#rememberTokenName: "remember_token"
#accessToken: null
}
dd($request);
خروجی
Illuminate\Http\Request {#43 ▼ // app\Http\Controllers\Auth\RegisterController.php:81
+attributes: Symfony\Component\HttpFoundation\ParameterBag {#45 ▶}
+request: Symfony\Component\HttpFoundation\InputBag {#44 ▶}
+query: Symfony\Component\HttpFoundation\InputBag {#51 ▶}
+server: Symfony\Component\HttpFoundation\ServerBag {#47 ▶}
+files: Symfony\Component\HttpFoundation\FileBag {#48 ▶}
+cookies: Symfony\Component\HttpFoundation\InputBag {#46 ▶}
+headers: Symfony\Component\HttpFoundation\HeaderBag {#49 ▶}
#content: null
#languages: null
#charsets: null
#encodings: null
#acceptableContentTypes: null
#pathInfo: "/token"
#requestUri: "/token"
#baseUrl: ""
#basePath: null
#method: "POST"
#format: null
#session: Illuminate\Session\Store {#268 ▶}
#locale: null
#defaultLocale: "en"
-preferredFormat: null
-isHostValid: true
-isForwardedValid: true
#json: null
#convertedFiles: null
#userResolver: Closure($guard = null) {#238 ▶}
#routeResolver: Closure() {#247 ▶}
basePath: ""
format: "html"
}
از این لاین dd گرفتم
$count = $user->activeCode()->whereCode($request->token)->where('expired_at' , '>' , now())->count();
dd($count);
نتیجه
0 // app\Http\Controllers\Auth\RegisterController.php:87
از
dd($user->activeCode());
نتیجه
Illuminate\Database\Eloquent\Relations\HasMany {#312 ▼ // app\Http\Controllers\Auth\RegisterController.php:86
#query: Illuminate\Database\Eloquent\Builder {#311 ▶}
#parent: App\Models\User {#298 ▼
#connection: null
#table: null
#primaryKey: "id"
#keyType: "int"
+incrementing: true
#with: []
#withCount: []
+preventsLazyLoading: false
#perPage: 15
+exists: false
+wasRecentlyCreated: false
#escapeWhenCastingToString: false
#attributes: []
#original: []
#changes: []
#casts: []
#classCastCache: []
#attributeCastCache: []
#dates: []
#dateFormat: null
#appends: []
#dispatchesEvents: []
#observables: []
#relations: []
#touches: []
+timestamps: true
#hidden: array:2 [▶]
#visible: []
#fillable: array:17 [▶]
#guarded: array:1 [▶]
#rememberTokenName: "remember_token"
#accessToken: null
}
#related: App\Models\ActiveCode {#294 ▶}
#foreignKey: "active_codes.user_id"
#localKey: "id"
}
از
dd($request->token);
نتیجه
"681788" // app\Http\Controllers\Auth\RegisterController.php:86
که تو دیتابیس همین کد هست و یکسانه
خب مشکل بازیابی کده
دیتابیس نشون بده با مدلت که رابطه $user->activeCode() رو ببینیم چطور نوشتی
باید count بشه یک دیگه
مشکل اینه
Schema::create('active_codes', function (Blueprint $table) {
$table->bigIncrements('id');
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
$table->integer('code');
$table->unique(['user_id' , 'code']);
$table->timestamp('expired_at');
});
مدل user
public function activeCode()
{
return $this->hasMany(ActiveCode::class);
}
@salar.mohammad2013
خروجی
Illuminate\Database\Eloquent\Collection {#1097 ▼ // app\Http\Controllers\Auth\RegisterController.php:81
#items: []
#escapeWhenCastingToString: false
}
یه مورد توی دیتابیست
شما id داری که باید table-> id مینویشتی مثلا که همون primary و uniqe باشه
وقتی کد ایجاد میکنی باید unique بودن چک کنی که چون کد های قبلی طرف رو هر بار پاک میکنی حتی نیاز به این unique نوشتن دو فیلد از نظر من نبود
میدونی حتی تکراری هم تولید و ذخیره هم حتی بکنی چون برای زمان expire بررسی میکنی بازم مورد دار نمیشد
میتونستی id نزاری و این دو فیلد رو primary کنی
الان کلید اصلی نزاشتی برا این جدول که معرف باشه قانونا id هست ولی نگفتی primary
آیا مایل به ارسال نوتیفیکیشن و اخبار از طرف راکت هستید ؟