restFUL API依赖于商店

时间:2013-12-05 20:16:36

标签: php api laravel laravel-4

我的应用程序是图书管理员,我可以在其中创建图书和页面。

我的bookController在POST上有一个“商店”,它存储标题和描述。

public function store()
{


    $rules = array(
        'title'         => 'required|min:3',
        'description'   => 'required|min:30'
    );


    $validator = Validator::make(Input::all(), $rules);

    if ($validator->fails()) {
        return Response::json(
            array(
                'metadata' => array(
                    'error'     => true,
                    'message'   => 'The book creation has failed'
                )
            ),
            400
        );
    }

    else {

        $slug           = Str::slug(Request::get('title'));
        $existSlug      = Book::where('slug',$slug)->get();

        if(count($existSlug) > 0) {
            return Response::json(
                array(
                    'metadata' => array(
                        'error'     => true,
                        'message'   => 'This title is already taken'
                    )
                ),
                400
            );
        }
        else {
            $book               = new Book;
            $book->title        = Request::get('title');
            $book->slug         = $slug;
            $book->description  = Request::get('description');
            $book->user_id      = Auth::user()->id;
            $book->status       = false;
            $book->save();

            $stored = $book->toArray();
            $metadata = array(
                'metadata' => array(
                    'error' => false,
                )
            );
            return Response::json(
                array_merge($stored,$metadata),
                201
            );
        }

    }

}

我还有一个在POST上有一个“store”的pageController,它存储一个页面内容:

public function store()
{
    $rules = array(
        'content'       => 'required|between:300,350',
        'book_id'       => 'required|exists:books,id'
    );

    $validator = Validator::make(Input::all(), $rules);

    if($validator->fails()) {

        return Response::json(
            array(
                'metadata'  => array(
                    'error'     => true,
                    'message'   => 'The page must be between 300 and 350 characters'
                )

            ),
            400
        );
    }
    else {

        $book               = Book::find(Input::get('book_id'));
        $content            = Input::get('content');
        $parent             = Page::where('book_id',$book->id)->where('status',1)->orderBy('id', 'desc')->first();

        if($parent){
            $parent_id      = $parent->id;
            $parent_number  = $parent->number;
            $status         = 0; //Define the status of the created page
        }
        else{
            //If it's the first page of the book
            $parent_id      = 0;
            $parent_number  = 0;
            $status         = 1; //if there's no parent page, the new page is the first - auto validated - page of the book.
            if($book->user_id != Auth::user()->id) {
                return Response::json(
                    array(
                        'metadata'  => array(
                            'error'     => true,
                            'message'   => 'You have to be the author of a book to write the first page.'
                        )

                    ),
                    403
                );
            }
        }

        $page               = new Page;
        $page->content      = $content;
        $page->book_id      = $book->id;
        $page->parent_id    = $parent_id;
        $page->number       = $parent_number + 1;
        $page->user_id      = Auth::user()->id;
        $page->status       = $status;
        $page->save();

        $stored     = $page->toArray();
        $metadata   = array(
            'metadata'  => array(
                'error' => false
            )
        );

        return Response::json(
                array_merge($stored,$metadata),
                201
            );
    }
}

每当有人创作一本书时,他必须至少写出第一页。这会产生一个带有输入标题,描述和内容的表单。

我使用我的输入标题和说明向[...] /书籍发送POST

如果成功=>我得到了书籍ID,并将输入内容发送到[...] /页面。

以下是我的问题:

  • 有人可以在[...] /书籍上发帖,并会存储一本没有页面的新书
  • 我想以更“restFUL方式”解决这个问题,这意味着没有“hackish解决方案”,比如将内容发送到/ books并在bookController中进行页面验证
  • 另外,即使我选择了hackish方式,我的API仍然不安全:我可以停止发送第二个请求(到/ pages)。

我如何处理这种共同依赖?

1 个答案:

答案 0 :(得分:2)

第一

您的控制器做得太多了,他们不应该对您的业务逻辑有任何了解,这是特定类(模型,存储库,域逻辑类)应该处理的事情。

创建一些类来处理这个逻辑,将Input发送给它们并实现它。无论你需要什么,打电话给他们,使用Laravel非常棒,因为你可以用你的代码做任何你想做的事。

第二

如果要强制执行不同的数据约束,您可以:

根据相同的请求处理

取决于您的界面,如果您在一个页面上拥有所需的一切,您只需发送数据并在可以访问所有模型的存储库中处理它。

可以用于两者的示例可以是:

使用依赖注入的书籍存储库,这意味着Book和Page将由Laravel自动实例化:

class BookRepository {

    __construct(Book $book, Page $page)
    {
        $this->book = $book;
        $this->page = $page;
    }

    public function store($input)
    {
        if ( ! $this->book->validate($input) || !$this->page->validate($input))
        {
            return 'error';
        }

        $book->create(input);
        $page->create($input);
    }

}

验证的基本模型:

class Book extends BaseModel {

    public function validate($input)
    {
        /// validate here and return
    }   

}

每种模型和规则:

class Book extends BaseModel {

    $book_rules = array(
        'title'         => 'required|min:3',
        'description'   => 'required|min:30'
    );


}

class Page extends BaseModel {

    $page_rules = array(
        'content'       => 'required|between:300,350',
        'book_id'       => 'required|exists:books,id'
    );


}

然后您创建包含书籍信息和页面信息的视图,并将POST到BookController @ store:

class BookController extends Controller {

    public function __controller(BookRepository $book_repository)
    {
        $this->book_repository = $book_repository;
    }

    public function store()
    {
        if ( ! $this->book_repository->store($input))
        {
            return Redirect::back()
                        ->withErrors(
                                        $this->book_repository
                                        ->validation
                                        ->messages()
                                        ->all()
                                    );
        }

        return Redirect::to('success');
    }

}

我们再次使用依赖注入。 $ book_repository将自动实例化。因此,您的Controller不需要知道书籍或页面的作用,只需要获取请求并传递到将负责处理所有内容的存储库。

并非全部,但这是一个开始。

处理不同的请求

通常这样。用户发送请求,应用程序检查并存储数据。如果需要,用户发送第二个请求,应用程序检查全部并发回错误。

在后台处理它们

这是一种更聪明的方法。您的应用程序将在一个或多个请求中接收所有数据,存储它们,使用队列工作程序检查它们并向用户发送电子邮件,告诉他有一些数据需要填写。一段时间后,可以删除没有页面的书籍。您不会冒不良数据的风险,并且您的用户一旦知道缺少什么就会知道。