23
23
24
24
use function array_column ;
25
25
use function array_combine ;
26
+ use function array_filter ;
26
27
use function array_flip ;
27
28
use function array_intersect_key ;
29
+ use function array_keys ;
28
30
use function array_map ;
29
31
use function array_merge ;
32
+ use function array_slice ;
30
33
use function array_values ;
31
34
use function count ;
32
35
use function implode ;
@@ -769,12 +772,6 @@ public function alias(string $alias): static
769
772
return $ this ;
770
773
}
771
774
772
- /**
773
- * @throws CircularReferenceException
774
- * @throws InvalidArgumentException
775
- * @throws NotInstantiableException
776
- * @throws \Yiisoft\Definitions\Exception\InvalidConfigException
777
- */
778
775
public function getTablesUsedInFrom (): array
779
776
{
780
777
if (empty ($ this ->from )) {
@@ -784,11 +781,6 @@ public function getTablesUsedInFrom(): array
784
781
return parent ::getTablesUsedInFrom ();
785
782
}
786
783
787
- /**
788
- * @throws CircularReferenceException
789
- * @throws NotInstantiableException
790
- * @throws \Yiisoft\Definitions\Exception\InvalidConfigException
791
- */
792
784
protected function getPrimaryTableName (): string
793
785
{
794
786
return $ this ->getARInstance ()->getTableName ();
@@ -817,82 +809,53 @@ public function getARClass(): string|ActiveRecordInterface|Closure
817
809
return $ this ->arClass ;
818
810
}
819
811
820
- /**
821
- * @throws Exception
822
- * @throws InvalidArgumentException
823
- * @throws InvalidConfigException
824
- * @throws Throwable
825
- */
826
- public function findOne (mixed $ condition ): array |ActiveRecordInterface |null
812
+ public function find (array |float |int |string $ properties ): static
827
813
{
828
- return $ this ->findByCondition ($ condition )->one ();
829
- }
830
-
831
- /**
832
- * @param mixed $condition The primary key value or a set of column values.
833
- *
834
- * @throws Exception
835
- * @throws InvalidArgumentException
836
- * @throws InvalidConfigException
837
- * @throws Throwable
838
- *
839
- * @return array Of ActiveRecord instance, or an empty array if nothing matches.
840
- */
841
- public function findAll (mixed $ condition ): array
842
- {
843
- return $ this ->findByCondition ($ condition )->all ();
844
- }
814
+ if (!is_array ($ properties )) {
815
+ $ properties = [$ properties ];
816
+ } elseif (DbArrayHelper::isAssociative ($ properties )) {
817
+ return $ this ->setWhere ($ this ->filterProperties ($ properties ));
818
+ }
845
819
846
- /**
847
- * Finds ActiveRecord instance(s) by the given condition.
848
- *
849
- * This method is internally called by {@see findOne()} and {@see findAll()}.
850
- *
851
- * @throws CircularReferenceException
852
- * @throws Exception
853
- * @throws InvalidArgumentException
854
- * @throws NotInstantiableException
855
- */
856
- protected function findByCondition (mixed $ condition ): static
857
- {
858
820
$ arInstance = $ this ->getARInstance ();
821
+ $ primaryKey = $ arInstance ->primaryKey ();
859
822
860
- if (! is_array ( $ condition )) {
861
- $ condition = [ $ condition ] ;
823
+ if (empty ( $ primaryKey )) {
824
+ throw new InvalidConfigException ( ' " ' . $ arInstance ::class . ' " must have a primary key. ' ) ;
862
825
}
863
826
864
- if (!DbArrayHelper:: isAssociative ( $ condition )) {
865
- /** query by primary key */
866
- $ primaryKey = $ arInstance -> primaryKey ();
827
+ if (count ( $ primaryKey ) < count ( $ properties )) {
828
+ throw new InvalidArgumentException ( ' Primary key is composed of ' . count ( $ primaryKey ) . ' columns while ' . count ( $ properties ) . ' were given ' );
829
+ }
867
830
868
- if (isset ($ primaryKey [0 ])) {
869
- $ pk = $ primaryKey [0 ];
831
+ $ primaryKey = array_slice ($ primaryKey , 0 , count ($ properties ));
870
832
871
- if (!empty ($ this ->getJoins ()) || !empty ($ this ->getJoinWith ())) {
872
- $ pk = $ arInstance ->getTableName () . '. ' . $ pk ;
873
- }
833
+ if (!empty ($ this ->getJoins ()) || !empty ($ this ->getJoinWith ())) {
834
+ $ tableName = $ arInstance ->getTableName ();
874
835
875
- /**
876
- * if the condition is scalar, search for a single primary key, if it's array, search for many primary
877
- * key values.
878
- */
879
- $ condition = [$ pk => array_values ($ condition )];
880
- } else {
881
- throw new InvalidConfigException ('" ' . $ arInstance ::class . '" must have a primary key. ' );
836
+ foreach ($ primaryKey as &$ pk ) {
837
+ $ pk = "$ tableName. $ pk " ;
882
838
}
883
- } else {
884
- $ aliases = $ arInstance ->filterValidAliases ($ this );
885
- $ condition = $ arInstance ->filterCondition ($ condition , $ aliases );
886
839
}
887
840
888
- return $ this ->setWhere ($ condition );
841
+ return $ this ->setWhere (array_combine ($ primaryKey , $ properties ));
842
+ }
843
+
844
+ public function findAll (array |float |int |string $ properties ): array
845
+ {
846
+ return $ this ->find ($ properties )->all ();
889
847
}
890
848
891
849
public function findBySql (string $ sql , array $ params = []): static
892
850
{
893
851
return $ this ->sql ($ sql )->params ($ params );
894
852
}
895
853
854
+ public function findOne (array |float |int |string $ properties ): array |ActiveRecordInterface |null
855
+ {
856
+ return $ this ->find ($ properties )->one ();
857
+ }
858
+
896
859
public function on (array |string |null $ value ): static
897
860
{
898
861
$ this ->on = $ value ;
@@ -946,6 +909,62 @@ private function createInstance(): static
946
909
->withQueries ($ this ->withQueries );
947
910
}
948
911
912
+ /**
913
+ * Filters properties before using them in a query filter.
914
+ *
915
+ * This method will ensure that the properties are valid column names and will filter keys of values that are arrays.
916
+ *
917
+ * @param array $properties Key-value pairs to be ensured and filtered.
918
+ */
919
+ private function filterProperties (array $ properties ): array
920
+ {
921
+ $ result = [];
922
+
923
+ $ quoter = $ this ->db ->getQuoter ();
924
+ $ columnNames = $ this ->getValidColumnNames ();
925
+
926
+ foreach ($ properties as $ key => $ value ) {
927
+ if (is_string ($ key ) && !in_array ($ quoter ->quoteSql ($ key ), $ columnNames , true )) {
928
+ throw new InvalidArgumentException (
929
+ 'Key " ' . $ key . '" is not a column name and can not be used as a filter. '
930
+ );
931
+ }
932
+
933
+ $ result [$ key ] = is_array ($ value ) ? array_values ($ value ) : $ value ;
934
+ }
935
+
936
+ return $ result ;
937
+ }
938
+
939
+ /**
940
+ * Returns valid column names: table column names and column names prefixed with table name and table aliases.
941
+ */
942
+ private function getValidColumnNames (): array
943
+ {
944
+ $ columnNames = [];
945
+
946
+ $ quoter = $ this ->db ->getQuoter ();
947
+ $ tables = $ this ->getTablesUsedInFrom ();
948
+ $ tableAliases = array_keys ($ tables );
949
+
950
+ $ tableNames = array_merge ($ tableAliases , array_filter ($ tables , 'is_string ' ));
951
+ $ tableNames = array_map ($ quoter ->getRawTableName (...), $ tableNames );
952
+
953
+ foreach ($ this ->getARInstance ()->propertyNames () as $ columnName ) {
954
+ $ columnNames [] = $ columnName ;
955
+ $ quotedColumnName = $ quoter ->quoteColumnName ($ columnName );
956
+ $ columnNames [] = $ quotedColumnName ;
957
+
958
+ foreach ($ tableNames as $ tableName ) {
959
+ $ columnNames [] = "$ tableName. $ columnName " ;
960
+ $ quotedTableName = $ quoter ->quoteTableName ($ tableName );
961
+ $ columnNames [] = "$ quotedTableName. $ quotedColumnName " ;
962
+ }
963
+ }
964
+
965
+ return $ columnNames ;
966
+ }
967
+
949
968
private function populateOne (array $ row ): ActiveRecordInterface |array
950
969
{
951
970
return $ this ->populate ([$ row ])[0 ];
0 commit comments