Laravel 5只读视图模型具有多态关系

时间:2017-11-20 18:53:08

标签: mysql laravel laravel-5 polymorphism

有时我们使用MySql Views来组织相关表,以便于搜索和排序。例如,如果您的帖子具有状态和来源。

Post
    subject
    body
    source_id
    status_id

Status
    id
    label
    other_field

Source
    id
    label
    other_field


View
   create view read_only_posts as
   SELECT statuses.label as status, sources.label as source, posts.*
   from posts
   left join statuses on statuses.id = posts.status_id
   left join sources on sources.id = posts.source_id

然后我们有Post模型和一个额外的模型:

// Post.php
class Post extends Model
{
    //
}

// ReadOnlyPost.php
class ReadOnlyPost extends Post
{
    protected $table = 'read_only_posts';
}

这很好,因为现在您可以直接对Status或Source进行排序或过滤,而不是id的字符串。您还可以添加' other_field'。

但是我们有一个需要帮助的问题。如果你在帖子上有多态的多对多关系,我无法让它在只读版本上工作。例如,如果您有多态标签:

// Post.php Model
public function tags()
{
    return $this->morphToMany(Tag::class, 'taggable');
}

问题是当您使用特定标记过滤帖子(使用只读模型)时,您会得到这样的SQL:

  

选择count(*)作为read_only_posts中存在的聚合(tags上的taggables内部加入tagsid = {{1 } {。taggables其中taggable_idread_only_posts = idtaggablestaggable_typetaggables =' read_only_posts& #39;和taggable_type =' test')

正如您所看到的,问题是 labeltaggables =' read_only_posts'

我找不到覆盖模型的变形类型的方法。 (我在laravel 5.4上,MorphClass已经不存在了)。变形图是一个关联数组,因此您无法执行此操作:

taggable_type

我的愚蠢修复是当我将标签附加到帖子时我还将它附加到ready_only_posts,这有点乱。

其他人使用Views只读模型吗?任何人都有更好的方法来覆盖特定模型的多对多多态类型?

1 个答案:

答案 0 :(得分:3)

查看代码,我相信这可能有用。

// SocketThreadConn.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <WinSock.h>
#include <Windows.h>

#pragma comment(lib, "ws2_32.lib")

#define PR_RECORED_TIME 10*1000 // (ms)

BYTE* pByteCamData = NULL;
INT nHeight = 900;
INT nWidth = 1600;
INT nSpect = 3;
INT nSolution = nHeight * nWidth * nSpect;

VOID SendRecoredData(SOCKET socket2operation);

int _tmain(int argc, _TCHAR* argv[])
{
    pByteCamData = new BYTE[nSolution]; // <-- use [], not ()!

    //----------------------
    // Initialize Winsock.
    WSADATA wsaData;
    int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != NO_ERROR) {
        wprintf(L"WSAStartup failed with error: %d\n", iResult);
        delete[] pByteCamData;
        return 1;
    }

    //----------------------
    // Create a SOCKET for listening for
    // incoming connection requests.
    SOCKET ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (ListenSocket == INVALID_SOCKET) {
        wprintf(L"socket failed with error: %d\n", WSAGetLastError());
        WSACleanup();
        delete[] pByteCamData;
        return 1;
    }

    //----------------------
    // The sockaddr_in structure specifies the address family,
    // IP address, and port for the socket that is being bound.
    sockaddr_in service = {};
    service.sin_family = AF_INET;
    service.sin_addr.s_addr = INADDR_ANY;   // inet_addr("127.0.0.1");
    service.sin_port = htons(27015);

    if (bind(ListenSocket, (SOCKADDR *) &service, sizeof(service)) == SOCKET_ERROR) {
        wprintf(L"bind failed with error: %d\n", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        delete[] pByteCamData;
        return 1;
    }

    //----------------------
    // Listen for incoming connection requests.
    // on the created socket
    if (listen(ListenSocket, 1) == SOCKET_ERROR) {
        wprintf(L"listen failed with error: %d\n", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        delete[] pByteCamData;
        return 1;
    }

    //----------------------
    // Accept the connection.
    wprintf(L"Waiting for client to connect...\n");
    SOCKET AcceptSocket = accept(ListenSocket, NULL, NULL);
    if (AcceptSocket == INVALID_SOCKET) {
        wprintf(L"accept failed with error: %d\n", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        delete[] pByteCamData;
        return 1;
    }

    wprintf(L"Client connected.\n");
    SendRecoredData(AcceptSocket); // <-- logic fix!

    // No longer need client socket
    closesocket(AcceptSocket); // <-- CLOSE_WAIT fix!

    // No longer need server socket
    closesocket(ListenSocket);

    WSACleanup();

    delete[] pByteCamData;

    return 0;
}

VOID SendRecoredData(SOCKET socket2operation)
{
    INT nCountDown = 5;
    INT nSentData, nNumToSend;
    BYTE *pData;

    do
    {
        if (nCountDown == 0)
        {
            nCountDown = 5;

            pData = pByteCamData;
            nNumToSend = nSolution;

            while (nNumToSend > 0) <-- send() fix!
            {
                nSentData = send(socket2operation, (char*)pData, nNumToSend, 0);
                if (SOCKET_ERROR == nSentData) {
                    wprintf(L"send failed with error: %d\n", WSAGetLastError());
                    return;
                }
                pData += nSentData;
                nNumToSend -= nSentData;
            }

            wprintf(L"Sent Camera Data OK [%d] Bytes\n", nSolution);
        }

        Sleep(PR_RECORED_TIME);
        --nCountDown;
    }
    while (TRUE);
}

理论上你应该在变形图中列出class ReadOnlyPost extends Posts { public function getMorphClass() { return 'posts'; } } 模型/表格,因为系统会根据命名为它自动生成“帖子”类型。