MJoin + Left Join

MJoin + Left Join

mgeyermgeyer Posts: 20Questions: 0Answers: 0
edited July 24 in Free community support

Hello,

is there an option to use mjoin and left join in the same server side script?
or multiple mjoins?

haven't found the syntax for this.

thank you :smile:
mg

if I use
... ->join( Mjoin::inst( 'Aufgaben_Kundenprojekte' ) ->link( 'Projekte_Kundenprojekte.ID', 'Aufgaben_Kundenprojekte.Projekt_ID' ) ->fields( Field::inst( 'ID' ) ) ) ->link('Kunden.ID', 'Projekte_Kundenprojekte.ID') ->fields( Field::inst('ID'), Field::inst('Abkuerzung') ) ...

DataTables warning: table id=projekte_kundenprojekte - Invalid JSON response. For more information about this error, please see http://datatables.net/tn/1

Tabels look like:

Projekte_Kundenprojekte
ID PMSchluessel Beschreibung Statusmeldung Zieldatum Verantwortlich Modus Kunde_ID

Kunden
ID Firmenname Notizen Ansprechperson EMail Telefon Abkuerzung

Replies

  • rf1234rf1234 Posts: 895Questions: 44Answers: 127

    there is no special syntax for this; you just use multiple left and Mjoins in one query. That's all.

    Like this for example:

    ->leftJoin( 'contract_has_fixed', 'contract_has_fixed.fixed_id', '=', 'fixed.id')
    ->leftJoin( 'proposal_has_fixed', 'proposal_has_fixed.fixed_id', '=', 'fixed.id')
    //we can optionally define a predecessor for a renewal (Umschuldung):
    ->join(
    Mjoin::inst( 'predecessor' )
        ->link( 'fixed.id', 'fixed_has_predecessor.fixed_id' )
        ->link( 'predecessor.prefixed_id', 'fixed_has_predecessor.prefixed_predecessor_id' )
        ->order( 'serial, element, type asc' )
        ->fields(
            Field::inst( 'prefixed_id' )->set( false )
                ->options( Options::inst()
                    ->table( 'predecessor' )
                    ->value( 'prefixed_id' )
                    ->label( array('serial', 'element', 'end_date', 'type', 'derivative', 'number') )
                //render serial, instrument, type, number
                    ->render( function ( $row ) {               
                        return '# '.$row['serial']
                                .' / '.renderElement($row['element'])
                                .' / ' . getEnd() . getFormatterDate($row["end_date"])
                                .' / '.renderTypeDerivative($row['type'], $row['derivative'])
                                .' ('.$row['number'].')';
                    } )
                    ->order( 'serial, element, type asc' )
                    //where clause MUST be a closure function in Options!!!
                    ->where( function($q) {
                        $q ->where( function($r) {
                            if ( isset($_SESSION['govdept_id'] ) ) {
                                $r ->where('govdept_id', $_SESSION['govdept_id'] );
                            } else {
                                $r ->where('govdept_id', 0 ); //if we have no gov entity we don't want any contracts to be returned!!
                            }
                        });
                    } )
                ),
            Field::inst( 'element' )->set( false ),
            Field::inst( 'end_date' )->set( false )
                ->getFormatter( function ( $val, $data, $opts ) {
                    return getFormatterDate($val);                     
                } ),
            Field::inst( 'serial' )->set( false ),
            Field::inst( 'type' )->set( false ),
            Field::inst( 'derivative' )->set( false ),
            Field::inst( 'number' )->set( false ),
            Field::inst( 'element_id' )->set( false ),
            Field::inst( 'contract_id' )->set( false )      
        )
    )
    ->where( function ( $q ) {
        $q ->where( 'contract_has_fixed.contract_id', $_SESSION['fixed_contract_id'] )
           ->or_where( 'proposal_has_fixed.proposal_id', $_SESSION['fixed_proposal_id'] );
    } )
    

    ... or this:

    ->join(
        Mjoin::inst( 'creditor' )
            ->link( 'user.id', 'creditor_has_user.user_id' )
            ->link( 'creditor.id', 'creditor_has_user.creditor_id' )
            ->order( 'creditor.name asc' )
            ->fields(
                Field::inst( 'creditor.name AS deptName' )->set( false ),
                Field::inst( 'creditor_has_user.role AS userRole' )->set( false )
            )
        )
    ->join(
        Mjoin::inst( 'lgf' )
            ->link( 'user.id', 'lgf.user_id' )
            ->fields(
                Field::inst( 'lgf.role AS userRole' )->set( false )
            )
        )
    
  • mgeyermgeyer Posts: 20Questions: 0Answers: 0
    edited July 24

    @rf1234 thank you!

    I forgot the ->join before :smile:

    1. How to post code with row numbers?
    2. How can I load existing values from the table "Kunden" into the Modal "Create"?
      (I want to show the data in a Select item)
  • rf1234rf1234 Posts: 895Questions: 44Answers: 127

    Don't understand question 1.

    Question 2.: with an options instance. You see one in my reply above in the first Mjoin. Here is more on it: https://editor.datatables.net/manual/php/joins
    Scroll down to "Options".

  • rf1234rf1234 Posts: 895Questions: 44Answers: 127

    This is the javascript for the options instance in the example above using a select field. https://editor.datatables.net/reference/field/select

    }, {
        label: lang === 'de' ? 
                'Wählen Sie ein oder mehrere Vorläufer-Geschäfte:' : 
                'Select one or more predecessor deals:',
        name:  "predecessor[].prefixed_id", //render serial, instrument, type, number
        type: "select",
        multiple: true,
        placeholderDisabled: false,
        placeholder: lang === 'de' ? 
                'Kein Vorläufer vorhanden bzw. ausgewählt' : 'No predecessor exists or is selected'
    }, {
    
    
  • mgeyermgeyer Posts: 20Questions: 0Answers: 0

    Question 1 is about how do you post your code snippets in this forum? because I do not find the layout

    Question 2 is I have linked both tables with a mjoin, but I can't access the field, the select box isn't filled.

  • rf1234rf1234 Posts: 895Questions: 44Answers: 127

    Question 1:

    You can copy & paste them if you don't find the back ticks on your key board.

    Question 2:
    Well, then there's something wrong with your code ... I guess. In my example above the options instance returns an array of rendered data. The field is called "prefixed_id" as in ->value on the server side.
    On the client side it must be accessed as an array as in "predecessor[].prefixed_id". "Predecessor" being the table as in ->table on the server side.

  • rf1234rf1234 Posts: 895Questions: 44Answers: 127

    Another example for the options instance to make it a little easier hopefully. The first client side field is an options instance for a field that is NOT contained in an Mjoin. The second one is an Mjoin options instance. You see the difference looking at "name:".

    var reportEditor = new $.fn.dataTable.Editor({
        ajax: {
            url: 'actions.php?action=tblReport'
        },
        table: "#tblReport",
        fields: [
                 {
                label: lang === 'de' ? 'Berichtstyp:' : 'Report Type:',
                name:  "report.report_type_id", //render report_type.label
                type: "select",
                placeholder: lang === 'de' ? 'Bitte wählen Sie einen Berichtstyp' : 'Please select one report type',
            },  {
                label: lang === 'de' ? 'Abteilungsauswahl:' : 'Department selection:',
                name: "govdept[].id", //render gov_name, govdept_name, (regional_12)
                type: "selectize",
                opts: {
                    create: false,
                    maxItems: null,
                    openOnFocus: true,
                    allowEmptyOption: false,
                    placeholder: lang === 'de' ? 'Bitte wählen Sie eine oder mehrere Abteilung(en)' : 'Please select one or more Department(s)',
                }
            },
    

    And the respective server side code:

    Editor::inst( $db, 'report' )
    ->field(
        Field::inst( 'report.id' )->set( false ),
        Field::inst( 'report.report_type_id' )->validator( 'Validate::notEmpty', array('message' => $msg[0]) )
            ->options( Options::inst()
                ->table('report_type')
                ->value('id')
                ->label( array('label', 'number') )  //we need to get number into the field list otherwise SQL error with the server MySQL-Version. 
                ->render( function ( $row ) { 
                    return sprintf("%02d", $row['number']) . ": " . $row['label']; 
                } )
                ->order('number asc')
                //where clause MUST be a closure function in Options!!!
                ->where( function($q) {                    
                    $q ->where( 'user_id', $_SESSION['id'] );
                } )
            ),
    .....
    
    ->leftJoin( 'report_type', 'report.report_type_id', '=', 'report_type.id')
    ->join(
    Mjoin::inst( 'govdept' )
        ->link( 'report.id', 'report_has_govdept.report_id' )
        ->link( 'govdept.id', 'report_has_govdept.govdept_id' )
        ->order( 'govdept.name asc' )
        ->fields(
            Field::inst( 'id' )->set( false )                
                ->options( Options::inst()
                    ->table('govdept')
                    ->value('id')                    
                    ->label( 'name' )
                    ->render( function ( $row ) {   
                        return getFormatterGovdeptOptions($row['id']);
                    } )
                    ->order( 'name asc' )
                    //where clause MUST be a closure function in Options!!!
                    ->where( function($q) {
                        //the user does not need more than reading rights for the
                        //respective department
                        $q ->where( function($r) {
                            $r  ->where( 'id',  
                                '( SELECT DISTINCT govdept.id    
                                    FROM user, govdept_has_user, govdept  
                                    WHERE user.id = :id                             AND  
                                          user.id = govdept_has_user.user_id        AND  
                                          govdept_has_user.govdept_id = govdept.id 
                                    )', 'IN', false);
                            $r  ->bind( ':id', $_SESSION['id'] );
                        });
                    } )
                ),
            Field::inst( 'name' )->set( false ) 
        )
    )
    
    
    
  • mgeyermgeyer Posts: 20Questions: 0Answers: 0

    @rf1234

    1. Thank you very much!!!
    2. Thank you - I am going to look for the reason why I can't access in my JSON object "Abkuerzung"

    JSON

    {
        "JSON": {
            "data": [{
                "DT_RowId": "row_16",
                "ID": "16",
                "PMSchluessel": "test1",
                "Beschreibung": "test1",
                "Statusmeldung": "test1",
                "Zieldatum": "2019-07-24",
                "Verantwortlich": "test1",
                "Modus": "test1",
                "Kunde_ID": "1",
                "Aufgaben_Kundenprojekte": [{
                    "ID": "34"
                }],
                "Kunden": [{
                    "Abkuerzung": "MG"
                }]
            },
    

    Server

    Editor::inst( $db, 'Projekte_Kundenprojekte' )
        ->fields(
            Field::inst( 'ID' )->set( false ),
            Field::inst( 'PMSchluessel' )->validator( 'Validate::notEmpty' ),
            Field::inst( 'Beschreibung' ),
            Field::inst( 'Statusmeldung' ),
            Field::inst( 'Zieldatum' ),
            Field::inst( 'Verantwortlich' ),
            Field::inst( 'Modus' ),
            Field::inst( 'Kunde_ID' )
        )
        ->join(
            Mjoin::inst( 'Aufgaben_Kundenprojekte' )
                ->link( 'Projekte_Kundenprojekte.ID', 'Aufgaben_Kundenprojekte.Projekt_ID' )
                ->fields(
                    Field::inst( 'ID' )
                )
        )
        ->join(
            Mjoin::inst('Kunden')
                ->link('Projekte_Kundenprojekte.Kunde_ID', 'Kunden.ID')
                ->fields(
                    Field::inst('Abkuerzung')
                )
        )
        ->process( $_POST )
        ->json();
    

    Client

    $(document).ready(function () {
        var siteEditor = new $.fn.dataTable.Editor({
            ajax: "php/projekte_kundenprojekte.php",
            table: "#projekte_kundenprojekte",
            fields: [
                {
                    label: "Projektschlüssel:",
                    name: "PMSchluessel"
                },
                {
                    label: "Kunde:",
                    name: "Kunden[].Abkuerzung",
                    type: "select"
                },
    

    Here would be a "demo", maybe it is because I have a child table - https://drakul.eu/testing/datatable/

  • rf1234rf1234 Posts: 895Questions: 44Answers: 127
    edited July 24

    There might be a data modelling issue?!

    The relationship between your tables

    Projekte_Kundenprojekte
    ID PMSchluessel Beschreibung Statusmeldung Zieldatum Verantwortlich Modus Kunde_ID

    Kunden
    ID Firmenname Notizen Ansprechperson EMail Telefon Abkuerzung

    is 1:N with "Kunden" being the parent table. For that you don't use an MJoin! A simple left join will do.

    In addition there is no options instance in your server side code. This way it won't work.

    If you take a look at this you'll see an excerpt from my data model that is exactly about my code example.

    The relationship between report_type and report is the same as the one between Kunden and Projekte_Kundenprojekte. The foreign key in report is "report_type_id". And that is precisely the field that is being filled with my options instance above.

    The mJoin is only needed if you have an N:M relationship requiring a link table. The link table in my example to resolve the N:M relationship between "report" and "govdept" is called "report_has_govdept". This table is being edited (create and delete of link table rows) by the MJoin. The options instance in the MJoin allows you to chose a department (= govdept) and upon saving your selection it creates link table entries.

    The link (i.e. the link table fields) is specified here:

    ->join(
    Mjoin::inst( 'govdept' )
        ->link( 'report.id', 'report_has_govdept.report_id' )
        ->link( 'govdept.id', 'report_has_govdept.govdept_id' )
    
  • mgeyermgeyer Posts: 20Questions: 0Answers: 0
    edited July 25

    @rf1234 thank you - now this is clear to me!

    my problem is if I try a left join select is also without data and I can't access my child table anymore, do you have an idea where I am hanging?

    parten table php

    Editor::inst( $db, 'Projekte_Kundenprojekte' )
        ->fields(
            Field::inst( 'Projekte_Kundenprojekte.ID' )->set( false ),
            Field::inst( 'Projekte_Kundenprojekte.PMSchluessel' )->validator( 'Validate::notEmpty' ),
            Field::inst( 'Projekte_Kundenprojekte.Beschreibung' ),
            Field::inst( 'Projekte_Kundenprojekte.Statusmeldung' ),
            Field::inst( 'Projekte_Kundenprojekte.Zieldatum' ),
            Field::inst( 'Projekte_Kundenprojekte.Verantwortlich' ),
            Field::inst( 'Projekte_Kundenprojekte.Modus' ),
            Field::inst( 'Projekte_Kundenprojekte.Kunde_ID' )
        )
        ->leftJoin( 'Kunden', 'Kunden.ID', '=', 'Projekte_Kundenprojekte.Kunde_ID')
        ->join(
            Mjoin::inst( 'Aufgaben_Kundenprojekte' )
                ->link( 'Projekte_Kundenprojekte.ID', 'Aufgaben_Kundenprojekte.Projekt_ID' )
                ->fields(
                    Field::inst( 'ID' )
                )
        )
    

    child table php - it is always the if entered, without the if the is an error
    (Notice: Undefined index: Aufgaben_Kundenprojekte.PMSchluessel in /var/www/clients/client1/web3/web/self_build/php/aufgaben_kundenprojekte.php on line 31)

    if ( ! isset($_POST['Aufgaben_Kundenprojekte.PMSchluessel']) ) {
        echo json_encode( [ "data" => [] ] );
    }
    else {
        Editor::inst( $db, 'Aufgaben_Kundenprojekte' )
            ->field(
                Field::inst( 'Aufgaben_Kundenprojekte.ID' ),
                Field::inst( 'Aufgaben_Kundenprojekte.Aufgabe' ),
                Field::inst( 'Aufgaben_Kundenprojekte.Zieldatum' ),
                Field::inst( 'Aufgaben_Kundenprojekte.Statusmeldung' ),
                Field::inst( 'Aufgaben_Kundenprojekte.Verantwortlich' ),
                Field::inst( 'Aufgaben_Kundenprojekte.Erfuellungsgrad' ),
                Field::inst( 'Aufgaben_Kundenprojekte.Modus' ),
                Field::inst( 'Aufgaben_Kundenprojekte.Projekt_ID' ),
                Field::inst( 'Aufgaben_Kundenprojekte.PMSchluessel' )
                    ->options( 'Projekte_Kundenprojekte', 'Projekte_Kundenprojekte.PMSchluessel', 'Aufgaben_Kundenprojekte.PMSchluessel' )
                    ->validator( 'Validate::dbValues' ),
                Field::inst( 'Projekte_Kundenprojekte.PMSchluessel' )
            )
            ->leftJoin( 'Projekte_Kundenprojekte', 'Projekte_Kundenprojekte.PMSchluessel', '=', 'Aufgaben_Kundenprojekte.PMSchluessel' )
            ->where( 'Aufgaben_Kundenprojekte.PMSchluessel', $_POST['Aufgaben_Kundenprojekte.PMSchluessel'] )
    

    javascript

    //==============
    //Parent Table
    //==============
    $(document).ready(function () {
        var siteEditor = new $.fn.dataTable.Editor({
            ajax: "php/projekte_kundenprojekte.php",
            table: "#projekte_kundenprojekte",
            fields: [
                {
                    label: "Projektschlüssel:",
                    name: "Projekte_Kundenprojekte.PMSchluessel"
                },
                {
                    label: "Kunde:",
                    name: "Kunden.Abkuerzung",
                    type: "select"
                },
                {
                    label: "Beschreibung:",
                    name: "Projekte_Kundenprojekte.Beschreibung"
                },
                {
                    label: "Statusmeldung:",
                    name: "Projekte_Kundenprojekte.Statusmeldung"
                },
                {
                    label: "Zieldatum:",
                    name: "Projekte_Kundenprojekte.Zieldatum",
                    type: 'datetime',
                    def: function () { return new Date(); },
                    format: 'YYYY-MM-DD'
                },
                {
                    label: "Verantwortlich",
                    name: "Projekte_Kundenprojekte.Verantwortlich"
                },
                {
                    label: "Modus",
                    name: "Projekte_Kundenprojekte.Modus"
                }
            ]
        });
    
        var siteTable = $("#projekte_kundenprojekte").DataTable({
            dom: "Bfrtip",
            ajax: "php/projekte_kundenprojekte.php",
            language: { url: "js/trans/dataTables.german.lang" },
            order: [1, "asc"],
            columns: [
                {
                    className: "details-control",
                    orderable: false,
                    data: null,
                    defaultContent: "",
                    width: "7%"
                },
                { data: "Projekte_Kundenprojekte.PMSchluessel" },
                { data: "Projekte_Kundenprojekte.Beschreibung" },
                { data: "Projekte_Kundenprojekte.Statusmeldung" },
                { data: "Projekte_Kundenprojekte.Zieldatum", },
                { data: "Projekte_Kundenprojekte.Verantwortlich" },
                { data: "Projekte_Kundenprojekte.Modus" },
                {
                    data: "Aufgaben_Kundenprojekte",
                    render: function (data) {
                        return data.length;
                    }
                }
            ],
            select: {
                style: "os",
                selector: "td:not(:first-child)"
            },
            buttons: [
                { extend: "create", editor: siteEditor },
                { extend: "edit", editor: siteEditor },
                { extend: "remove", editor: siteEditor }
            ]
        });
    
        // Add event listener for opening and closing details
        $("#projekte_kundenprojekte tbody").on("click", "td.details-control", function () {
            var tr = $(this).closest("tr");
            var row = siteTable.row(tr);
    
            if (row.child.isShown()) {
                // This row is already open - close it
                destroyChild(row);
                tr.removeClass("shown");
            } else {
                // Open this row
                createChild(row);
                tr.addClass("shown");
            }
        });
    
        // When updating a site label, we want to update the child table's site labels as well
        siteEditor.on("submitSuccess", function () {
            siteTable.rows().every(function () {
                if (this.child.isShown()) {
                    updateChild(this);
                }
            });
        });
    });
    //==============
    //Child Table
    //==============
    function createChild(row) {
        var rowData = row.data();
    
        // This is the table we'll convert into a DataTable
        var table = $('<table class="display" width="100%"/>');
    
        // Display it the child row
        row.child(table).show();
    
        // Editor definition for the child table
        var usersEditor = new $.fn.dataTable.Editor({
            ajax: {
                url: "php/aufgaben_kundenprojekte.php",
                data: function (d) {
                    d.PMSchluessel = rowData.PMSchluessel;
                }
            },
            table: table,
            fields: [
                {
                    label: "Aufgabe:",
                    name: "Aufgaben_Kundenprojekte.Aufgabe"
                },
                {
                    label: "Verantwortlich:",
                    name: "Aufgaben_Kundenprojekte.Verantwortlich"
                },
                {
                    label: "Zieldatum:",
                    name: "Aufgaben_Kundenprojekte.Zieldatum",
                    type: 'datetime',
                    def: function () { return new Date(); },
                    format: 'YYYY-MM-DD',
                },
                {
                    label: "Modus:",
                    name: "Aufgaben_Kundenprojekte.Modus"
                },
                {
                    label: "Erfüllungsgrad:",
                    name: "Aufgaben_Kundenprojekte.Erfuellungsgrad"
                },
                {
                    label: "Statusmeldung:",
                    name: "Aufgaben_Kundenprojekte.Statusmeldung"
                },
                {
                    label: "Projekt_ID:",
                    name: "Aufgaben_Kundenprojekte.Projekt_ID",
                    def: rowData.ID,
                    type: "hidden"
                },
                {
                    label: "Projektschlüssel:",
                    name: "Aufgaben_Kundenprojekte.PMSchluessel",
                    type: "hidden", //select
                    placeholder: "PMSchlüssel auswählen",
                    def: rowData.PMSchluessel
                }
            ]
        });
    
        // Child row DataTable configuration, always passes the parent row's id to server
        var usersTable = table.DataTable({
            dom: "Bfrtip",
            language: { url: "js/trans/dataTables.german.lang" },
            pageLength: 12,
            ajax: {
                url: "php/aufgaben_kundenprojekte.php",
                type: "post",
                data: function (d) {
                    d.PMSchluessel = rowData.PMSchluessel;
                }
            },
            columns: [
                { title: "Aufgabe", data: "Aufgaben_Kundenprojekte.Aufgabe" },
                { title: "Verantwortlich", data: "Aufgaben_Kundenprojekte.Verantwortlich" },
                { title: "Zieldatum", data: "Aufgaben_Kundenprojekte.Zieldatum" },
                { title: "Modus", data: "Aufgaben_Kundenprojekte.Modus" },
                { title: "Erfüllungsgrad", data: "Aufgaben_Kundenprojekte.Erfuellungsgrad" },
                { title: "Statusmeldung", data: "Aufgaben_Kundenprojekte.Statusmeldung" },
                { title: "Projektschlüssel", data: "Projekte_Kundenprojekte.PMSchluessel" }
            ],
            select: true,
            buttons: [
                { extend: "create", editor: usersEditor },
                { extend: "edit", editor: usersEditor },
                { extend: "remove", editor: usersEditor }
            ]
        });
    
    
  • rf1234rf1234 Posts: 895Questions: 44Answers: 127

    In this code the left join is redundant because you are not selecting any fields from the left joined table. The MJoin seems wrong too because you seem to have a foreign key from "Projekte_Kundenprojekte" in your child table "Aufgaben_Kundenprojekte". In that case you don't need an MJoin. And here as well: You are not selecting anything from the MJoined table.

    My impression is that you need to gain clarity on your data model first. And you have this field "PMSchluessel" that isn't an ID field but seems to play a similar role as a foreign key or even is a foreign key?!

    Editor::inst( $db, 'Projekte_Kundenprojekte' )
        ->fields(
            Field::inst( 'Projekte_Kundenprojekte.ID' )->set( false ),
            Field::inst( 'Projekte_Kundenprojekte.PMSchluessel' )->validator( 'Validate::notEmpty' ),
            Field::inst( 'Projekte_Kundenprojekte.Beschreibung' ),
            Field::inst( 'Projekte_Kundenprojekte.Statusmeldung' ),
            Field::inst( 'Projekte_Kundenprojekte.Zieldatum' ),
            Field::inst( 'Projekte_Kundenprojekte.Verantwortlich' ),
            Field::inst( 'Projekte_Kundenprojekte.Modus' ),
            Field::inst( 'Projekte_Kundenprojekte.Kunde_ID' )
        )
        ->leftJoin( 'Kunden', 'Kunden.ID', '=', 'Projekte_Kundenprojekte.Kunde_ID')
        ->join(
            Mjoin::inst( 'Aufgaben_Kundenprojekte' )
                ->link( 'Projekte_Kundenprojekte.ID', 'Aufgaben_Kundenprojekte.Projekt_ID' )
                ->fields(
                    Field::inst( 'ID' )
                )
        )
    

    What is it actually that you want to do?

    Do you want to assign tasks ("Aufgaben") to a project ("Kundenprojekte")? If you tell me what you want I might be able to help. Please also clarify what this PMSchluessel is all about. Since you have a foreign key from "Kundenprojekte" already in "Aufgaben" you don't need "PMSchluessel" to define the relationship. It looks pretty much redundant.

  • mgeyermgeyer Posts: 20Questions: 0Answers: 0
    edited July 25

    @rf1234 thank you for your patience!

    For the structure see the pdf document attached.

    1) Now I got the 1:n for Kunde working :smile:
    2) The mjoin was copied by this tutorial https://datatables.net/blog/2019-01-11 and a little bit adapted so it counts the amount of "aufgaben" for the different "project_id"s.
    3) Yes you are right I want to assigns tasks ("Aufgaben") to a project ("Kundenprojekte") - the "PMSchluessel" is an automatically generated Key with a increasing number, the name of the customer ("Kunden.Abkuerzung") and a manuel added Text ("Projekte_Kundenprojekte.Bezeichnung")
    4) It would be also necessary to save status updates in a table to look back how the project has developed and load the newest status from this table("Statusberichte_Kundenprojekte") to the task("Aufgabe") or project ("Projekte_Kundenprojekte")

    Hope it is now clear to you what I want to build.

    5) What do you think, how would it be best to assign tasks to projects and also count the open (where clause) tasks of the project?

    !(https://datatables.net/forums/uploads/editor/a9/lq7c6bdyzuud.pdf "")

  • rf1234rf1234 Posts: 895Questions: 44Answers: 127

    Hi there, will switch to German now. For everyone else reading this: Use deepl.com please to translate this into English if required.

    Guten Morgen!
    Zu 1) freut mich!
    zu 2) ok verstanden! Hier geht es darum, einfach nur mehrere Werte pro Zeile der Parent Tabelle anzuzueigen; dafür ist ein MJoin genau das richtige. Wenn es darum geht, Werte zuzuweisen, die logisch in einer 1:N Beziehung stehen, braucht man keinen MJoin. Den bräuchte man nur, wenn man eine Link Tabelle hätte zur Auflösung einer N:M Beziehung, die es in Deinem Modell nicht gibt.
    zu 3) ich versuche es mal

    Mit dieser Editor Instanz kannst Du eine Aufgabe einem Projekt zuweisen. Ich habe das Ganze bewusst einfach gehalten.

    Editor::inst( $db, 'Aufgaben_Kundenprojekte' )
    ->fields(
        Field::inst( 'Aufgaben_Kundenprojekte.ID' )->set( false ),
        Field::inst( 'Aufgaben_Kundenprojekte.Projekt_ID' )->validator( 'Validate::notEmpty' )
            ->options( Options::inst()
                ->table('Projekte_Kundenprojekte')
                ->value('ID')
                ->label( array('Beschreibung', 'Zieldatum') ) 
                ->render( function ( $row ) { 
                    return $row['Beschreibung'] . "; Fertig bis: " . $row['Zieldatum']; 
                } )
                ->order('Beschreibung asc')
                //where clause MUST be a closure function in Options!!!
                ->where( function($q) {                    
                    $q ->where( HIER WHERE CLAUSE EINSETZEN );
                } )
            ),      
        Field::inst( 'Projekte_Kundenprojekte.Beschreibung' ),
        Field::inst( 'Projekte_Kundenprojekte.Zieldatum' ),
    )
    ->leftJoin( 'Projekte_Kundenprojekte', 'Aufgaben_Kundenprojekte.Projekt_ID', '=', 'Projekte_Kundenprojekte.ID')
    

    In dieser Editor Instanz wird nichts zugewiesen. Hier werden lediglich die Projekte mit Ihren Aufgaben dargestellt. Ein Projekt hat N Aufgaben. Die Aufgaben werden als Wiederholungsgruppe in einem Feld des Data Table dargestellt. Hierfür kann man den MJoin gut verwenden.

    Editor::inst( $db, 'Projekte_Kundenprojekte' )
        ->fields(
            Field::inst( 'Projekte_Kundenprojekte.ID' )->set( false ),
            Field::inst( 'Projekte_Kundenprojekte.PMSchluessel' )->validator( 'Validate::notEmpty' ),
            Field::inst( 'Kunden.Firmenname' )->set( false ), 
            Field::inst( 'Kunden.Ansprechperson' )->set( false ),  
            Field::inst( 'Projekte_Kundenprojekte.Beschreibung' ),
            Field::inst( 'Projekte_Kundenprojekte.Statusmeldung' ),
            Field::inst( 'Projekte_Kundenprojekte.Zieldatum' ),
            Field::inst( 'Projekte_Kundenprojekte.Verantwortlich' ),
            Field::inst( 'Projekte_Kundenprojekte.Modus' )
        )
        ->leftJoin( 'Kunden', 'Kunden.ID', '=', 'Projekte_Kundenprojekte.Kunde_ID')
        ->join(
            Mjoin::inst( 'Aufgaben_Kundenprojekte' )
                ->link( 'Projekte_Kundenprojekte.ID', 'Aufgaben_Kundenprojekte.Projekt_ID' )
                ->fields(
                    Field::inst( 'Aufgaben_Kundenprojekte.Aufgabe   AS Aufgabe' )->set( false ),
                    Field::inst( 'Aufgaben_Kundenprojekte.Zieldatum AS Zieldatum' )->set( false )
                )
            )
    

    4) Du könntest beispielsweise ein Log schreiben oder Ähnliches hierfür stehen die PHP Events zur Verfügung.

    Hier ein Beispiel für das Log; du kannst natürlich auch jegliche andere Art von Update machen.

    ->on( 'postCreate', function ( $editor, $id, $values, $row ) {            
        logChange( $editor->db(), 'create', $id, $row, 'contract' );
    } )
    ->on( 'postEdit', function ( $editor, $id, $values, $row ) {
        logChange( $editor->db(), 'edit', $id, $row, 'contract' );
    } )
    ->on( 'postRemove', function ( $editor, $id, $values ) {
        logChange( $editor->db(), 'delete', $id, $values, 'contract' );
    } )
    ->process($_POST)            
    ->json();
    
    function logChange ( $db, $action, $id, $values, $tableChanged ) {
        //insert what happened before into the log table   
        $db->insert( 'log', array(
            'user_id'       => $_SESSION['id'],
            'table'         => $tableChanged,
            'action'        => $action,
            'values'        => json_encode( $values ),
            'changed_id'    => $id
        ) );
    }
    

    5) Den Aufgabenstatus könntest Du ebenfalls im MJoin mit selektieren und anschließend auch die offenen Positionen auf der client Seite mit reduce zählen und irgendwo anzeigen
    https://datatables.net/reference/api/reduce()

    Dazu findest Du auch irgendwo im Forum ein Beispiel von @allan

    Viele Grüße
    Roland

  • mgeyermgeyer Posts: 20Questions: 0Answers: 0

    @rf1234

    Danke Roland!!!

    Ich werd mich mal durch die Codezeilen bewegen, jetzt habe ich alle Informationen geballt vor mir - da sollte ich schon was drauß zaubern können!!!!!!!

    Nochmals DANKE!!!!

Sign In or Register to comment.