我正在开发一个用户生成的内容博客,该博客允许用户在提示注册之前完成整个上传过程。基本流程:填写表单以选择用户名/基本信息 - >上传博客帖子>提示用电子邮件/密码注册。扭转正常流量的目的是提高用户体验和转换率,并在开始时避免堵塞。
我没有迁移,而是在PHPmyAdmin中手动创建表。我有3个关系模型:Usermeta-> hasOne(App \ Mopdels \ Post),Post-> belongsTo(App \ Models \ Usermeta),User-> belongsTo(App \ Models \ Usermeta)。
我遇到的问题是,一旦用户创建了用户名并将第一个表单提交到usermeta表,然后提交第二个表单以将他们的博客帖子上传到帖子表,它就没有&#39 ; t似乎将usermeta.id附加到posts.usermeta_id将它们链接在一起。我必须遗漏一些东西或者没有正确地附上它。这是我的StoryController:
<?php
namespace App\Controllers\Story;
use App\Models\Post;
use App\Models\User;
use App\Models\Usermeta;
use App\Controllers\Controller;
use Respect\Validation\Validator as v;
class StoryUploadController extends Controller
{
public function guidance($request, $response)
{
return $this->view->render($response, 'storyupload/guidance.twig');
}
//set up our the Upload Story class so the user can upload their story
//render the view 'uploadstory.twig'
public function getStoryUpload($request, $response)
{
return $this->view->render($response, 'storyupload/upload.twig');
}
// This method is called when the user submits the final form
public function postStoryUpload($request, $response, $id)
{
//set up our validation rules for our complete sign up form
$validation = $this->validator->validate($request, [
'title' => v::stringType()->notEmpty()->length(1, 80),
'body' => v::stringType()->notEmpty()->length(1, 2500),
]);
//if validation fails, stay on story upload page
if ($validation->failed()) {
return $response->withRedirect($this->router>pathFor('storyupload.upload'));
}
$user = Usermeta::find($id)->first();
//We can use our Post Model to send the form data to the database
$post = Post::create([
'title' => $request->getParam('title'),
'body' => $request->getParam('body'),
'category' => $request->getParam('category'),
'files' => $request->getParam('img_path'),
'usermeta_id' => usermeta()->attach($user->id),
]);
//after submit, redirect to completesignup page
return $response->withRedirect($this->router->pathFor('auth.completesignup'));
}
}
我继续收到错误&#39; usermeta_id不能为空&#39;所以它绝对不能正确地从usermeta表中提取id。 我已经使用create()方法将usermeta数据发送到我的Auth控制器中的表。
在Auth控制器中提交所有表单提交是否更好?使用我的示例确保我的posts.usermeta_id链接到我的usermeta.id的正确方法是什么?
usermeta表单由我的Auth Controller负责:
//render the view 'signup.twig'
public function getSignUp($request, $response)
{
return $this->view->render($response, 'auth/signup.twig');
}
// This method is called when the user submits the form
public function postSignUp($request, $response)
{
$validation = $this->validator->validate($request, [
'name' => v::notEmpty()->alpha(),
'username' => v::noWhitespace()->notEmpty()->UsernameAvailable(),
'city' => v::notEmpty()->alpha(),
'country' => v::notEmpty()->alpha(),
]);
//if validation fails, stay on signup page
if ($validation->failed()) {
return $response->withRedirect($this->router->pathFor('auth.signup'));
}
$usermeta = Usermeta::create([
'name' => $request->getParam('name'),
'username' => $request->getParam('username'),
'city' => $request->getParam('city'),
'country' => $request->getParam('country'),
'share_location' => $request->getParam('share_location'),
]);
//after submit, redirect to storyupload/guidance
return $response->withRedirect($this->router>pathFor('storyupload.guidance'));
}
答案 0 :(得分:1)
我在这里写了很多。要直接跳到我认为可以解决您的问题,请参阅&#34;您的问题&#34;部分。剩下的就是教育活动。
正如您可能已经知道的那样,&#34;关系&#34;在Laravel中是从数据库中的硬数据派生的虚拟概念。因为它们是虚拟的,所以关系的定义有一些重叠。
当你说&#34; Usermeta有一个帖子&#34; - 这意味着posts
表将有一个usermeta_id
字段。
当你说&#34; Post属于Usermeta&#34; - 这意味着posts
表将有一个usermeta_id
字段。
请注意,这两个关系映射到完全相同的表中的完全相同的字段。声明一个关系将通过简单的同余来声明另一个关系。 &#34; Usermeta有一个帖子&#34;和&#34; Post属于Usermeta&#34;是相同的关系。
另一个共享同一模式的关系(posts
表有一个usermeta_id
字段)。那就是&#34; Usermeta 有很多帖子&#34;。这里的区别不在于如何将关系存储到数据库中,而在于Laravel如何解释关系以及Laravel将运行的查询。
当您说&#34; Usermeta有一个发布&#34;时,Laravel将扫描数据库以查找匹配usermeta_id
的第一个帖子,将其作为Usermeta模型的一个实例返回。
当您说&#34; Usermeta有很多帖子&#34;时,Laravel将扫描数据库以查找匹配usermeta_id
的所有并将其作为Usermeta模型的集合。您可能想要这第二种行为 - 否则用户在注册后无法再发帖。
usermeta_id
字段Laravel允许您通过关系直接设置数据库字段。 See their documentation on inserting related models for details
由于许多关系只是同一底层架构的密码,因此无需双向插入或更新相关模型。例如,假设我们有以下两个模型:
class User extends Eloquent {
public function posts() {
return $this->hasMany("App\Post");
}
}
class Post extends Eloquent {
public function user() {
return $this->belongsTo("App\User");
}
}
在这种情况下,以下两行代码是相同的,您只需要使用其中一行:
$post->user()->associate($user);
$user->posts()->save($post);
这两个效果都相同(在user_id
表上设置posts
字段)
我提到这一点的原因是,您似乎正在尝试重复使用代码。您正在使用attach()
(可以想象设置usermeta_id
)并且您还要直接设置usermeta_id
。我已在下面的attach
方法中添加了附注 - 因为我不相信它是正确的方法。
要使用Laravel的关系,您需要以下代码来设置此字段:
public function postStoryUpload($request, $response, $id)
{
//set up our validation rules for our complete sign up form
$validation = $this->validator->validate($request, [
'title' => v::stringType()->notEmpty()->length(1, 80),
'body' => v::stringType()->notEmpty()->length(1, 2500),
]);
//if validation fails, stay on story upload page
if ($validation->failed()) {
return $response->withRedirect($this->router>pathFor('storyupload.upload'));
}
$user = Usermeta::find($id)->first();
//We can use our Post Model to send the form data to the database
$post = Post::create([
'title' => $request->getParam('title'),
'body' => $request->getParam('body'),
'category' => $request->getParam('category'),
'files' => $request->getParam('img_path'),
]);
// Set the usermeta_id field
$post->usermeta()->associate($user);
// Save the model so we write changes to the database
$post->save();
//after submit, redirect to completesignup page
return $response->withRedirect($this->router->pathFor('auth.completesignup'));
}
usermeta_id
字段您可以手动设置字段,而不是使用Laravel关系来设置此字段。这有时可能更干净,但它不那么明确,如果你不小心,可能会导致小错误。为此,您需要将usermeta_id
字段视为模型上的任何其他字段。
$post->usermeta_id = $user->id;
当使用fill
或create
批量分配属性时,这也适用:
$post = \App\Post::create([
'title' => $title,
'body' => $body,
'usermeta_id' => $user->id
]);
$post->fill([
'title' => $title,
'body' => $body,
'usermeta_id' => $user->id
]);
请注意,手动设置usermeta_id
时,不需要使用任何关系方法。以下代码是多余的:
$post->usermeta_id = $user->id;
$post->usermeta()->associate($user);
fillable
或guarded
属性。
这是任何Laravel代码中最常见的错误之一,如果不是最常见错误 - 并且它不会引发明显的错误,因此很容易小姐。考虑以下模型:
class Post extends Eloquent {
private $fillable = ["title", "body"];
}
如果您尝试批量分配usermeta_id
字段,请执行以下操作:
$post = \App\Post::create([
'title' => $title,
'body' => $body,
'usermeta_id' => $user->id
]);
然后默默地失败。不会抛出任何错误,Post
已创建,但usermeta_id
字段将为NULL
- 因为它不是可分配的。这可以通过更新您的模型来解决:
class Post extends Eloquent {
private $fillable = ["title", "body", "usermeta_id"];
}
我将再次重复,如上所述,如果使用这样的质量分配,则不需要使用associate
或save
关系方法。这将是多余的。因此,您只需将usermeta_id
直接设置为$user->id
,而无需任何usermeta()->associate()
诡计。
我提到手动设置这样的字段会导致错误。因此,让我们现在讨论一下这些错误,而不是掩饰它们。
如果您手动更新关系字段,Laravel将不会意识到这两个模型是相关的,直到它从数据库重新加载模型。考虑以下两个代码块:
$post = new Post();
$post->usermeta_id = $user->id;
dd( $post->usermeta->name );
$post = new Post();
$post->usermeta()->associate($user);
dd( $post->usermeta->name );
第一个代码块将失败,抛出错误&#34;无法读取null对象的属性&#34; - 因为就Laravel所知,$post->usermeta
是NULL
。您设置$post->usermeta_id
,但未设置$post->usermeta
。
第二个代码块将按预期工作,因为通过运行associate
函数,它会同时设置usermeta_id
和usermeta
。
usermeta_id
字段时自动启动关系。
attach()
方法Laravel使用不同的方法来保存不同类型的关系 - 因为不同的关系意味着不同的底层数据库字段。
associate
:这会在当前模型表中设置*_id
字段。例如:$post->user()->associate($user)
会在user_id
表posts
save
:这会在其他模型表中设置*_id
字段。例如:$post->comments()->save($comment)
会在post_id
表comments
attach
:这会在many to many relationships的链接表上设置*_id
个字段。例如,如果您有标记系统,那么$post->tags()->attach($tag)
会在post_id
表格上设置tag_id
和post_tags
记住你需要的这三个功能中的哪一个可能有点棘手。一般来说,从关系到函数的直接映射是: