@@ -126,14 +126,14 @@ abstract class AbstractConnectionResolver {
126126 /**
127127 * The nodes (usually GraphQL models) returned from the query.
128128 *
129- * @var \WPGraphQL\Model\Model[]|mixed[]
129+ * @var \WPGraphQL\Model\Model[]|mixed[]|null
130130 */
131131 protected $ nodes ;
132132
133133 /**
134134 * The edges for the connection.
135135 *
136- * @var array<string,mixed>[]
136+ * @var ? array<string,mixed>[]
137137 */
138138 protected $ edges ;
139139
@@ -558,19 +558,11 @@ public function get_ids() {
558558 * @throws \Exception
559559 */
560560 public function get_nodes () {
561- $ nodes = [];
562-
563- // These are already sliced and ordered, we're just populating node data.
564- $ ids = $ this ->get_ids_for_nodes ();
565-
566- foreach ( $ ids as $ id ) {
567- $ model = $ this ->get_node_by_id ( $ id );
568- if ( true === $ this ->get_is_valid_model ( $ model ) ) {
569- $ nodes [ $ id ] = $ model ;
570- }
561+ if ( ! isset ( $ this ->nodes ) ) {
562+ $ this ->nodes = $ this ->prepare_nodes ();
571563 }
572564
573- return $ nodes ;
565+ return $ this -> nodes ;
574566 }
575567
576568 /**
@@ -579,43 +571,11 @@ public function get_nodes() {
579571 * @return array<string,mixed>[]
580572 */
581573 public function get_edges () {
582- // Bail early if there are no nodes.
583- if ( empty ( $ this ->nodes ) ) {
584- return [];
574+ if ( ! isset ( $ this ->edges ) ) {
575+ $ this ->edges = $ this ->prepare_edges ( $ this ->get_nodes () );
585576 }
586577
587- $ edges = [];
588-
589- // The nodes are already ordered, sliced, and populated. What's left is to populate the edge data for each one.
590- foreach ( $ this ->nodes as $ id => $ node ) {
591- $ edge = [
592- 'cursor ' => $ this ->get_cursor_for_node ( $ id ),
593- 'node ' => $ node ,
594- 'source ' => $ this ->source ,
595- 'connection ' => $ this ,
596- ];
597-
598- /**
599- * Create the edge, pass it through a filter.
600- *
601- * @param array<string,mixed> $edge The edge within the connection
602- * @param \WPGraphQL\Data\Connection\AbstractConnectionResolver $connection_resolver Instance of the connection resolver class
603- */
604- $ edge = apply_filters (
605- 'graphql_connection_edge ' ,
606- $ edge ,
607- $ this
608- );
609-
610- /**
611- * If not empty, add the edge to the edges
612- */
613- if ( ! empty ( $ edge ) ) {
614- $ edges [] = $ edge ;
615- }
616- }
617-
618- return $ edges ;
578+ return $ this ->edges ;
619579 }
620580
621581 /**
@@ -809,22 +769,28 @@ function () {
809769 *
810770 * Filters the nodes in the connection
811771 *
812- * @param array<int|string,mixed|\WPGraphQL\Model\Model|null> $nodes The nodes in the connection
813- * @param \WPGraphQL\Data\Connection\AbstractConnectionResolver $connection_resolver Instance of the Connection Resolver
772+ * @todo We reinstantate this here for b/c. Once that is not a concern, we should relocate this filter to ::get_nodes().
773+ *
774+ * @param \WPGraphQL\Model\Model[]|mixed[]|null $nodes The nodes in the connection
775+ * @param self $resolver Instance of the Connection Resolver
814776 */
815777 $ this ->nodes = apply_filters ( 'graphql_connection_nodes ' , $ this ->get_nodes (), $ this );
816778
817779 /**
818- * Filters the edges in the connection
780+ * Filters the edges in the connection.
781+ *
782+ * @todo We reinstantate this here for b/c. Once that is not a concern, we should relocate this filter to ::get_edges().
819783 *
820- * @param array<int| string,mixed|\WPGraphQL\Model\Model|null> $nodes The nodes in the connection
821- * @param \WPGraphQL\Data\Connection\AbstractConnectionResolver $connection_resolver Instance of the Connection Resolver
784+ * @param array<string,mixed> $edges The edges in the connection
785+ * @param self $resolver Instance of the Connection Resolver
822786 */
823787 $ this ->edges = apply_filters ( 'graphql_connection_edges ' , $ this ->get_edges (), $ this );
824788
789+ // @todo: we should also shortcircuit fetching/populating the actual nodes/edges if we only need one result.
825790 if ( true === $ this ->one_to_one ) {
826791 // For one to one connections, return the first edge.
827- $ connection = ! empty ( $ this ->edges [ array_key_first ( $ this ->edges ) ] ) ? $ this ->edges [ array_key_first ( $ this ->edges ) ] : null ;
792+ $ first_edge_key = array_key_first ( $ this ->edges );
793+ $ connection = isset ( $ first_edge_key ) && ! empty ( $ this ->edges [ $ first_edge_key ] ) ? $ this ->edges [ $ first_edge_key ] : null ;
828794 } else {
829795 // For plural connections (default) return edges/nodes/pageInfo
830796 $ connection = [
@@ -840,8 +806,8 @@ function () {
840806 *
841807 * This filter allows additional fields to be returned to the connection resolver
842808 *
843- * @param array<string,mixed> $ connection The connection data being returned
844- * @param \WPGraphQL\Data\Connection\AbstractConnectionResolver $connection_resolver The instance of the connection resolver
809+ * @param ? array<string,mixed> $connection The connection data being returned. A single edge or null if the connection is one-to-one.
810+ * @param self $resolver The instance of the connection resolver
845811 */
846812 return apply_filters ( 'graphql_connection ' , $ connection , $ this );
847813 }
@@ -978,6 +944,29 @@ public function get_array_index_for_offset( $offset, $ids ) {
978944 return array_search ( $ offset , array_values ( $ ids ), true );
979945 }
980946
947+ /**
948+ * Prepares the nodes for the connection.
949+ *
950+ * @used-by self::get_nodes()
951+ *
952+ * @return array<int|string,mixed|\WPGraphQL\Model\Model|null>
953+ */
954+ protected function prepare_nodes (): array {
955+ $ nodes = [];
956+
957+ // These are already sliced and ordered, we're just populating node data.
958+ $ ids = $ this ->get_ids_for_nodes ();
959+
960+ foreach ( $ ids as $ id ) {
961+ $ model = $ this ->get_node_by_id ( $ id );
962+ if ( true === $ this ->get_is_valid_model ( $ model ) ) {
963+ $ nodes [ $ id ] = $ model ;
964+ }
965+ }
966+
967+ return $ nodes ;
968+ }
969+
981970 /**
982971 * Gets the IDs for the currently-paginated slice of nodes.
983972 *
@@ -1033,6 +1022,62 @@ protected function get_is_valid_model( $model ): bool {
10331022 return apply_filters ( 'graphql_connection_is_valid_model ' , $ is_valid , $ model , $ this );
10341023 }
10351024
1025+ /**
1026+ * Prepares the edges for the connection.
1027+ *
1028+ * @used-by self::get_edges()
1029+ *
1030+ * @param array<int|string,mixed|\WPGraphQL\Model\Model|null> $nodes The nodes for the connection.
1031+ *
1032+ * @return array<string,mixed>[]
1033+ */
1034+ protected function prepare_edges ( array $ nodes ): array {
1035+ // Bail early if there are no nodes.
1036+ if ( empty ( $ nodes ) ) {
1037+ return [];
1038+ }
1039+
1040+ // The nodes are already ordered, sliced, and populated. What's left is to populate the edge data for each one.
1041+ $ edges = [];
1042+ foreach ( $ nodes as $ id => $ node ) {
1043+ $ edge = $ this ->prepare_edge ( $ id , $ node );
1044+
1045+ /**
1046+ * Filter the edge within the connection.
1047+ *
1048+ * @param array<string,mixed> $edge The edge within the connection
1049+ * @param self $resolver Instance of the connection resolver class
1050+ */
1051+ $ edge = apply_filters (
1052+ 'graphql_connection_edge ' ,
1053+ $ edge ,
1054+ $ this
1055+ );
1056+
1057+ $ edges [] = $ edge ;
1058+ }
1059+
1060+ return $ edges ;
1061+ }
1062+
1063+ /**
1064+ * Prepares a single edge for the connection.
1065+ *
1066+ * @used-by self::prepare_edges()
1067+ *
1068+ * @param int|string $id The ID of the node.
1069+ * @param mixed|\WPGraphQL\Model\Model|null $node The node for the edge.
1070+ *
1071+ * @return array<string,mixed>
1072+ */
1073+ protected function prepare_edge ( $ id , $ node ): array {
1074+ return [
1075+ 'cursor ' => $ this ->get_cursor_for_node ( $ id ),
1076+ 'node ' => $ node ,
1077+ 'source ' => $ this ->get_source (),
1078+ 'connection ' => $ this ,
1079+ ];
1080+ }
10361081
10371082 /**
10381083 * Given an ID, a cursor is returned.
0 commit comments