リレーション配列は必要ないと思います。
db テーブルは次のようになります。
event_id UINT(10) auto_increment NOT NULL
/* not important fields omitted */
start DATETIME not null
end DATETIME not null
reoccurring ENUM('NO', 'WEEKDAY', 'MONTHDAY', 'MONTH_REL', 'YEARLY') DEFAULT 'NO';
weekdays UINT(1) DEFAULT 0;
until TIMESTAMP DEFAULT NULL
クエリが簡単なので使用DATETIME
しましたが(以下を参照)、実際には問題ありません。お好みでお預かりできTIMESTAMP
ます。
: 日曜日、: 月曜日などweekdays
のビットでバイトを保持できます。したがって、イベントが毎日繰り返される場合は、そこに配置します。2^0
2^1
127
の場合、イベントuntil
はNULL
永遠に繰り返されます。
「その月の第3水曜日」が特定の範囲内にあるかどうかをSQLで見つけるのは非常に難しいため、ユーザー定義関数を使用しないと不可能ではないかと思いますが、非常に難しく、コードが明確ではないことをお勧めします。すべてのイベントを取得し、それらを php で取得して、そこでフィルター処理します。
必要なイベント (事前フィルタリング) のみをロードするクエリは次のようになります。
SELECT ... FROM events
WHERE
/* We take all non-reoccuring events in period */
((reoccurring = 'NO') AND (start >= :start) AND (end <= :end))
OR
/* We take some part of reoccurring events */
((reoccuring <> 'NO') AND ((start <= :end) OR (end >= :start)) AND ((until >= :start) OR until IS NULL)
ORDER BY start ASC;
したがって、フェッチ中に、レコードが次の基準を満たしているかどうかをテストできます。
- 再発しないのでそのままにしておく
- 特定の平日 (例: 毎週水曜日と毎週金曜日) に繰り返し発生する - 期間の間にそのような平日があるかどうかを確認し、少なくとも 1 つある場合はイベントを維持し、そうでない場合は破棄します
- 繰り返しが月の日にある場合 (例: 12 月 21 日ごと)、同じことを行います。
- 繰り返しが毎月 - 相対的な日 (第 3 水曜日など) の場合は、同じことを行います。
レコードが基準を満たしていない場合は、もちろんデータベースではなく配列から削除してください:-)。
一部のタスクは、SQL クエリに入れるのも簡単です。たとえば、特定の月日で繰り返されるイベントをフィルタリングできますSELECT ... WHERE ... OR ... (start LIKE '%-:month-:day %)
(質問の写真に示されているように、イベントの開始と終了が同じであると仮定します)。DATETIME
これは、文字列のように簡単に検索できるというフィールドの利点です。したがって、 %-12-21 %
12 月と 21 日を含むすべてのレコードが検索されます (もちろん、これらは常に 2 桁の数字である必要があります)。TIMESTAMP
(日付差等の計算がしやすいのがメリットです)
イベントが月日ごとに繰り返される場合は、... LIKE
%-%-:day %` などを使用します。
boolean
したがって、最後に、 2 つのケースをチェックする2 つの関数を返す必要があります。
- 特定期間の平日
- 期間中の n 番目の平日です (最初の曜日が失敗した場合、2 番目の曜日を実行する必要はありません)。
foreach
または何かを使用して、ブルートフォースでもコーディングできます。
また、フィールド値が 127 の場合は平日のチェックを実行する必要がないため、毎日発生します。
EDIT on 2013-03-29 - ビットを平日として使用する方法の説明
フィールドweekdays
では、1 つの (符号なし) INT(1) 数値に 7 日と 8 ビットがあるため、日をビットとして保持できます。したがって、「occurs_monday」、「occurs_tuesday」などの列を追加する必要も、リレーションを使用する必要もありません。イベントが「毎週月曜日」と「毎週金曜日」に発生する可能性があると思うので、このように提案しました。そうでない場合は、そこに数値を保持します (0 = 日曜日、1 = 月曜日など)。
また、毎日発生するイベントは、週 7 日発生するイベントの特殊なケースでもあるため、列に別のENUM
値は必要ありません。reoccurring
PHPでそれを使用する方法は?
特定の曜日のビットが設定されているかどうかをテストするだけです。これは、ビットAND
演算子を使用して行うことができます。いくつかの定数を定義すると、さらに簡単になります。
define("WEEKDAY_SUNDAY",1); // 2^0
define("WEEKDAY_MONDAY",2); // 2^1
define("WEEKDAY_TUESDAY",4); // 2^2
// ....
define("WEEKDAY_SATURDAY",64); // 2^6
// Does the event occur on Friday, maybe also other weekdays?
if($row['weekdays'] & WEEKDAY_FRIDAY){
// Does the event occurs only on Friday, and no other day?
if($row['weekdays'] == WEEKDAY_FRIDAY){
// Let's make the event occur on Friday and the day(s) that it already occurs
$row['weekdays'] = $row['weekdays'] | WEEKDAY_FRIDAY;
// Make the event occur only on Friday and no other weekday
$row['weekdays'] = WEEKDAY_FRIDAY;
// Let's check if the event occurs today:
if(pow(2,date('w')) & $row['weekdays']){ //...
「date
w」パラメータを持つ関数は、0 から 6 までの曜日番号を返すので、そのように使用しました。